Bumalik sa blog

Pag-troubleshootGabay

429 Too Many Requests mula sa isang AI API: mga retry na may backoff

Ano ang ibig sabihin ng 429 mula sa isang AI API at paano ito hahawakan: exponential backoff na may jitter, Retry-After, at concurrency ng agent, may Python at JavaScript code.

Ni CheapTokens TeamNai-publish noong Na-update noong 7 min na pagbabasa

Diagram ng isang request loop: isang 429 na tugon, isang hakbang ng paghihintay na may lumalaking delay, at isang retry
Sa pahinang ito
  1. Ano ang ibig sabihin ng 429
  2. Basahin ang mga header bago maghula ng delay
  3. Python: backoff na may jitter
  4. JavaScript: ang parehong loop
  5. Paano dapat hawakan ng mga agent ang 429
  6. Magpatakbo ng agent loops sa CheapTokens
  7. Kung nabigo pa rin

Ang 429 Too Many Requests mula sa isang AI API ay nangangahulugang tinanggihan ang kahilingan dahil masyadong marami ang ipinadala mo nang masyadong mabilis, o naabot mo ang limitasyon sa iyong account. Ang solusyon ay maghintay at subukang muli gamit ang exponential backoff at jitter, gamitin ang Retry-After header kapag mayroon ito sa tugon, at limitahan kung gaano karaming kahilingan ang ipinapadala ng iyong agent nang sabay-sabay. Huwag subukang muli ang 429 na talagang limitasyon sa gastos o balanse: hindi ito maaayos ng paghihintay.

Ang gabay na ito ay batay sa opisyal na mga gabay sa rate-limit ng OpenAI at Anthropic, parehong sinuri noong 22 Oktubre 2026. Wala sa dalawang pahina ang nagpapakita ng petsa ng huling pag-update.

Ano ang ibig sabihin ng 429#

Inilalarawan ng OpenAI ang 429 bilang isang kahilingang tinanggihan dahil lumampas sa rate limit (rate_limit_error, na may code na slow_down kapag masyadong mabilis ang pagtaas ng trapiko), o dahil naabot ang hard spend limit. Gumagamit din ang Anthropic ng rate_limit_error para sa 429. Ang 429 na dulot ng spend-cap ay walang retry-after header at patuloy na nabibigo hanggang sa maibalik ang access.

Dalawang kalapit na error ang madaling malito dito. Ang 503 server_is_overloaded ng OpenAI at 529 overloaded_error ng Anthropic ay mga kondisyon ng overload, hindi ang iyong rate limit. Karaniwang hinahawakan ang mga ito gamit ang parehong retry loop, ngunit iba ang sinasabi nila tungkol sa sanhi.

Kaya may tatlong kaso, at bawat isa ay nangangailangan ng ibang reaksyon:

Tugon Sanhi Ano ang gagawin
429 rate limit Masyadong maraming kahilingan o token kada minuto Maghintay, subukang muli gamit ang backoff
429 spend o balance limit Naabot ang limitasyon ng account Huwag subukang muli; ayusin ang limitasyon o dagdagan ang balanse
503 / 529 overloaded Abala ang panig ng provider Subukang muli gamit ang backoff, may cap

Kung naubos ang iyong balanse, basahin ang error na "not enough tokens" sa halip. Para sa mga pagkabigo sa antas ng network tulad ng mga timeout at refused connections, tingnan ang mga karaniwang error sa koneksyon.

Basahin ang mga header bago maghula ng delay#

Idinodokumento ng OpenAI ang mga header na ito sa mga tugon na may rate limit: Retry-After, at x-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests na may mga variant na -tokens. Maaaring magpadala ang ibang API ng subset o wala sa mga ito, kaya isulat ang client upang gamitin ang Retry-After kapag naroroon at bumalik sa sarili mong iskedyul kapag wala.

Ang patnubay ng OpenAI sa mga retry, sa maikli:

  • Ituring ang Retry-After bilang minimum na paghihintay at magdagdag ng maliit na random na delay sa ibabaw nito.
  • Kung wala ito, gumamit ng exponential backoff na may jitter.
  • Limitahan ang parehong bilang ng mga pagtatangka at ang kabuuang oras ng retry.
  • Huwag magpatong ng sarili mong mga retry sa ibabaw ng mga retry ng SDK.
  • Huwag subukang muli ang mga error sa quota o billing.
  • Ang mga nabigong kahilingan ay binibilang pa rin sa per-minute na limitasyon, kaya ang agresibong loop ay nagpapalala ng sitwasyon.
  • Para sa streaming, huwag i-replay ang isang kahilingan pagkatapos mong makakonsumo ng output mula rito.

Python: backoff na may jitter#

Gumagana ang opisyal na openai package laban sa anumang OpenAI-compatible endpoint. Patayin ang sariling mga retry ng SDK (max_retries=0) upang hindi sila dumami kasama ng sa iyo. Ang id ng modelo ay nagmumula sa CheapTokens docs; nagkakaiba ang mga id sa pagitan ng mga provider.

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)

Ang upper bound ng delay na walang header ay lumalaki nang 1, 2, 4, 8 segundo (capped sa 30), at ang random.uniform ay pumipili ng random na halaga sa ilalim nito, kaya hindi lahat ng worker ay nagising nang sabay. Ang Retry-After ay maaari ring isang HTTP date; hinahawakan ng code sa itaas ang numeric na anyo at kung hindi ay bumabalik sa backoff.

JavaScript: ang parehong loop#

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);
    }
  }
}

Kapag gumana, ang isang rate-limited na tawag ay tumatagal lamang ng mas matagal at pagkatapos ay nagbabalik ng normal na completion. Kapag nabigo pa rin pagkatapos ng huling pagtatangka, itinataas ang orihinal na error, upang ma-log ito ng iyong code o ma-queue ang trabaho para mamaya.

Paano dapat hawakan ng mga agent ang 429#

Ang agent loop ay nagpapadala ng maraming maiikling tawag, at maraming agent o tool call ang maaaring tumakbo nang sabay. Hindi sapat ang retry lamang; bawasan ang rate ng kahilingan sa pinagmulan:

  1. Limitahan ang concurrency. Ang semaphore na 3–5 parallel na tawag ay makatwirang simula; taasan lamang ito habang bihira ang mga error.
  2. Ibahagi ang isang limiter. Kung maraming worker ang gumagamit ng parehong key, ibinabahagi nila ang parehong mga limitasyon, kaya hindi sapat ang isang retry loop bawat worker: gumamit ng isang queue o isang semaphore para sa proseso.
  3. Mag-back off nang global. Kapag ang isang tawag ay nakakuha ng 429 na may delay, i-pause ang buong pool para sa tagal na iyon sa halip na ang nabigong tawag lamang.
  4. Panatilihing mas maliit ang mga kahilingan. Mas kaunting token bawat kahilingan ay nangangahulugang mas kaunting pressure sa token-per-minute na limitasyon: bawasan ang history at tool output. Tingnan ang paano tantiyahin ang gastos ng isang AI agent para sa kung saan napupunta ang mga token.
  5. Huminto sa mga error na hindi na-retry. Ang 401, 400, o error sa balanse ay hindi maaayos sa sarili nito; mabilis na mag-fail at iulat.
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

Magpatakbo ng agent loops sa CheapTokens#

Para sa mga agent loop na may maraming maiikling tawag, nag-aalok ang CheapTokens ng MiniMax-M2.7: isang presyo sa anumang oras ng araw, 180K context, hanggang 8,192 token bawat sagot, at isang balanse para sa lahat ng modelo. Ang output ay nagkakahalaga ng $0.15 kada 1M token, at sa kabuuan, kasama ang input at output na binibilang nang magkasama, ito ay mas mura kaysa OpenRouter. Gumagana ito sa pamamagitan ng OpenAI-compatible endpoint na https://api.cheaptokens.dev/v1. Ang code sa itaas ay nakaturo na sa endpoint na ito; itakda ang model id mula sa CheapTokens docs at patakbuhin ito.

Live na mga presyo para sa 500,000-input, 100,000-output na workload:

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

500,000 input at 100,000 output na token sa kabuuan. Ang mga presyo kada 1M token ay kasalukuyan at nagbabago kasabay ng aming mga taripa; ang column ng OpenRouter ay nagpapakita ng reference na presyo para sa parehong workload.

Tingnan ang lahat ng presyo, ang setup docs, at gumawa ng key upang ipadala ang iyong unang kahilingan.

Kung nabigo pa rin#

  • 429 sa pinakaunang kahilingan. Basahin ang uri ng error at mensahe sa body ng tugon: ang 429 na dulot ng spend o account-limit ay patuloy na nabibigo sa retry hanggang sa itaas ang limitasyon o maibalik ang access, habang ang 429 na rate-limit ay nawawala pagkatapos ng pause.
  • Patuloy na dumarating ang 429 na may mahabang loop. Maaaring nagpapatong ka ng mga retry: SDK retries na pinarami ng iyong mga retry. Itakda ang SDK sa zero, tulad ng sa mga halimbawa.
  • Dumarating ang mga error nang sabay-sabay sa simula ng batch. Dahan-dahang mag-ramp up sa halip na sabay-sabay na magpaputok ng lahat ng worker; iniuulat ng OpenAI ang slow_down para sa trapikong masyadong mabilis ang paglaki.
  • Nabigo ang streaming call sa kalagitnaan. Huwag itong i-replay nang walang pag-iingat pagkatapos mong makakonsumo ng output; magpasya kung i-restart ang buong sagot o magpatuloy mula sa mayroon ka na.
  • Walang Retry-After sa tugon. Ang code ay bumabalik sa backoff na may jitter, kaya walang pagbabagong kailangan.