Kembali ke blog

Pemecahan masalahPanduan

429 Too Many Requests dari API AI: percobaan ulang dengan backoff

Apa arti 429 dari API AI dan cara menanganinya: exponential backoff dengan jitter, Retry-After, dan konkurensi agen, dengan kode Python dan JavaScript.

Oleh CheapTokens TeamDiterbitkan Diperbarui 5 menit baca

Diagram loop permintaan: respons 429, langkah menunggu dengan penundaan yang bertambah, dan percobaan ulang
Di halaman ini
  1. Apa arti 429
  2. Baca header sebelum menebak penundaan
  3. Python: backoff dengan jitter
  4. JavaScript: loop yang sama
  5. Bagaimana agen harus menangani 429
  6. Jalankan loop agen di CheapTokens
  7. Jika masih gagal

429 Too Many Requests dari API AI berarti permintaan ditolak karena Anda mengirim terlalu banyak terlalu cepat, atau mencapai batas pada akun Anda. Solusinya adalah menunggu dan mencoba ulang dengan exponential backoff dan jitter, menggunakan header Retry-After jika respons memilikinya, dan membatasi berapa banyak permintaan yang dikirim agen Anda secara paralel. Jangan mencoba ulang 429 yang sebenarnya adalah batas pengeluaran atau saldo: menunggu tidak akan memperbaikinya.

Panduan ini didasarkan pada panduan rate-limit resmi dari OpenAI dan Anthropic, keduanya diperiksa pada 22 Oktober 2026. Tidak ada halaman yang menampilkan tanggal terakhir diperbarui.

Apa arti 429#

OpenAI mendeskripsikan 429 sebagai permintaan yang ditolak karena melebihi batas laju (rate_limit_error, dengan kode slow_down saat lalu lintas naik terlalu cepat), atau karena batas pengeluaran keras tercapai. Anthropic juga menggunakan rate_limit_error untuk 429. 429 batas pengeluaran tidak memiliki header retry-after dan terus gagal sampai akses dilanjutkan.

Dua tetangga mudah tertukar dengannya. 503 server_is_overloaded dari OpenAI dan 529 overloaded_error dari Anthropic adalah kondisi kelebihan beban, bukan batas laju Anda. Biasanya ditangani dengan loop percobaan ulang yang sama, tetapi keduanya menyatakan penyebab yang berbeda.

Jadi ada tiga kasus, dan masing-masing memerlukan reaksi berbeda:

Respons Penyebab Yang harus dilakukan
429 batas laju Terlalu banyak permintaan atau token per menit Tunggu, coba ulang dengan backoff
429 batas pengeluaran atau saldo Batas akun tercapai Jangan coba ulang; perbaiki batas atau isi ulang saldo
503 / 529 kelebihan beban Sisi penyedia sedang sibuk Coba ulang dengan backoff, dengan batas

Jika saldo Anda habis, baca kesalahan "token tidak cukup" sebagai gantinya. Untuk kegagalan tingkat jaringan seperti timeout dan koneksi ditolak, lihat kesalahan koneksi umum.

Baca header sebelum menebak penundaan#

OpenAI mendokumentasikan header ini pada respons yang dibatasi laju: Retry-After, dan x-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests dengan varian -tokens. API lain mungkin mengirim sebagian atau tidak sama sekali, jadi tulis klien untuk menggunakan Retry-After jika ada dan kembali ke jadwal Anda sendiri jika tidak ada.

Panduan OpenAI tentang percobaan ulang, singkatnya:

  • Perlakukan Retry-After sebagai minimum tunggu dan tambahkan penundaan acak kecil di atasnya.
  • Tanpa itu, gunakan exponential backoff dengan jitter.
  • Batasi jumlah percobaan dan total waktu percobaan ulang.
  • Jangan menumpuk percobaan ulang Anda sendiri di atas percobaan ulang SDK.
  • Jangan coba ulang kesalahan kuota atau penagihan.
  • Permintaan yang gagal tetap dihitung terhadap batas per menit, jadi loop agresif memperburuk keadaan.
  • Untuk streaming, jangan memutar ulang permintaan setelah Anda mengonsumsi output darinya.

Python: backoff dengan jitter#

Paket resmi openai berfungsi terhadap endpoint apa pun yang kompatibel dengan OpenAI. Matikan percobaan ulang SDK sendiri (max_retries=0) agar tidak berlipat dengan milik Anda. Id model berasal dari dokumentasi CheapTokens; id berbeda antar penyedia.

python
import os
import random
import time

from openai import OpenAI, APIStatusError

client = OpenAI(
    base_url="https://api.cheaptokens.dev/v1",
    api_key=os.environ["CHEAPTOKENS_API_KEY"],
    max_retries=0,  # we retry ourselves
)

RETRYABLE = {429, 500, 502, 503, 504}


def chat_with_retry(model, messages, max_attempts=5, max_total=60.0):
    started = time.monotonic()
    for attempt in range(max_attempts):
        try:
            return client.chat.completions.create(model=model, messages=messages)
        except APIStatusError as err:
            last = attempt == max_attempts - 1
            if err.status_code not in RETRYABLE or last:
                raise
            header = err.response.headers.get("retry-after")
            if header and header.replace(".", "", 1).isdigit():
                delay = float(header) + random.uniform(0, 1)  # minimum wait + jitter
            else:
                delay = random.uniform(0, min(30.0, 2.0 ** attempt))  # full jitter
            if time.monotonic() - started + delay > max_total:
                raise
            time.sleep(delay)

Batas atas penundaan tanpa header tumbuh 1, 2, 4, 8 detik (dibatasi pada 30), dan random.uniform memilih nilai acak di bawahnya, sehingga banyak pekerja tidak semua bangun pada saat yang sama. Retry-After juga bisa berupa tanggal HTTP; kode di atas menangani bentuk numerik dan jika tidak kembali ke backoff.

JavaScript: loop yang sama#

javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.cheaptokens.dev/v1",
  apiKey: process.env.CHEAPTOKENS_API_KEY,
  maxRetries: 0, // we retry ourselves
});

const RETRYABLE = new Set([429, 500, 502, 503, 504]);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function chatWithRetry(model, messages, maxAttempts = 5, maxTotalMs = 60000) {
  const started = Date.now();
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    try {
      return await client.chat.completions.create({ model, messages });
    } catch (err) {
      const last = attempt === maxAttempts - 1;
      if (!RETRYABLE.has(err.status) || last) throw err;
      const header = Number(err.headers?.get?.("retry-after"));
      const delayMs = Number.isFinite(header) && header > 0
        ? header * 1000 + Math.random() * 1000 // minimum wait + jitter
        : Math.random() * Math.min(30000, 2 ** attempt * 1000); // full jitter
      if (Date.now() - started + delayMs > maxTotalMs) throw err;
      await sleep(delayMs);
    }
  }
}

Ketika berhasil, panggilan yang dibatasi laju hanya memakan waktu lebih lama dan kemudian mengembalikan penyelesaian normal. Ketika masih gagal setelah percobaan terakhir, kesalahan asli dimunculkan, sehingga kode Anda dapat mencatatnya atau mengantrekan pekerjaan untuk nanti.

Bagaimana agen harus menangani 429#

Loop agen mengirim banyak panggilan singkat, dan beberapa agen atau panggilan alat dapat berjalan sekaligus. Percobaan ulang saja tidak cukup; turunkan laju permintaan di sumbernya:

  1. Batasi konkurensi. Semaphore 3–5 panggilan paralel adalah awal yang wajar; naikkan hanya selama kesalahan tetap jarang.
  2. Bagikan satu limiter. Jika beberapa pekerja menggunakan kunci yang sama, mereka berbagi batas yang sama, jadi satu loop percobaan ulang per pekerja tidak cukup: gunakan satu antrean atau satu semaphore untuk proses.
  3. Backoff secara global. Ketika satu panggilan mendapat 429 dengan penundaan, jeda seluruh kumpulan selama waktu itu, bukan hanya panggilan yang gagal.
  4. Jaga permintaan tetap kecil. Token lebih sedikit per permintaan berarti tekanan lebih kecil pada batas token per menit: pangkas riwayat dan output alat. Lihat cara memperkirakan biaya agen AI untuk mengetahui ke mana token pergi.
  5. Berhenti pada kesalahan yang tidak dapat dicoba ulang. 401, 400, atau kesalahan saldo tidak akan memperbaiki dirinya sendiri; gagal cepat dan laporkan.
python
import asyncio

limit = asyncio.Semaphore(4)  # at most 4 requests in flight


async def run(job):
    async with limit:
        return await call_model(job)  # your async call with the retry loop above

Jalankan loop agen di CheapTokens#

Untuk loop agen dengan banyak panggilan singkat, CheapTokens menawarkan MiniMax-M2.7: satu harga kapan pun sepanjang hari, konteks 180K, hingga 8.192 token per jawaban, dan satu saldo untuk semua model. Output berbiaya $0.15 per 1 juta token, dan secara total, dengan input dan output dihitung bersama, lebih murah daripada OpenRouter. Ini bekerja melalui endpoint yang kompatibel dengan OpenAI https://api.cheaptokens.dev/v1. Kode di atas sudah mengarah ke endpoint ini; atur id model dari dokumentasi CheapTokens dan jalankan.

Harga langsung untuk beban kerja 500.000 input, 100.000 output:

Model Biaya OpenRouter
GLM-5.3-Flash $0.014 $0.0282
DeepSeek-V4-Flash $0.0175 $0.0394
MiniMax-M2.7 $0.04 $0.27

Total 500.000 token input dan 100.000 token output. Harga per 1 juta token adalah harga saat ini dan berubah seiring tarif kami; kolom OpenRouter menunjukkan harga referensi untuk beban kerja yang sama.

Lihat semua harga, dokumentasi penyiapan, dan buat kunci untuk mengirim permintaan pertama Anda.

Jika masih gagal#

  • 429 pada permintaan pertama. Baca jenis dan pesan kesalahan di badan respons: 429 batas pengeluaran atau akun terus gagal saat dicoba ulang sampai batas dinaikkan atau akses dilanjutkan, sedangkan 429 batas laju hilang setelah jeda.
  • 429 terus muncul dengan loop panjang. Anda mungkin menumpuk percobaan ulang: percobaan ulang SDK dikali percobaan ulang Anda. Setel SDK ke nol, seperti pada contoh.
  • Kesalahan datang bergelombang di awal batch. Naikkan secara bertahap alih-alih menembakkan semua pekerja sekaligus; OpenAI melaporkan slow_down untuk lalu lintas yang tumbuh terlalu cepat.
  • Panggilan streaming gagal di tengah jalan. Jangan memutarnya ulang secara buta setelah Anda mengonsumsi output; putuskan apakah akan memulai ulang seluruh jawaban atau melanjutkan dari yang sudah ada.
  • Tidak ada Retry-After dalam respons. Kode kembali ke backoff dengan jitter, jadi tidak perlu perubahan.