Normal path: execute → tool → observe.
Problem (aus der Praxis)
Kein Full Outage. Schlimmer.
Ein Tool ist flaky:
- manchmal 200
- manchmal Timeout
- manchmal 502
Dein Agent versucht “fertig zu werden”. User retry’n weil sie Timeouts sehen. Budgets brennen, weil jeder Retry ein neuer Run ist.
Partial Outages zeigen, ob dein Agent ein Engineer ist oder ein Gambler.
Warum das in Production bricht
Partial Outages sind fies, weil Erfolg intermittierend ist. Das verführt Loops.
1) Intermittenter Erfolg triggert “weiter versuchen”
LLMs sind optimistisch. Wenn einmal etwas klappt, wollen sie “vollständig” werden.
In Prod heißt das: runaway spend.
2) Kein Konzept von Tool Health
Ohne “tool X ist degraded” Signal wird der Agent:
- weiter callen
- retry’n
- replan’n und wieder callen
Du brauchst Health:
- breaker state
- error rate
- latency spikes
3) Kein Safe-mode Verhalten
Wenn Tool degraded ist, brauchst du ein Verhalten ohne das Tool:
- cached data
- partial results
- stop reason und User entscheidet
4) “All or nothing” API Contract
Wenn dein API Contract “immer volle Antwort” ist, thrash’t der Agent.
Besser:
- partial results + confidence + stop reason
- optional: async continuation
Implementierungsbeispiel (echter Code)
Health Snapshot am Run-Start:
- critical tool degraded → disable im Run
- safe-mode
- partial results + stop reason
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class Health:
degraded_tools: set[str]
def snapshot_health() -> Health:
return Health(degraded_tools=set(get_degraded_tools())) # (pseudo)
def safe_tools_for_run(health: Health) -> set[str]:
allow = {"search.read", "kb.read", "http.get"}
for t in health.degraded_tools:
allow.discard(t)
return allow
def run(task: str) -> dict[str, Any]:
health = snapshot_health()
allow = safe_tools_for_run(health)
if "kb.read" not in allow:
return {
"status": "degraded",
"reason": "kb.read degraded",
"partial": "KB ist gerade nicht zuverlässig. Das kann ich ohne KB machen…",
}
return agent_loop(task, allow=allow) # (pseudo)export function snapshotHealth() {
return { degradedTools: new Set(getDegradedTools()) }; // (pseudo)
}
export function safeToolsForRun(health) {
const allow = new Set(["search.read", "kb.read", "http.get"]);
for (const t of health.degradedTools) allow.delete(t);
return allow;
}
export function run(task) {
const health = snapshotHealth();
const allow = safeToolsForRun(health);
if (!allow.has("kb.read")) {
return {
status: "degraded",
reason: "kb.read degraded",
partial: "KB ist gerade nicht zuverlässig. Das kann ich ohne KB machen…",
};
}
return agentLoop(task, { allow }); // (pseudo)
}Während Partial Outage ist das Ziel nicht “succeed um jeden Preis”. Ziel ist “mach aus Partial Outage keine Full Outage”.
Echter Incident (mit Zahlen)
Support Agent nutzte kb.read.
KB degradete (p95 von ~300ms → 9s, intermittierende Timeouts). Agent machte weiter, weil es manchmal ging.
Impact:
- avg run time: 8s → 52s
- client retries verdoppelten Traffic
- Pager wegen “agent timeouts” statt wegen KB Root Cause
- spend +~$180/Tag durch Retries + größere Prompts
Fix:
- health snapshot + degrade mode
- fail fast wenn breaker open
- partial results + stop reason
- “retry later” statt silent timeouts
Lesson: Stop Reasons sind User-Features.
Abwägungen
- Degrade Antworten sind weniger komplett.
- Fail fast senkt momentane success rate.
- Health kann falsch liegen. Besser als Thrash.
Wann du es NICHT nutzen solltest
- Wenn Vollständigkeit Pflicht ist: async workflows + progress.
- Wenn du keine partial semantics hast: du endest in timeouts.
- Wenn du keine Health Signals hast: starte mit Budgets + Breaker Defaults.
Checkliste (Copy/Paste)
- [ ] Tool Health Snapshot am Start
- [ ] Degrade Mode Policy (tools disabled, read-only, cached)
- [ ] Fail fast bei breaker open
- [ ] Partial results + stop reason
- [ ] Budgets gelten trotzdem
- [ ] Alerting: degraded runs vs normal runs
Sicheres Default-Config-Snippet (JSON/YAML)
degrade_mode:
enabled: true
disable_tools_when_degraded: true
allow_partial_results: true
health:
breaker_open_means_degraded: true
budgets:
max_seconds: 60
max_tool_calls: 12
FAQ (3–5)
Von Patterns genutzt
Verwandte Failures
Q: Warum nicht einfach retry’n bis es klappt?
A: Weil intermittente Failures + Retries Outages verstärken. Der Agent wird zum Load Generator.
Q: Was returne ich im Degrade Mode?
A: Partial results, cached data oder ein klares “geht gerade nicht” mit stop reason.
Q: Brauche ich per-tool Health?
A: Ja für externe Dependencies. Starte mit breaker state + error rate.
Q: Kommen User mit partial klar?
A: Besser als Timeouts. Gib stop reason und Option “retry later”.
Verwandte Seiten (3–6 Links)
- Foundations: Production-ready Agent · Warum Agents scheitern
- Failure: Cascading Tool Failures · Tool-Spam Loops
- Governance: Tool Permissions
- Production stack: Production Stack