Problem (aus der Praxis)
AutoGPT ist der Archetyp von “lass es laufen”. LangGraph ist der Archetyp von “mach den Loop explizit”.
In Prod zählt diese Philosophie mehr als API-Details. Eins optimiert für Autonomie. Das andere für Kontrolle.
Wenn du echte User und echte Budgets hast: erst Kontrolle verdienen, dann Autonomie.
Schnelle Entscheidung (wer sollte was wählen)
- LangGraph: wenn du Replay, Tests, und explizite Stop Reasons brauchst. Sicherer Default.
- AutoGPT-style Autonomie: nur wenn Risk niedrig ist und Budgets/Monitoring/Kill Switches schon stehen.
- Multi-Tenant + Writes: nicht mit “let it run” starten.
Warum man in Prod die falsche Wahl trifft
- Autonomie wird überbewertet: in Prod heißt das oft Tool Spam + Budget Explosion.
- “Boring code” wird unterschätzt: explizite Flows sind debugbar um 03:00.
- Control Layer fehlt: Budgets/Permissions/Validation/Stop Reasons sind nicht optional.
Vergleichstabelle
| Kriterium | LangGraph-style | AutoGPT-style | Prod-Relevanz | |---|---|---|---| | Kontrolle | Hoch | Niedrig/mittel | Runaway Loops stoppen | | Debuggability | Hoch | Niedrig | Replay + Trace | | Kosten | besser | schlechter | Spend spikes | | Outage Amplification | geringer | höher | Abhängigkeiten schützen |
Wo das in Production bricht
Autonomie bricht:
- “one more try” loops
- Retries auf mehreren Ebenen
- Tool Space wird “explored”
Explizite Flows brechen:
- State Machine wächst
- trotzdem keine Validation
- zu viel im Prompt, zu wenig in Code
Implementierungsbeispiel (echter Code)
Autonomie braucht Sandbox: Budgets + Tool Allowlist + Stop Reasons.
from dataclasses import dataclass
from typing import Any
import time
@dataclass(frozen=True)
class Budgets:
max_steps: int = 30
max_seconds: int = 90
max_tool_calls: int = 15
class Stop(RuntimeError):
def __init__(self, reason: str):
super().__init__(reason)
self.reason = reason
class GuardedTools:
def __init__(self, *, allow: set[str]):
self.allow = allow
self.calls = 0
def call(self, tool: str, args: dict[str, Any], *, budgets: Budgets) -> Any:
self.calls += 1
if self.calls > budgets.max_tool_calls:
raise Stop("max_tool_calls")
if tool not in self.allow:
raise Stop(f"tool_denied:{tool}")
return tool_impl(tool, args=args) # (pseudo)
def run(task: str, *, budgets: Budgets) -> dict[str, Any]:
tools = GuardedTools(allow={"search.read", "kb.read", "http.get"})
started = time.time()
for _ in range(budgets.max_steps):
if time.time() - started > budgets.max_seconds:
return {"status": "stopped", "stop_reason": "max_seconds"}
action = llm_decide(task) # (pseudo)
if action.kind == "final":
return {"status": "ok", "answer": action.final_answer}
try:
obs = tools.call(action.name, action.args, budgets=budgets)
except Stop as e:
return {"status": "stopped", "stop_reason": e.reason}
task = update(task, action, obs) # (pseudo)
return {"status": "stopped", "stop_reason": "max_steps"}export class Stop extends Error {
constructor(reason) {
super(reason);
this.reason = reason;
}
}
export class GuardedTools {
constructor({ allow = [] } = {}) {
this.allow = new Set(allow);
this.calls = 0;
}
call(tool, args, { budgets }) {
this.calls += 1;
if (this.calls > budgets.maxToolCalls) throw new Stop("max_tool_calls");
if (!this.allow.has(tool)) throw new Stop("tool_denied:" + tool);
return toolImpl(tool, { args }); // (pseudo)
}
}Echter Incident (mit Zahlen)
Autonomer Research-Agent ohne harte Budgets. Er suchte, bis er “confident” war.
Impact:
- ein Run: ~17 Minuten
- tool calls: ~140
- spend: ~$74
- User retryten, weil UI “stuck” wirkte → Kosten multipliziert
Fix: Budgets + degrade mode + Stop Reasons in UI.
Migrationspfad (A → B)
- AutoGPT → LangGraph: instrumentieren, happy path explizit codieren, autonomy nur bounded als Branch.
- LangGraph → mehr Autonomie: risky Transitions explizit lassen, autonomy nur in bounded Investigation Nodes.
Entscheidungshilfe
- Predictable behavior → explicit flow.
- Exploration, aber bounded → autonomy branch.
- Ohne Monitoring/Spend-Metering → keine Autonomie.
Abwägungen
- Explizite Flows brauchen mehr upfront Engineering.
- Autonomie löst weird tasks, erhöht operational risk.
- Hybrid ist oft best.
Wann du es NICHT nutzen solltest
- Keine Autonomie mit Write Tools in Multi-Tenant Prod.
- Graphs sind keine Ausrede, Validation/Monitoring zu skippen.
- Framework ist keine Governance.
Checkliste (Copy/Paste)
- [ ] Happy path explizit
- [ ] Autonomie bounded
- [ ] Default-deny Tools
- [ ] Stop Reasons
- [ ] Monitor tool_calls/run und spend/run
- [ ] Kill Switch (writes/expensive tools)
Sicheres Default-Config-Snippet (JSON/YAML)
mode:
default: "explicit_flow"
autonomy:
allowed_for: ["investigation_nodes"]
budgets:
max_steps: 30
max_seconds: 90
max_tool_calls: 15
tools:
allow: ["search.read", "kb.read", "http.get"]
writes:
require_approval: true
FAQ (3–5)
Von Patterns genutzt
Verwandte Failures
Verwandte Seiten (3–6 Links)
- Foundations: Workflow vs agent · Planning vs reactive
- Failure: Tool spam · Budget explosion
- Governance (EN): Budget controls · Step limits
- Production stack: Production stack