Cost Limits für AI Agents (Stop Spending) + Code

Token-Limits reichen nicht. So setzt du harte Cost Caps, die Tool-Kosten + Model-Kosten zusammen tracken und einen sauberen Stop-Reason liefern.
Auf dieser Seite
  1. Problem (aus der Praxis)
  2. Warum das in Production bricht
  3. 1) Teams limitieren Tokens und vergessen Tools
  4. 2) Cost ohne Stop-Reason ist nicht operierbar
  5. 3) Ohne per-tenant Caps eskaliert ein einzelner Kunde deinen Monat
  6. Implementierungsbeispiel (echter Code)
  7. Echter Incident (mit Zahlen)
  8. Abwägungen
  9. Wann du es NICHT nutzen solltest
  10. Checkliste (Copy/Paste)
  11. Sicheres Default-Config-Snippet (JSON/YAML)
  12. FAQ (3–5)
  13. Verwandte Seiten (3–6 Links)
Interaktiver Ablauf
Szenario:
Schritt 1/3: Execution

Action is proposed as structured data (tool + args).

Problem (aus der Praxis)

Du schaust auf deine LLM-Usage und denkst: „Alles okay.“

Dann kommt die Rechnung vom Browser-Vendor / Scraper / Datenanbieter. Und plötzlich ist klar: du hast „Speed Limits“ auf einem Rad gebaut.

Cost Limits sind nicht sexy. Sie sind der Unterschied zwischen:

  • „Agent ist gelegentlich teuer“
  • und „Agent ist ein unbounded Cost-Generator“

Warum das in Production bricht

1) Teams limitieren Tokens und vergessen Tools

In realen Agenten:

  • Tokens sind predictable-ish
  • Tools sind der wilde Teil (Retries, Rate Limits, variable Work)

Wenn dein Tool $0.20 pro Call kostet, brauchst du 10 Calls, um $2 zu verbrennen. Das passiert schneller, als ein Promptrun fertig tippt.

2) Cost ohne Stop-Reason ist nicht operierbar

Wenn du nur „timeout“ hast, sieht niemand, dass es eigentlich „zu teuer“ war. Und dann retryen Leute. Und es wird noch teurer.

3) Ohne per-tenant Caps eskaliert ein einzelner Kunde deinen Monat

Multi-tenant heißt: ein Customer kann den Cost-Graphen für alle ruinieren, wenn du nicht capst.

Implementierungsbeispiel (echter Code)

Ein einfacher „Cost Guard“:

  • token + tool costs in einem State
  • checkt nach jedem Step und Tool Call
  • stoppt sauber mit max_usd
PYTHON
from dataclasses import dataclass, field
import time


TOOL_USD = {
  "browser.run": 0.20,
  "search.read": 0.00,
}


@dataclass(frozen=True)
class CostPolicy:
  max_usd: float = 1.00
  max_seconds: int = 60


@dataclass
class CostState:
  started_at: float = field(default_factory=time.time)
  tokens_in: int = 0
  tokens_out: int = 0
  tool_usd: float = 0.0

  def elapsed_s(self) -> float:
      return time.time() - self.started_at


def estimate_model_usd(tokens_in: int, tokens_out: int) -> float:
  return (tokens_in + tokens_out) * 0.000002


class CostExceeded(RuntimeError):
  def __init__(self, stop_reason: str, *, state: CostState):
      super().__init__(stop_reason)
      self.stop_reason = stop_reason
      self.state = state


class CostGuard:
  def __init__(self, policy: CostPolicy):
      self.policy = policy
      self.state = CostState()

  def total_usd(self) -> float:
      return estimate_model_usd(self.state.tokens_in, self.state.tokens_out) + self.state.tool_usd

  def check(self) -> None:
      if self.total_usd() > self.policy.max_usd:
          raise CostExceeded("max_usd", state=self.state)
      if self.state.elapsed_s() > self.policy.max_seconds:
          raise CostExceeded("max_seconds", state=self.state)

  def on_model(self, *, tokens_in: int, tokens_out: int) -> None:
      self.state.tokens_in += tokens_in
      self.state.tokens_out += tokens_out
      self.check()

  def on_tool(self, *, tool: str) -> None:
      self.state.tool_usd += float(TOOL_USD.get(tool, 0.0))
      self.check()
JAVASCRIPT
const TOOL_USD = { "browser.run": 0.2, "search.read": 0.0 };

export class CostExceeded extends Error {
constructor(stopReason, { state }) {
  super(stopReason);
  this.stopReason = stopReason;
  this.state = state;
}
}

export class CostGuard {
constructor(policy) {
  this.policy = policy;
  this.state = { startedAtMs: Date.now(), tokensIn: 0, tokensOut: 0, toolUsd: 0 };
}

totalUsd() {
  return estimateModelUsd(this.state.tokensIn, this.state.tokensOut) + this.state.toolUsd;
}

check() {
  if (this.totalUsd() > this.policy.maxUsd) throw new CostExceeded("max_usd", { state: this.state });
  if ((Date.now() - this.state.startedAtMs) / 1000 > this.policy.maxSeconds) {
    throw new CostExceeded("max_seconds", { state: this.state });
  }
}

onModel({ tokensIn, tokensOut }) {
  this.state.tokensIn += tokensIn;
  this.state.tokensOut += tokensOut;
  this.check();
}

onTool({ tool }) {
  this.state.toolUsd += Number(TOOL_USD[tool] ?? 0);
  this.check();
}
}

function estimateModelUsd(tokensIn, tokensOut) {
return (tokensIn + tokensOut) * 0.000002;
}

Echter Incident (mit Zahlen)

Wir haben eine „simple“ Research-Loop gesehen, die Browser-Tools benutzt hat.

Ein Vendor hatte an dem Tag Instabilität. Tools retryen. Agent retry’t. Und plötzlich kostet ein einziger User-Request mehr als dein durchschnittlicher Tageswert.

Impact:

  • p95 spend/request stieg auf $4.80
  • Queue wurde voll (weil Runs länger wurden)
  • Support hat 2 Stunden lang „es ist langsam“ Tickets triagiert

Fix:

  1. harte Cost Cap (max_usd) + Stop-Reason
  2. Tool-level Circuit Breaker bei Vendor Instabilität
  3. Caching/Dedupe bei gleichen URLs/Queries

Abwägungen

  • Cost Caps schneiden manchmal „nützliche“ Runs ab.
  • Exakte Kosten pro Tool Call sind schwer; Approx ist okay für Guardrails.
  • Cost Limits ohne Budgets (Steps/Time/Tool Calls) sind unvollständig.

Wann du es NICHT nutzen solltest

  • Wenn du wirklich keine Kosten approximieren kannst, nutz wenigstens Time + Tool-call budgets.
  • Für read-only, free internal tools: du brauchst trotzdem Caps, sobald ein Vendor Geld kostet.

Checkliste (Copy/Paste)

  • [ ] max_usd cap pro run
  • [ ] Stop-Reason max_usd in Logs + Response
  • [ ] Tool costs approximieren (konservativ)
  • [ ] Circuit breaker für flaky vendors
  • [ ] per-tenant caps / tiers
  • [ ] Alert: spike in max_usd stops

Sicheres Default-Config-Snippet (JSON/YAML)

YAML
cost_limits:
  max_usd: 1.00
  max_seconds: 60
tool_costs_usd:
  browser.run: 0.20
  search.read: 0.00
stop_reasons:
  log: true
  surface_to_user: true

FAQ (3–5)

Reicht es, nur Tool Costs zu cappen?
Nein. Tokens können auch eskalieren (lange Kontext-Threads, Retries). Track beides.
Wie setze ich per-tenant Cost Limits?
Über Tiers. Und logge spend per tenant, sonst merkst du’s erst am Monatsende.
Was ist eine gute Default-Cap?
So niedrig, dass du nicht überrascht wirst, aber hoch genug für ‚normal‘. Starte z. B. bei $1 und adjust nach Daten.
Warum nicht einfach den günstigsten Model nehmen?
Model kostet selten am meisten. Tool-Calls + Retries sind oft der echte Cost-Treiber.

Q: Reicht es, nur Tool Costs zu cappen?
A: Nein. Tokens können auch eskalieren (lange Kontext-Threads, Retries). Track beides.

Q: Wie setze ich per-tenant Cost Limits?
A: Über Tiers. Und logge spend per tenant, sonst merkst du’s erst am Monatsende.

Q: Was ist eine gute Default-Cap?
A: So niedrig, dass du nicht überrascht wirst, aber hoch genug für „normal“. Starte z. B. bei $1 und adjust nach Daten.

Q: Warum nicht einfach den günstigsten Model nehmen?
A: Model kostet selten am meisten. Tool-Calls + Retries sind oft der echte Cost-Treiber.

Nicht sicher, ob das dein Fall ist?

Agent gestalten ->
⏱️ 5 Min. LesezeitAktualisiert Mär, 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

Diese Dokumentation wird von Engineers kuratiert und gepflegt, die AI-Agenten in der Produktion betreiben.

Die Inhalte sind KI-gestützt, mit menschlicher redaktioneller Verantwortung für Genauigkeit, Klarheit und Produktionsrelevanz.

Patterns und Empfehlungen basieren auf Post-Mortems, Failure-Modes und operativen Incidents in produktiven Systemen, auch bei der Entwicklung und dem Betrieb von Governance-Infrastruktur für Agenten bei OnceOnly.