Budget Explosion: Wenn Agent-Kosten stark steigen

Budget Explosion entsteht, wenn unkontrollierte Agent-Ausführung API- und Modellkosten schnell erhöht. Wie Budgets Kosten beherrschbar machen.
Auf dieser Seite
  1. Das Problem
  2. Warum das passiert
  3. Häufigste Fehlermuster
  4. Kumulatives Kontextwachstum (Context cost creep)
  5. Aufgeblähtes Tool-Fan-out (Tool fan-out spike)
  6. Retry-Amplifikation über Schichten
  7. Schneeballeffekt in der Queue (Queue cost snowball)
  8. Wie man diese Probleme erkennt
  9. Wie man Budget-Explosion von einer wirklich teuren Aufgabe unterscheidet
  10. Wie man solche Ausfälle stoppt
  11. Wo das in der Architektur umgesetzt wird
  12. Selbstcheck
  13. FAQ
  14. Verwandte Seiten

Das Problem

Die Anfrage wirkt simpel: Zahlungen für mehrere Bestellungen prüfen und eine kurze Zusammenfassung geben.

In den Traces sieht es anders aus: In 14 Minuten machte ein Run 63 Schritte, 41 Tool-Aufrufe und verbrannte etwa $11.80. Für diese Aufgabenklasse liegt es normalerweise bei etwa $0.20-0.30.

Es gibt keinen offensichtlichen Absturz: Ein Teil der Aufrufe liefert 200, der Agent "arbeitet" formal, aber die Run-Queue wächst, und cost_per_run verlässt schon in den ersten Minuten den Budget-Rahmen.

Das System fällt nicht hart aus.

Es bläht einfach langsam Rechnung und Run-Queue auf, bis die Kosten außerhalb des Budgets liegen.

Analogie: Stell dir ein Taxi mit Taxameter vor, das zwischen Fahrten nie zurückgesetzt wird. Das Auto fährt, Fahrgäste wechseln, aber die Summe steigt nur weiter. Bei Agenten sieht Budget Explosion genauso aus: Arbeit scheint weiterzulaufen, aber die Kosten wachsen schneller als der Nutzen.

Warum das passiert

Budget Explosion entsteht meist nicht durch einen einzelnen teuren Aufruf, sondern durch fehlende harte Kontrolle über kumulierte Laufzeitkosten.

In Production ist es typischerweise diese Mischung:

  1. Kontext und History wachsen Turn für Turn, dadurch wird jeder neue Model-Call teurer;
  2. ein Agent-Schritt kann Tool-Fan-out starten, und die Kosten multiplizieren sich;
  3. Retries leben in mehreren Schichten und machen aus einem kurzen Fehler eine lange Kostenwelle;
  4. es gibt kein einheitliches budget gate für Schritte, Tokens, Tool-Calls, Zeit und USD;
  5. ohne stop reasons und Cost-Metriken merkt man den Vorfall oft erst bei der Rechnung.

Im Trace sieht man das als gleichzeitiges Wachstum von prompt_tokens, tool_calls und retry_attempts, wobei jeder nächste Schritt teurer ist als der vorherige.

Ohne budget gate auf Runtime-Ebene verschärft jeder neue Schritt den Vorfall.

Häufigste Fehlermuster

In Production sieht man am häufigsten vier wiederkehrende Muster von Budget Explosion.

Kumulatives Kontextwachstum (Context cost creep)

Der Prompt wächst ohne Priorisierung: History, Retrieval und Tool-Output werden fast ohne Limits angehängt.

Typische Ursache: kein max_prompt_tokens, keine Source-Caps, kein Summarization-Tier.

Aufgeblähtes Tool-Fan-out (Tool fan-out spike)

Ein Schritt startet zu viele externe Aufrufe, oft parallel. Selbst ohne Fehler erhöht das die Run-Kosten stark.

Typische Ursache: keine per-tool Caps und kein bounded fan-out.

Retry-Amplifikation über Schichten

Retries passieren gleichzeitig in Runtime, Tool Gateway und SDK. Eine kurze Degradation einer Abhängigkeit wird zur langen Welle wiederholter Kosten.

Typische Ursache: Retry-Policy ist nicht an einer Stelle zentralisiert.

Schneeballeffekt in der Queue (Queue cost snowball)

Lange teure Runs belegen Worker, Backlog wächst, und neue Runs werden wegen Wait und Timeout ebenfalls teurer.

Typische Ursache: kein hartes max_seconds, max_steps und keine stop reason für Budget-Overflow.

Wie man diese Probleme erkennt

Budget Explosion sieht man gut an der Kombination aus Cost-, Runtime- und Queue-Metriken.

MetrikSignal für Budget ExplosionWas tun
cost_per_runstarker Anstieg der Kosten pro Runmax_usd aktivieren und budget gate vor jedem Schritt prüfen
tool_cost_shareAnteil der Tool-Kosten wird unverhältnismäßig hochFan-out begrenzen und per-tool Caps einführen
retry_attempts_per_runviele Wiederholungen derselben AufrufeRetries im Tool Gateway zentralisieren und Retry-Budget einführen
prompt_tokens_per_runstetiges Token-Wachstum ohne QualitätsgewinnCaps auf Context-Quellen + Summarization
queue_backlogQueue wächst zusammen mit langen teuren Runsmax_seconds begrenzen, runaway Runs kontrolliert beenden

Wie man Budget-Explosion von einer wirklich teuren Aufgabe unterscheidet

Nicht jede teure Aufgabe ist ein Incident. Die Kernfrage lautet: liefern zusätzliche Kosten einen vorhersehbaren Qualitätsgewinn.

Normal ist, wenn:

  • Kosten zusammen mit Genauigkeit oder Abdeckung bei komplexen Aufgaben steigen;
  • es ein kontrolliertes Kostenprofil für diese Anfrageklasse gibt;
  • cost_per_success innerhalb der Ziel-Unit-Economics bleibt.

Gefährlich ist, wenn:

  • Kosten schneller steigen als die Success-Rate;
  • dieselben Retries und Tool-Signaturen ohne neues Signal wiederkehren;
  • das Budget "explodiert", ohne Änderung bei Aufgabenkomplexität oder SLA.

Wie man solche Ausfälle stoppt

Praktisch sieht das so aus:

  1. Execution Budgets setzen: max_steps, max_seconds, max_prompt_tokens, max_tool_calls, max_usd;
  2. budget gate bei jedem Schritt prüfen, nicht erst am Ende des Runs;
  3. Retries in einem Tool Gateway zentralisieren und non-retryable Fehler abschneiden;
  4. bei Limitüberschreitung stop reason, partial/fallback und Alert zurückgeben.

Minimaler Guard für Budget-Kontrolle:

PYTHON
from dataclasses import dataclass
import time


@dataclass(frozen=True)
class BudgetLimits:
    max_steps: int = 30
    max_seconds: int = 120
    max_prompt_tokens: int = 12000
    max_tool_calls: int = 20
    max_retries: int = 6
    max_usd: float = 2.0


@dataclass
class BudgetUsage:
    steps: int = 0
    prompt_tokens: int = 0
    completion_tokens: int = 0
    tool_calls: int = 0
    retries: int = 0
    model_usd: float = 0.0
    tool_usd: float = 0.0


def estimate_model_usd(prompt_tokens: int, completion_tokens: int) -> float:
    # Placeholder pricing: replace with your real model pricing.
    return (prompt_tokens / 1000) * 0.003 + (completion_tokens / 1000) * 0.015


class BudgetGuard:
    def __init__(self, limits: BudgetLimits = BudgetLimits()):
        self.limits = limits
        self.usage = BudgetUsage()
        self.started_at = time.time()

    def total_usd(self) -> float:
        return self.usage.model_usd + self.usage.tool_usd

    def on_step(self) -> None:
        self.usage.steps += 1

    def on_model_call(self, prompt_tokens: int, completion_tokens: int) -> None:
        self.usage.prompt_tokens += prompt_tokens
        self.usage.completion_tokens += completion_tokens
        self.usage.model_usd = estimate_model_usd(
            self.usage.prompt_tokens,
            self.usage.completion_tokens,
        )

    def on_tool_call(self, tool_cost_usd: float = 0.0) -> None:
        self.usage.tool_calls += 1
        self.usage.tool_usd += tool_cost_usd

    def on_retry(self) -> None:
        self.usage.retries += 1

    def check(self) -> str | None:
        elapsed_s = time.time() - self.started_at

        if self.usage.steps > self.limits.max_steps:
            return "budget:max_steps"
        if elapsed_s > self.limits.max_seconds:
            return "budget:timeout"
        if self.usage.prompt_tokens > self.limits.max_prompt_tokens:
            return "budget:prompt_tokens"
        if self.usage.tool_calls > self.limits.max_tool_calls:
            return "budget:tool_calls"
        if self.usage.retries > self.limits.max_retries:
            return "budget:retries"
        if self.total_usd() > self.limits.max_usd:
            return "budget:usd"
        return None

Das ist ein Basis-Guard. In Production ergänzt man ihn meist mit per-tool Limits, backoff + jitter und separaten Budgets für Model- und Tool-Anteile. check() wird nach jedem Schritt aufgerufen, bevor die nächste Aktion geplant wird. on_model_call(...) und on_tool_call(...) aktualisieren Usage direkt nach dem echten Aufruf, damit die stop reason die realen Run-Kosten widerspiegelt.

Wo das in der Architektur umgesetzt wird

In Production wird Budget-Explosion-Kontrolle fast immer über drei Systemschichten verteilt.

Agent Runtime hält Execution Budgets, stop reasons und kontrollierte Beendigung von Runs. Hier wird Budget zur Regel statt zum Wunsch.

Tool Execution Layer steuert Fan-out, Retries, Timeouts und Kosten externer Aufrufe. Wenn Retries über mehrere Schichten verteilt sind, multiplizieren sich Kosten fast immer.

Memory Layer steuert, was in den Prompt kommt und was im Langzeitspeicher bleibt. Ohne diese Schicht wachsen Token-Kosten stabil weiter, auch ohne schwierigere Aufgaben.

Selbstcheck

Schneller Check vor dem Release. Hake die Punkte ab und sieh dir den Status unten an.
Das ist ein kurzer Sanity-Check, kein formales Audit.

Fortschritt: 0/7

⚠ Es gibt Risikosignale

Grundlegende Kontrollen fehlen. Schließen Sie die wichtigsten Checklist-Punkte vor dem Release.

FAQ

Q: Brauche ich eine exakte Kostenberechnung für einen Budget-Guard?
A: Nein. Am Anfang reicht eine konservative Schätzung. Ziel ist nicht Buchhaltung, sondern frühes Stoppen von runaway Runs.

Q: Mit welchem Limit sollte ich starten?
A: Starte konservativ mit max_usd und max_seconds, und erhöhe nur dort, wo ein Qualitätsgewinn belegt ist.

Q: Was tun, wenn das Budget bei einer wichtigen Anfrage ausgeschöpft ist?
A: Gib eine klare stop reason zurück, zeige ein partial Ergebnis und biete kontrollierte Eskalation an (höherer Tier oder manuelles Review).

Q: Wo sollen Retries liegen, damit Kosten nicht explodieren?
A: In einem choke point, meistens im Tool Gateway. Wenn Retries in mehreren Schichten liegen, ist Budget Explosion fast unvermeidbar.


Budget Explosion sieht fast nie wie ein lauter Crash aus. Es ist eine langsame finanzielle Degradation, die man meist nur in Metriken und im Vergleich zur Baseline sieht. Darum brauchen Production-Agents nicht nur bessere Modelle, sondern auch strikte Execution-Budget-Kontrolle.

Verwandte Seiten

Wenn dieses Problem in Production auftritt, sind diese Seiten ebenfalls hilfreich:

⏱️ 7 Min. LesezeitAktualisiert 12. März 2026Schwierigkeit: ★★☆
In OnceOnly umsetzen
Guardrails for loops, retries, and spend escalation.
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
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
Integriert: Production ControlOnceOnly
Guardrails für Tool-Calling-Agents
Shippe dieses Pattern mit Governance:
  • Budgets (Steps / Spend Caps)
  • Kill switch & Incident Stop
  • Audit logs & Nachvollziehbarkeit
  • Idempotenz & Dedupe
  • Tool-Permissions (Allowlist / Blocklist)
Integrierter Hinweis: OnceOnly ist eine Control-Layer für Production-Agent-Systeme.
Beispiel-Policy (Konzept)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}

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.