Human-in-the-Loop Patterns
Wissen
Nicht jede Entscheidung sollte ein Agent allein treffen. Ein Agent, der automatisch Code in Produktion deployt, Kunden-E-Mails versendet oder Datenbankmigrationen ausführt, braucht menschliche Kontrolle an kritischen Punkten. Human-in-the-Loop (HITL) Patterns definieren, wann und wie ein Mensch eingreift.
Wann muss ein Mensch entscheiden?
Die Entscheidung, ob ein Mensch eingreifen muss, hängt von zwei Faktoren ab: Risiko und Reversibilität.
| Reversibel (Undo möglich) | Irreversibel (kein Undo) | |
|---|---|---|
| Niedriges Risiko | Agent entscheidet autonom | Agent entscheidet, Mensch wird informiert |
| Hohes Risiko | Mensch gibt Freigabe | Mensch muss aktiv bestätigen (Approval-Gate) |
Beispiele:
- Autonom: Code-Formatierung, Lint-Fixes, Test-Ausführung
- Informieren: Dependency-Updates, Dokumentations-Änderungen
- Freigabe: Code-Deployment, API-Schema-Änderungen
- Aktive Bestätigung: Datenbankmigration, Löschung von Produktionsdaten, Kunden-Kommunikation
Die drei HITL-Patterns
1. Approval-Gate: Der Agent hält an einem definierten Punkt an und wartet auf menschliche Freigabe, bevor er weitermacht.
2. Escalation: Der Agent erkennt, dass er an seine Grenzen stößt, und übergibt an einen Menschen -- mit vollständigem Kontext.
3. Feedback-Loop: Der Mensch gibt dem Agent nach Abschluss einer Aufgabe Feedback, das in zukünftige Entscheidungen einfließt.
Verstehen
Approval-Gate implementieren
import json
from enum import Enum
from dataclasses import dataclass, field
from datetime import datetime
class ApprovalStatus(Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"
TIMEOUT = "timeout"
@dataclass
class ApprovalRequest:
task_id: str
agent_name: str
action: str
context: dict
risk_level: str
status: ApprovalStatus = ApprovalStatus.PENDING
reviewer: str = ""
feedback: str = ""
created_at: str = field(default_factory=lambda: datetime.now().isoformat())
class ApprovalGate:
def __init__(self, notification_handler=None):
self.pending_requests: list[ApprovalRequest] = []
self.notify = notification_handler or self._default_notify
def request_approval(
self, task_id: str, agent_name: str, action: str,
context: dict, risk_level: str = "high"
) -> ApprovalRequest:
"""Erstellt eine Freigabe-Anfrage und benachrichtigt den Reviewer."""
request = ApprovalRequest(
task_id=task_id,
agent_name=agent_name,
action=action,
context=context,
risk_level=risk_level
)
self.pending_requests.append(request)
self.notify(request)
return request
def approve(self, task_id: str, reviewer: str, feedback: str = "") -> bool:
"""Gibt eine ausstehende Anfrage frei."""
for req in self.pending_requests:
if req.task_id == task_id and req.status == ApprovalStatus.PENDING:
req.status = ApprovalStatus.APPROVED
req.reviewer = reviewer
req.feedback = feedback
return True
return False
def reject(self, task_id: str, reviewer: str, feedback: str) -> bool:
"""Lehnt eine Anfrage ab."""
for req in self.pending_requests:
if req.task_id == task_id and req.status == ApprovalStatus.PENDING:
req.status = ApprovalStatus.REJECTED
req.reviewer = reviewer
req.feedback = feedback
return True
return False
def _default_notify(self, request: ApprovalRequest):
print(f"[APPROVAL NEEDED] {request.agent_name}: {request.action}")
print(f" Risk: {request.risk_level}")
print(f" Context: {json.dumps(request.context, indent=2)}")
Escalation-Pattern
@dataclass
class EscalationRule:
condition: str # z.B. "confidence < 0.7"
threshold: float
target: str # z.B. "senior-developer", "team-lead"
message_template: str
ESCALATION_RULES = [
EscalationRule(
condition="confidence",
threshold=0.7,
target="senior-developer",
message_template=(
"Agent {agent} ist unsicher bei Aufgabe {task}. "
"Confidence: {confidence:.0%}. Bitte übernehmen."
)
),
EscalationRule(
condition="retries",
threshold=3,
target="team-lead",
message_template=(
"Agent {agent} hat Aufgabe {task} nach {retries} Versuchen "
"nicht lösen können. Menschliches Eingreifen nötig."
)
),
EscalationRule(
condition="cost",
threshold=5.0,
target="engineering-manager",
message_template=(
"Agent {agent} hat für Aufgabe {task} bereits ${cost:.2f} "
"verbraucht. Budget-Grenze erreicht."
)
),
]
Der HITL-Workflow visualisiert
Das folgende Diagramm zeigt den Workflow eines Production Agents mit Approval-Gates. Klicke auf die Checkpoints, um zu sehen, wann der Agent autonom handelt und wann menschliche Freigabe nötig ist:
Human-in-the-Loop Flow
Anwenden
Dein Agent soll automatisch Kunden-E-Mails beantworten. Welches HITL-Pattern passt am besten?
Reflektieren
Human-in-the-Loop ist kein Zeichen von Schwäche eines Agent-Systems -- es ist ein Zeichen von Reife. Die besten Production Agents sind nicht die, die alles allein machen, sondern die, die wissen, wann sie einen Menschen einbeziehen müssen. Die Kunst liegt darin, die richtige Balance zu finden: Zu viel menschliche Kontrolle macht den Agent nutzlos, zu wenig macht ihn gefährlich. Die Risiko-Reversibilitäts-Matrix aus diesem Abschnitt ist dein Werkzeug für diese Entscheidung.