Rate Limiting für KI-Agenten: wie man Request-Spitzen und Retry-Stürme eindämmt

Praktisches Rate Limiting in Production: per-user/per-tenant/global Limits, Burst-Kontrolle, retry_after, Backoff, Audit Logs und Alerting.
Auf dieser Seite
  1. Idee in 30 Sekunden
  2. Problem
  3. Lösung
  4. Rate limiting ≠ Step limits
  5. Komponenten der Rate-Limiting-Kontrolle
  6. Wie das in der Architektur aussieht
  7. Beispiel
  8. Im Code sieht das so aus
  9. Wie das während der Ausführung aussieht
  10. Szenario 1: Stopp durch tenant-Limit
  11. Szenario 2: Burst-Spitze
  12. Szenario 3: Normale Ausführung
  13. Typische Fehler
  14. Selbstcheck
  15. FAQ
  16. Wo Rate Limiting im Gesamtsystem liegt
  17. Verwandte Seiten

Idee in 30 Sekunden

Rate limiting ist eine Runtime-Kontrolle, die die Frequenz externer Agent-Aufrufe begrenzt, damit Request-Spitzen und Retry-Stürme in Production nicht eskalieren.

Wann das nötig ist: wenn ein Agent häufig model/tool APIs aufruft, Retry-Logik hat und unter Lastspitzen läuft.

Problem

Ohne Rate Limiting erzeugt ein instabiler Service schnell eine Kette: Retry → Aufruf → noch ein Retry. Im Demo ist das kaum sichtbar. In Production führt dieses Verhalten zu Wellen von 429/5xx, Warteschlangen und Latenz.

Am schlimmsten: Der Incident skaliert sich selbst:

  • ein überaktiver Nutzer zieht Quoten leer
  • ein Tenant "erstickt" andere
  • eine globale Spitze bricht Abhängigkeiten für alle gleichzeitig

Und jede Minute ohne Frequenzbegrenzung erzeugt neue Retries, Queues und Verzögerungen, bis sich das System effektiv selbst DDoS't.

Analogie: Das ist wie eine Auffahrtsregelung auf eine Autobahn. Ohne Dosierung wird selbst eine gute Straße in Minuten zum Stau.

Lösung

Die Lösung ist ein zentraler Rate-Limit-Policy-Layer in Runtime und Tool Gateway. Jeder externe Agent-Aufruf wird gegen Limits per_user, per_tenant, global und burst_tokens geprüft.

Die Policy gibt eine technische Entscheidung zurück: allow oder stop mit explizitem Grund:

  • rate_limited_user
  • rate_limited_tenant
  • rate_limited_global
  • burst_limited

Wenn stop zurückkommt, sendet Runtime retry_after_ms an den Client und führt den Aufruf nicht aus. Das ist eine eigene Systemschicht, nicht Teil von Prompt oder Modelllogik.

Rate limiting ≠ Step limits

Das sind unterschiedliche Kontrollstufen:

  • Rate limiting begrenzt die Frequenz externer Aufrufe.
  • Step limits begrenzen Länge und Verhalten der Runtime-Loop.

Eins ohne das andere reicht nicht:

  • ohne Rate Limiting fallen externe APIs bei Spitzen und Retry-Stürmen aus
  • ohne Step limits kann ein Run selbst bei moderater Aufruffrequenz zu lange kreisen

Beispiel:

  • rate limiting: nicht mehr als per_user=6 Aufrufe pro 10 Sekunden
  • step limits: max_steps=18, max_repeat_action=3

Komponenten der Rate-Limiting-Kontrolle

Diese Komponenten wirken bei jedem externen Agent-Aufruf zusammen.

KomponenteWas sie kontrolliertZentrale MechanikWarum
Per-user limitVerhalten eines einzelnen Nutzersper_user quota
sliding window
Verhindert, dass ein Nutzer alle Ressourcen verbraucht
Per-tenant limitLast eines Tenantsper_tenant quota
tenant-scoped keys
Isoliert Spitzen zwischen Kunden
Global limitGesamtsystemlastglobal cap
shared limiter
Schützt externe Abhängigkeiten vor Massen-Spitzen
Burst controlKurze Peak-"Spikes"token bucket
refill rate
Dämpft plötzliche Sprünge ohne Vollstopp des Systems
Rate-limit observabilitySichtbarkeit von Policy-Entscheidungenaudit logs
alerts bei stop spikes
Begrenzt Aufrufe nicht direkt, hilft aber, Spike-Quellen schnell zu finden

Beispiel-Alert:

Slack: 🛑 Support-Agent hit rate_limited_tenant. retry_after=1200ms, tenant=t_42.

Wie das in der Architektur aussieht

Der Rate-Limit-Policy-Layer steht zwischen Runtime und externen model/tool APIs. Jede Entscheidung (allow oder stop) wird im Audit Log erfasst.

Jeder externe Agent-Aufruf läuft vor der Ausführung durch diesen Flow: Runtime führt Aufrufe nicht direkt aus, sondern lässt zuerst den Policy Layer entscheiden.

Flow kurz zusammengefasst:

  • Runtime bildet einen externen Agent-Aufruf
  • Policy prüft per_user, per_tenant, global und burst_tokens
  • allow → Aufruf wird ausgeführt
  • stopretry_after_ms und partielle Antwort werden zurückgegeben
  • beide Entscheidungen werden ins Audit Log geschrieben

Beispiel

Ein Support-Agent verarbeitet viele Requests gleichzeitig und retried crm.search mehrfach.

Mit Rate Limiting:

  • per_user = 6 / 10s
  • per_tenant = 120 / min
  • global = 50 / s
  • burst_tokens = 5

→ die Spitze wird auf Policy-Ebene gestoppt, bevor Abhängigkeiten und Queues ausfallen.

Rate Limiting stoppt den Incident direkt vor dem externen Aufruf, nicht erst nach einer Welle von 429.

Im Code sieht das so aus

Die vereinfachte Skizze oben zeigt den Haupt-Flow. Kritisch: rate-limit check muss O(1) und atomar sein (meist via Redis/Lua oder Äquivalent), sonst wird er unter Peak selbst zum Bottleneck. Nach stop(...) baut Runtime meist eine partielle Antwort für den Client mit explizitem Grund und retry_after_ms.

Beispiel für Rate-Limit-Konfiguration:

YAML
rate_limits:
  per_user_10s: 6
  per_tenant_min: 120
  global_rps: 50
  burst_tokens: 5
  refill_per_second: 2
PYTHON
action = planner.next(state)
action_key = make_action_key(action.name, action.args)

if not action.is_external_call():
    # execute_local — bedingter Helper für lokale Aktionen ohne externes API.
    # Decision.allow — bedingter Helper, um ein einheitliches outcome/reason-Modell zu behalten.
    local_result = execute_local(action)
    local_decision = Decision.allow(reason=None)
    audit.log(
        run_id,
        decision=local_decision.outcome,
        reason=local_decision.reason,
        scope="local",
        action=action.name,
        action_key=action_key,
        result=local_result.status,
    )
    return local_result

decision = rate_limit.check(
    user_id=state.user_id,
    tenant_id=state.tenant_id,
    action=action.name,
    now_ms=clock.now_ms(),
)

if decision.outcome == "stop":
    audit.log(
        run_id,
        decision=decision.outcome,
        reason=decision.reason,
        scope=decision.scope,
        retry_after_ms=decision.retry_after_ms,
        action=action.name,
        action_key=action_key,
    )
    alerts.notify_if_needed(run_id, decision.reason, scope=decision.scope)
    return stop(decision.reason, retry_after_ms=decision.retry_after_ms)

result = executor.execute(action)

audit.log(
    run_id,
    decision=decision.outcome,
    reason=decision.reason,
    scope=decision.scope,
    action=action.name,
    action_key=action_key,
    result=result.status,
)

return result

Wie das während der Ausführung aussieht

Szenario 1: Stopp durch tenant-Limit

  1. Runtime bildet externen Aufruf crm.search.
  2. Policy erkennt überschrittene per_tenant-Quote.
  3. Entscheidung: stop (reason=rate_limited_tenant).
  4. Runtime gibt retry_after_ms zurück.
  5. Aufruf wird nicht ausgeführt, Event wird ins Audit Log geschrieben.

Szenario 2: Burst-Spitze

  1. Mehrere Runs erzeugen gleichzeitig eine kurze Aufrufspitze.
  2. Policy verbraucht burst_tokens.
  3. Entscheidung: stop (reason=burst_limited).
  4. Ein Teil der Aufrufe wird mit retry_after_ms abgewiesen.
  5. System bleibt stabil ohne cascade-failure.

Szenario 3: Normale Ausführung

  1. Runtime bildet externen Aufruf.
  2. Policy prüft Limits: alles im Rahmen.
  3. Entscheidung: allow.
  4. Aufruf wird ausgeführt.
  5. Entscheidung und Ergebnis werden ins Audit Log geschrieben.

Typische Fehler

  • nur globales Limit setzen, ohne per_user/per_tenant-Isolation
  • bei stop kein retry_after zurückgeben
  • retry ohne backoff und jitter
  • Rate Limit nur in einer Schicht prüfen (nur Runtime oder nur Gateway)
  • stop-Entscheidungen nicht loggen (reason, scope, retry_after_ms)
  • kein Alerting auf rate_limited_*-Spitzen

Ergebnis: Das System wirkt kontrolliert, degradiert aber bei realen Spitzen schnell.

Selbstcheck

Schneller Rate-Limiting-Check vor dem Production-Start:

Fortschritt: 0/8

⚠ Grundlegende Governance-Kontrollen fehlen

Vor production brauchen Sie mindestens Zugriffskontrolle, Limits, audit logs und einen Not-Stopp.

FAQ

Q: Mit welchen Limits sollten wir starten?
A: Mindestens: per_user, per_tenant, global + eine kleine Burst-Kontrolle. Danach anhand realer Stop-Events nachjustieren.

Q: Wenn externe API schon 429 zurückgibt, brauchen wir trotzdem eigenes Rate Limiting?
A: Ja. Eigenes Rate Limiting schützt Runtime vor externem 429 und liefert kontrollierte stop reasons, retry_after und Audit.

Q: Was ist bei Limit-Treffer besser: stop oder Queue?
A: Für sync-runs ist stop + retry_after meist besser. Für async-Pipelines kann Queueing sinnvoll sein, aber weiterhin mit expliziten Limits und Timeout.

Q: Ersetzt Rate Limiting Budget Controls?
A: Nein. Rate Limiting steuert Aufruffrequenz, Budget Controls steuern die Gesamtkosten eines Runs.

Q: Wo sollten Counter gespeichert werden?
A: In gemeinsamem Low-Latency-Store mit atomaren Operationen (oft Redis). Ohne das werden Limits über Instanzen hinweg inkonsistent.

Wo Rate Limiting im Gesamtsystem liegt

Rate limiting ist eine der Ebenen von Agent Governance. Zusammen mit RBAC, Budgets, Step Limits, Approval und Audit bildet es ein einheitliches System zur Ausführungskontrolle.

Verwandte Seiten

Als Nächstes zum Thema:

⏱️ 6 Min. LesezeitAktualisiert 27. März 2026Schwierigkeit: ★★★
In OnceOnly umsetzen
Budgets + permissions you can enforce at the boundary.
In OnceOnly nutzen
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
writes:
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true }
Integriert: Production ControlOnceOnly
Guardrails für Tool-Calling-Agents
Shippe dieses Pattern mit Governance:
  • Budgets (Steps / Spend Caps)
  • Tool-Permissions (Allowlist / Blocklist)
  • Kill switch & Incident Stop
  • Idempotenz & Dedupe
  • Audit logs & Nachvollziehbarkeit
Integrierter Hinweis: OnceOnly ist eine Control-Layer für Production-Agent-Systeme.

Autor

Nick — Engineer, der Infrastruktur für KI-Agenten in Produktion aufbaut.

Fokus: Agent-Patterns, Failure-Modes, Runtime-Steuerung und Systemzuverlässigkeit.

🔗 GitHub: https://github.com/mykolademyanov


Redaktioneller Hinweis

Diese Dokumentation ist KI-gestützt, mit menschlicher redaktioneller Verantwortung für Genauigkeit, Klarheit und Produktionsrelevanz.

Der Inhalt basiert auf realen Ausfällen, Post-Mortems und operativen Vorfällen in produktiv eingesetzten KI-Agenten-Systemen.