
AI Agent Ops: Agenten in Produktion überwachen, auditieren und kontrollieren
TL;DR: „Ein Agent in Produktion braucht drei Dinge: Observability (was tut er?), Audit (was hat er getan?), und Control (wie stoppe ich ihn?). Hier ist der operative Leitfaden."
— Till FreitagIn 30 Sekunden
Governance definiert die Regeln. Aber Regeln ohne Durchsetzung sind wertlos. Dieser Artikel zeigt die operative Seite: Wie man Agenten in Produktion überwacht, jede Entscheidung nachvollziehbar macht und im Notfall innerhalb von Sekunden eingreifen kann.
Das Problem: Agenten sind keine APIs
Eine API ist deterministisch: gleicher Input, gleicher Output. Ein Agent ist nicht-deterministisch: Er entscheidet selbst über Toolauswahl, Reihenfolge und Parameter. Das macht klassisches Monitoring unbrauchbar.
| API | Agent | |
|---|---|---|
| Verhalten | Deterministisch | Non-deterministisch |
| Aufrufkette | Bekannt | Dynamisch |
| Fehlerfall | Exception → Retry | Fehlentscheidung → Seiteneffekte |
| Monitoring | Statuscode + Latenz | Reasoning-Trace + Tool-Calls + Ergebnis |
Was wir brauchen: ein Monitoring-Stack, der nicht nur ob etwas passiert ist, sondern warum es passiert ist.
Die drei Säulen von Agent Ops
1. Observability: Was tut der Agent gerade?
Observability für Agenten geht über Metriken hinaus. Man braucht den vollständigen Reasoning-Trace:
@dataclass
class AgentTrace:
trace_id: str
timestamp: datetime
input_hash: str # Nie Klartext loggen
reasoning_steps: list[ReasoningStep]
tool_calls: list[ToolCall]
model_used: str
routing_decision: str # local / cloud
total_tokens: int
total_latency_ms: float
outcome: str # success / error / timeout / killed
@dataclass
class ToolCall:
tool_name: str
input_hash: str
output_hash: str
sandbox_type: str # container / wasm / kernel
latency_ms: float
status: str # success / error / timeout
side_effects: list[str] # ["db_write", "email_sent", ...]Entscheidend: Jeder Tool-Call muss seine Seiteneffekte deklarieren. Nur so lässt sich im Nachhinein rekonstruieren, was der Agent tatsächlich verändert hat.
Dashboards, die zählen
Vergiss vanity metrics. Diese vier Kennzahlen definieren, ob ein Agent in Produktion tragbar ist:
| Metrik | Was sie zeigt | Grenzwert |
|---|---|---|
| Tool-Call Rejection Rate | Wie oft wird ein Tool-Call von der Policy abgelehnt? | >5% → Policy zu streng oder Agent halluziniert |
| Privacy Route Ratio | Anteil der Anfragen auf dem lokalen Pfad | Branchenabhängig, aber trackbar |
| Reasoning Depth | Durchschnittliche Schritte bis zur Antwort | >10 → Agent könnte in Loops stecken |
| Side Effect Rate | Wie oft löst der Agent schreibende Aktionen aus? | Jede schreibende Aktion braucht Audit-Eintrag |
2. Audit: Was hat der Agent getan?
Audit ist nicht dasselbe wie Logging. Logging ist für Entwickler, Audit ist für Compliance. Der Unterschied:
| Logging | Audit | |
|---|---|---|
| Zielgruppe | Entwickler | Compliance, Geschäftsführung, Regulierer |
| Inhalt | Technische Details | Entscheidungen und deren Begründung |
| Aufbewahrung | Tage bis Wochen | Jahre (DSGVO: bis zu 10 Jahre) |
| Unveränderbarkeit | Nice-to-have | Pflicht |
| Format | Frei | Strukturiert, maschinenlesbar |
Audit-Trail-Architektur
class AuditTrail:
def __init__(self, storage: AuditStorage):
self.storage = storage
def record(self, event: AuditEvent):
"""Append-only. Kein Update, kein Delete."""
signed_event = self._sign(event)
self.storage.append(signed_event)
def _sign(self, event: AuditEvent) -> SignedAuditEvent:
"""Kryptographische Signatur für Unveränderbarkeit."""
previous_hash = self.storage.get_last_hash()
event_hash = hash_chain(previous_hash, event)
return SignedAuditEvent(
event=event,
hash=event_hash,
previous_hash=previous_hash,
)
@dataclass
class AuditEvent:
timestamp: datetime
agent_id: str
action_type: str # "tool_call" | "routing" | "escalation"
decision: str # Was wurde entschieden?
policy_basis: str # Welche Policy hat die Entscheidung getrieben?
data_classification: str # sensitive | non_sensitive
model_path: str # local | cloud
outcome: str
human_override: bool # Wurde manuell eingegriffen?Hash-Chain: Jeder Audit-Eintrag referenziert den Hash des vorherigen Eintrags. Manipulation eines einzelnen Eintrags bricht die Kette – vergleichbar mit einer Mini-Blockchain für Agent-Entscheidungen.
Was muss auditiert werden?
Nicht alles. Aber mindestens:
- Jede Routing-Entscheidung – Welches Modell wurde gewählt und warum?
- Jeder schreibende Tool-Call – DB-Writes, E-Mails, API-Calls mit Seiteneffekten
- Jede Eskalation – Wann hat der Agent an einen Menschen übergeben?
- Jede Policy-Verletzung – Auch Versuche, die geblockt wurden
- Jeder manuelle Eingriff – Kill-Switch, Override, Konfigurationsänderung
3. Control: Wie stoppe ich den Agenten?
Das ist der Teil, den die meisten vergessen. Einen Agenten zu starten ist einfach. Ihn kontrolliert zu stoppen ist die eigentliche Herausforderung.
Kill-Switch-Hierarchie
Level 0: Soft Stop
→ Agent beendet aktuellen Task, nimmt keine neuen an
→ Graceful Shutdown
Level 1: Immediate Stop
→ Laufende Tool-Calls werden abgebrochen
→ Pending Side Effects werden gerollt (wo möglich)
→ Agent geht in Quarantäne-Modus
Level 2: Emergency Kill
→ Prozess wird sofort beendet
→ Alle Container werden gestoppt
→ Netzwerkzugriff wird gekappt
→ Incident wird erstelltImplementierung
class AgentController:
def __init__(self, agent_id: str):
self.agent_id = agent_id
self.state = AgentState.RUNNING
async def soft_stop(self, reason: str):
"""Level 0: Agent beendet aktuellen Task."""
self.state = AgentState.DRAINING
await self._notify_agent("stop_accepting")
await self._wait_for_current_task(timeout=60)
self.state = AgentState.STOPPED
self._audit("soft_stop", reason)
async def immediate_stop(self, reason: str):
"""Level 1: Sofortiger Stop mit Rollback."""
self.state = AgentState.STOPPING
await self._cancel_running_tools()
await self._rollback_pending_effects()
self.state = AgentState.QUARANTINED
self._audit("immediate_stop", reason)
async def emergency_kill(self, reason: str):
"""Level 2: Notfall-Abbruch."""
self.state = AgentState.KILLED
await self._kill_process()
await self._stop_all_containers()
await self._revoke_network()
self._create_incident(severity="critical", reason=reason)
self._audit("emergency_kill", reason)Automatische Trigger
Kill-Switches sollten nicht nur manuell auslösbar sein:
AUTO_KILL_TRIGGERS = [
# Agent steckt in einer Schleife
Trigger(
condition="reasoning_steps > 20 in single task",
action="soft_stop",
reason="Possible reasoning loop detected",
),
# Zu viele schreibende Aktionen in kurzer Zeit
Trigger(
condition="side_effects > 10 in 60 seconds",
action="immediate_stop",
reason="Abnormal side effect rate",
),
# Versuch, sensible Daten an Cloud zu senden
Trigger(
condition="privacy_violation_attempt",
action="emergency_kill",
reason="Privacy policy violation",
),
# Unbekannter Tool-Call
Trigger(
condition="tool_call not in allowed_tools",
action="immediate_stop",
reason="Unauthorized tool call attempted",
),
]Human-in-the-Loop: Wo der Mensch eingreifen muss
Nicht jede Entscheidung braucht einen Menschen. Aber manche schon:
Agent-Entscheidung
└── Ist es eine schreibende Aktion?
├── Nein → Automatisch
└── Ja
└── Betrifft es sensible Daten?
├── Nein → Automatisch mit Audit
└── Ja → Human Approval erforderlich
└── Ist es reversibel?
├── Ja → Approval mit 1 Person
└── Nein → Approval mit 2 Personen (4-Augen)Approval Gates
class ApprovalGate:
def __init__(self, required_approvers: int = 1):
self.required = required_approvers
async def request_approval(
self,
action: str,
context: dict,
timeout_minutes: int = 30,
) -> ApprovalResult:
ticket = await self._create_approval_ticket(action, context)
# Warte auf Approval oder Timeout
result = await self._wait_for_approvals(
ticket,
required=self.required,
timeout=timeout_minutes * 60,
)
if result.timed_out:
return ApprovalResult.DENIED # Timeout = Ablehnung
return resultWichtig: Timeout ist immer Ablehnung. Ein Agent, der auf eine nie kommende Genehmigung wartet, ist genauso gefährlich wie einer ohne Genehmigung.
Alerting: Die richtigen Signale
Zu viele Alerts sind genauso schlimm wie keine. Die Kunst ist, nur bei echten Problemen zu alerten:
| Alert-Level | Trigger | Aktion |
|---|---|---|
| Info | Agent hat Task erfolgreich abgeschlossen mit ungewöhnlich vielen Steps | Dashboard-Eintrag |
| Warning | Privacy-Route-Ratio weicht >20% vom Durchschnitt ab | Slack-Notification an Agent-Owner |
| Error | Tool-Call fehlgeschlagen nach 3 Retries | PagerDuty an On-Call |
| Critical | Privacy-Violation-Attempt oder Kill-Switch ausgelöst | PagerDuty + Incident + Agent gestoppt |
Der komplette Stack
┌─────────────────────────────────────────────┐
│ Alerting │
│ (PagerDuty / Slack / monday.com Incidents) │
├─────────────────────────────────────────────┤
│ Control Plane │
│ Kill-Switches │ Approval Gates │ Policies │
├─────────────────────────────────────────────┤
│ Audit Trail │
│ Hash-Chain │ Compliance Reports │ Retention│
├─────────────────────────────────────────────┤
│ Observability │
│ Traces │ Metrics │ Dashboards │ Logs │
├─────────────────────────────────────────────┤
│ Agent Runtime │
│ Privacy Router │ Sandbox │ Tool Execution │
└─────────────────────────────────────────────┘Integration mit bestehenden Tools
Agent Ops muss nicht von Null gebaut werden. Bestehende Tools können adaptiert werden:
| Funktion | Tool | Anpassung |
|---|---|---|
| Traces | OpenTelemetry | Custom Spans für Reasoning Steps |
| Metriken | Prometheus / Grafana | Agent-spezifische Metriken |
| Audit | Append-only DB (z.B. EventStore) | Schema für Agent-Events |
| Alerts | PagerDuty / OpsGenie | Agent-spezifische Severity-Rules |
| Incidents | monday.com Service | Automatische Ticket-Erstellung |
| Approval | Slack / monday.com | Approval-Workflows |
Checkliste: Agent Production Readiness
Bevor ein Agent in Produktion geht, müssen diese Punkte erfüllt sein:
- Observability: Vollständiger Reasoning-Trace wird erfasst
- Audit-Trail: Append-only, signiert, mit Hash-Chain
- Kill-Switch: Alle drei Level implementiert und getestet
- Automatische Trigger: Loop-Detection, Rate-Limiting, Policy-Enforcement
- Human-in-the-Loop: Approval Gates für sensible schreibende Aktionen
- Alerting: Abgestuft (Info → Warning → Error → Critical)
- Privacy Routing: Sensible Daten bleiben lokal (Privacy Router)
- Sandboxing: Tool-Calls isoliert (Container/WASM/Kernel)
- Rollback-Plan: Wie wird ein fehlerhafter Agent-Run rückgängig gemacht?
- Incident-Playbook: Wer wird wann informiert und was passiert dann?
Fazit
Einen Agenten zu bauen ist der einfache Teil. Ihn in Produktion zu betreiben – sicher, auditierbar, kontrollierbar – ist die eigentliche Arbeit. Die drei Säulen Observability, Audit und Control sind nicht optional. Sie sind die Voraussetzung dafür, dass autonome Agenten im Unternehmen überhaupt eingesetzt werden dürfen.
Drei Takeaways:
- Observability ≠ Logging – Du brauchst den vollständigen Reasoning-Trace, nicht nur Statuscode und Latenz
- Audit-Trails müssen unveränderbar sein – Hash-Chain, kryptographisch signiert, append-only
- Kill-Switches brauchen drei Level – Graceful, Immediate, Emergency – und automatische Trigger
→ Autonome KI-Agenten: Governance-Framework → Privacy Router mit OpenClaw bauen → Agent Sandboxing: Container vs. WASM vs. Kernel → Die 5 Bausteine eines KI-Agenten → Kontakt aufnehmen








