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:
- Kontext und History wachsen Turn für Turn, dadurch wird jeder neue Model-Call teurer;
- ein Agent-Schritt kann Tool-Fan-out starten, und die Kosten multiplizieren sich;
- Retries leben in mehreren Schichten und machen aus einem kurzen Fehler eine lange Kostenwelle;
- es gibt kein einheitliches budget gate für Schritte, Tokens, Tool-Calls, Zeit und USD;
- 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.
| Metrik | Signal für Budget Explosion | Was tun |
|---|---|---|
cost_per_run | starker Anstieg der Kosten pro Run | max_usd aktivieren und budget gate vor jedem Schritt prüfen |
tool_cost_share | Anteil der Tool-Kosten wird unverhältnismäßig hoch | Fan-out begrenzen und per-tool Caps einführen |
retry_attempts_per_run | viele Wiederholungen derselben Aufrufe | Retries im Tool Gateway zentralisieren und Retry-Budget einführen |
prompt_tokens_per_run | stetiges Token-Wachstum ohne Qualitätsgewinn | Caps auf Context-Quellen + Summarization |
queue_backlog | Queue wächst zusammen mit langen teuren Runs | max_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_successinnerhalb 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:
- Execution Budgets setzen:
max_steps,max_seconds,max_prompt_tokens,max_tool_calls,max_usd; - budget gate bei jedem Schritt prüfen, nicht erst am Ende des Runs;
- Retries in einem Tool Gateway zentralisieren und non-retryable Fehler abschneiden;
- bei Limitüberschreitung stop reason, partial/fallback und Alert zurückgeben.
Minimaler Guard für Budget-Kontrolle:
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:
- Warum AI-Agenten scheitern - allgemeine Karte von Ausfällen in Production.
- Token overuse - wie Kontextwachstum zu Kostenwachstum wird.
- Tool spam - wie wiederholte Tool-Aufrufe das Budget aufblasen.
- Tool failure - wie Fehler- und Retry-Wellen die Run-Kosten erhöhen.
- Agent Runtime - wo Execution Budgets und stop reasons gesetzt werden.
- Tool Execution Layer - wo Retries, Fan-out und Cost-Gates liegen.