Zurück zum Blog

FehlerbehebungAnleitung

429 Too Many Requests von einer KI-API: Wiederholungen mit Backoff

Was ein 429 von einer KI-API bedeutet und wie man damit umgeht: exponentielles Backoff mit Jitter, Retry-After und Agenten-Parallelität, mit Python- und JavaScript-Code.

Von CheapTokens TeamVeröffentlicht am Aktualisiert am 5 Min. Lesezeit

Diagramm einer Anfrage-Schleife: eine 429-Antwort, ein Warteschritt mit wachsender Verzögerung und ein erneuter Versuch
Auf dieser Seite
  1. Was ein 429 bedeutet
  2. Lies die Header, bevor du eine Verzögerung errätst
  3. Python: Backoff mit Jitter
  4. JavaScript: dieselbe Schleife
  5. Wie Agenten mit 429 umgehen sollten
  6. Agenten-Schleifen auf CheapTokens ausführen
  7. Wenn es immer noch fehlschlägt

Ein 429 Too Many Requests von einer KI-API bedeutet, dass die Anfrage abgelehnt wurde, weil du zu viel zu schnell gesendet hast oder ein Limit deines Kontos erreicht wurde. Die Lösung ist, zu warten und mit exponentiellem Backoff und Jitter erneut zu versuchen, den Retry-After-Header zu verwenden, wenn die Antwort einen enthält, und zu begrenzen, wie viele Anfragen dein Agent parallel sendet. Wiederhole keinen 429, der eigentlich ein Ausgaben- oder Guthabenlimit ist: Warten behebt das nicht.

Dieser Leitfaden basiert auf den offiziellen Rate-Limit-Leitfäden von OpenAI und Anthropic, beide geprüft am 22. Oktober 2026. Keine der beiden Seiten zeigt ein Datum der letzten Aktualisierung.

Was ein 429 bedeutet#

OpenAI beschreibt einen 429 als eine Anfrage, die abgelehnt wurde, weil ein Rate-Limit überschritten wurde (rate_limit_error, mit dem Code slow_down, wenn der Traffic zu schnell ansteigt), oder weil ein hartes Ausgabenlimit erreicht wurde. Anthropic verwendet ebenfalls rate_limit_error für 429. Ein 429 wegen Ausgabenobergrenze hat keinen retry-after-Header und schlägt weiter fehl, bis der Zugang wiederhergestellt ist.

Zwei Nachbarn sind leicht damit zu verwechseln. OpenAIs 503 server_is_overloaded und Anthropics 529 overloaded_error sind Überlastungszustände, nicht dein Rate-Limit. Sie werden üblicherweise mit derselben Retry-Schleife behandelt, sagen aber etwas anderes über die Ursache aus.

Es gibt also drei Fälle, und jeder erfordert eine andere Reaktion:

Antwort Ursache Was zu tun ist
429 Rate-Limit Zu viele Anfragen oder Tokens pro Minute Warten, mit Backoff erneut versuchen
429 Ausgaben- oder Guthabenlimit Kontolimit erreicht Nicht wiederholen; Limit anpassen oder Guthaben aufladen
503 / 529 überlastet Anbieterseite ist ausgelastet Mit Backoff erneut versuchen, mit Obergrenze

Wenn dein Guthaben aufgebraucht ist, lies stattdessen den Fehler "nicht genügend Tokens". Für Fehler auf Netzwerkebene wie Timeouts und abgelehnte Verbindungen siehe häufige Verbindungsfehler.

Lies die Header, bevor du eine Verzögerung errätst#

OpenAI dokumentiert diese Header bei rate-limitierten Antworten: Retry-After, und x-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests mit -tokens-Varianten. Andere APIs senden möglicherweise eine Teilmenge oder keinen davon, also schreibe den Client so, dass er Retry-After verwendet, wenn es vorhanden ist, und auf deinen eigenen Zeitplan zurückfällt, wenn nicht.

OpenAIs Hinweise zu Wiederholungen, kurz gefasst:

  • Behandle Retry-After als die minimale Wartezeit und füge eine kleine zufällige Verzögerung hinzu.
  • Ohne ihn verwende exponentielles Backoff mit Jitter.
  • Begrenze sowohl die Anzahl der Versuche als auch die gesamte Wiederholungszeit.
  • Stapel deine eigenen Wiederholungen nicht auf die Wiederholungen des SDK.
  • Wiederhole keine Quota- oder Abrechnungsfehler.
  • Fehlgeschlagene Anfragen zählen weiterhin zum Limit pro Minute, also verschlimmert eine aggressive Schleife die Lage.
  • Beim Streaming spiele eine Anfrage nicht erneut ab, nachdem du bereits Ausgabe daraus konsumiert hast.

Python: Backoff mit Jitter#

Das offizielle openai-Paket funktioniert mit jedem OpenAI-kompatiblen Endpoint. Schalte die eigenen Wiederholungen des SDK ab (max_retries=0), damit sie sich nicht mit deinen multiplizieren. Die ID des Modells stammt aus der CheapTokens-Dokumentation; IDs unterscheiden sich zwischen Anbietern.

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)

Die Obergrenze der Verzögerung ohne Header wächst 1, 2, 4, 8 Sekunden (begrenzt auf 30), und random.uniform wählt einen zufälligen Wert darunter, damit nicht alle Worker gleichzeitig aufwachen. Retry-After kann auch ein HTTP-Datum sein; der obige Code behandelt die numerische Form und fällt andernfalls auf Backoff zurück.

JavaScript: dieselbe Schleife#

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

Wenn es funktioniert, dauert ein rate-limitierter Aufruf einfach länger und gibt dann eine normale Completion zurück. Wenn er nach dem letzten Versuch immer noch fehlschlägt, wird der ursprüngliche Fehler ausgelöst, sodass dein Code ihn protokollieren oder den Job für später einreihen kann.

Wie Agenten mit 429 umgehen sollten#

Eine Agenten-Schleife sendet viele kurze Aufrufe, und mehrere Agenten oder Tool-Aufrufe können gleichzeitig laufen. Alleiniges Wiederholen reicht nicht; senke die Anfragefrequenz an der Quelle:

  1. Begrenze die Parallelität. Ein Semaphor von 3–5 parallelen Aufrufen ist ein sinnvoller Anfang; erhöhe ihn nur, solange Fehler selten bleiben.
  2. Teile einen Limiter. Wenn mehrere Worker denselben Schlüssel verwenden, teilen sie dieselben Limits, also reicht eine Retry-Schleife pro Worker nicht: Verwende eine Warteschlange oder ein Semaphor für den Prozess.
  3. Backoff global. Wenn ein Aufruf einen 429 mit einer Verzögerung erhält, pausiere den gesamten Pool für diese Zeit, nicht nur den fehlschlagenden Aufruf.
  4. Halte Anfragen kleiner. Weniger Tokens pro Anfrage bedeuten weniger Druck auf Tokens-pro-Minute-Limits: kürze Verlauf und Tool-Ausgabe. Siehe wie man die Kosten eines KI-Agenten schätzt, um zu erfahren, wohin die Tokens gehen.
  5. Stoppe bei nicht wiederholbaren Fehlern. Ein 401, 400 oder ein Guthabenfehler behebt sich nicht von selbst; scheitere schnell und melde.
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

Agenten-Schleifen auf CheapTokens ausführen#

Für Agenten-Schleifen mit vielen kurzen Aufrufen bietet CheapTokens MiniMax-M2.7: ein Preis zu jeder Tageszeit, ein 180K-Kontext, bis zu 8.192 Tokens pro Antwort und ein Guthaben für alle Modelle. Die Ausgabe kostet $0.15 pro 1M Tokens, und insgesamt, mit Eingabe und Ausgabe zusammen gezählt, ist es günstiger als OpenRouter. Es funktioniert über den OpenAI-kompatiblen Endpoint https://api.cheaptokens.dev/v1. Der obige Code zeigt bereits auf diesen Endpoint; setze die Modell-ID aus der CheapTokens-Dokumentation und führe ihn aus.

Live-Preise für eine Arbeitslast von 500.000 Eingabe- und 100.000 Ausgabe-Tokens:

Modell Kosten 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- und 100.000 Output-Tokens insgesamt. Die Preise pro 1 Mio. Tokens sind aktuell und ändern sich zusammen mit unseren Tarifen; die OpenRouter-Spalte zeigt Referenzpreise für dieselbe Arbeitslast.

Siehe alle Preise, die Setup-Dokumentation, und erstelle einen Schlüssel, um deine erste Anfrage zu senden.

Wenn es immer noch fehlschlägt#

  • 429 bei der allerersten Anfrage. Lies den Fehlertyp und die Meldung im Antwort-Body: Ein 429 wegen Ausgaben- oder Kontolimit schlägt bei Wiederholung weiter fehl, bis das Limit erhöht oder der Zugang wiederhergestellt ist, während ein Rate-Limit-429 nach einer Pause verschwindet.
  • 429 kommt weiterhin mit einer langen Schleife. Möglicherweise stapelst du Wiederholungen: SDK-Wiederholungen mal deine Wiederholungen. Setze das SDK auf null, wie in den Beispielen.
  • Fehler kommen am Anfang eines Batches in Schüben. Steigere dich allmählich, statt alle Worker auf einmal zu starten; OpenAI meldet slow_down für Traffic, der zu schnell wächst.
  • Streaming-Aufruf mittendrin fehlgeschlagen. Spiele ihn nicht blind erneut ab, nachdem du Ausgabe konsumiert hast; entscheide, ob du die ganze Antwort neu startest oder mit dem fortfährst, was du hast.
  • Kein Retry-After in der Antwort. Der Code fällt auf Backoff mit Jitter zurück, also ist keine Änderung nötig.