Sieben Muster für Agenten-Schleifen und wann jedes davon versagt: ReAct, Maker-Checker und weitere.
Ein praktischer Katalog von Designs für Agenten-Schleifen, von Plan-Act-Verify bis hin zur menschlichen Eskalation, mit Anleitungen dazu, wann welche Methode geeignet ist, wann man sie vermeiden sollte und wie man die richtige Wahl trifft.
Quellen: Agentic Loops & Design Patterns
Niemand sollte einen Agenten danach beurteilen, wie klug er klingt. Entscheidend ist das Verhalten in Situationen mit hohem Verkehrsaufkommen, wenn etwas kaputtgeht oder ein Prüfer auftaucht. Genau hier überwiegen die Loop-Designmuster jeden einzelnen Prompt. Loops funktionieren am besten, wenn sie als architektonische Primitiven behandelt werden: Jeder von ihnen befasst sich mit einer bestimmten Problemklasse, weist bekannte Kompromisse auf und sollte bewusst gewählt werden. Die untenstehenden Muster sind mit beispielen im Stil von Claude sowie mit den Situationen versehen, in denen jedes davon vermieden werden sollte.
1. Planen, handeln, überprüfen
Das ist das grundlegende Muster. Der Agent plant einen kleinen Schritt, führt eine Aktion aus und prüft anschließend, ob diese Aktion ihn einem klar definierten Ziel nähergebracht hat. So wird ein Gleichgewicht zwischen Flexibilität und Kontrolle erreicht.
// Pseudo-code: Node/TypeScript orchestrating Claude as an agent
async function planActVerifyLoop(ticket) {
let iteration = 0;
const maxIterations = 5;
while (iteration < maxIterations) {
iteration++;
// 1. PLAN: ask Claude for the next step
const plan = await claude.chat({
model: "claude-3-opus",
messages: [
{
role: "user",
content: `You are a coding agent working on ticket ${ticket.id}.
Goal: Make tests pass for this ticket without changing public APIs.
Current context:
${ticket.description}
${ticket.latestFailureLog}
What is the single most useful next action?`
}
]
});
// 2. ACT: execute the suggested action if it's in the allowed action space
const action = parseAction(plan);
const result = await executeAction(action); // run tests, edit file, etc.
// 3. VERIFY: use tests as verification
const verification = await runTests(ticket.testSuite);
if (verification.allPassing) {
return { status: "done", iterations: iteration };
}
// Attach the failure output back into ticket context
ticket.latestFailureLog = verification.failureOutput;
}
return { status: "budget_exhausted" };
}
In der Skizze übernimmt Claude die mikroplanerische Gestaltung der nächsten Aktion, während der Schleifenmechanismus selbst die Überprüfung durch Tests vornimmt und eine Obergrenze für Iterationen festlegt. Diese Aufteilung verhindert, dass das System Erfolg meldet, nur weil das Modell selbstsicher ist.
Gute Anwendungsfallbeispiele sind mehrschrittige Ingenieursaufgaben mit messbarem Fortschritt, Rollout-Skripte sowie Konfigurationsänderungen, die in einen überprüften Funktionszustand gebracht werden müssen, sowie interne Tools, in die starke Prüfmechanismen wie Tests oder Schema-Validierung integriert werden können.
Schlechte Anwendungsfallbeispiele umfassen rein kreative Arbeiten wie Werbetexte oder längere Texte, subjektive Entscheidungen, bei denen eine Überprüfung lediglich Geschmackssache wäre, sowie Echtzeit-Prozesse, die sich mehrere Iterationen auf dem kritischen Pfad nicht leisten können.
2. ReAct (erst überlegen, dann handeln)
ReAct wechselt zwischen kurzen Gedankensprüngen und einzelnen Aktionen ab. Anstatt im Voraus den gesamten Weg zu planen, untersucht der Agent den neuesten Zustand, wählt ein Werkzeug aus, verwendet es und denkt anschließend erneut nach. Dadurch eignet es sich ideal für explorative oder diagnostische Aufgaben, bei denen jede neue Beobachtung den Plan zu Recht verändern kann.
# Pseudo-code: Python coordinator orchestrating Claude tool calls
def react_loop(incident):
iteration = 0
max_iterations = 6
while iteration < max_iterations:
iteration += 1
# REASON: Claude decides what to inspect next
reasoning = claude.chat(
model="claude-3-opus",
messages=[
{
"role": "user",
"content": f"""
You are an SRE assistant triaging a payment incident.
Incident summary:
{incident.summary}
Recent metrics:
{incident.latest_metrics}
Logs snippet:
{incident.logs_snippet}
Decide one next diagnostic action from:
- CHECK_METRICS
- CHECK_LOGS
- CHECK_DB_HEALTH
- SUMMARIZE_FINDINGS_AND_RECOMMEND_ACTION
Explain your reasoning briefly and output JSON with 'action' and 'target'.
"""
}
]
)
action = parse_json(reasoning)
if action["action"] == "SUMMARIZE_FINDINGS_AND_RECOMMEND_ACTION":
return claude.chat(... ) # final summary + recommended steps
# ACT: run the selected diagnostic
observation = run_diagnostic(action, incident)
# Update incident state for the next reasoning step
incident.update_with_observation(observation)
Jeder diagnostische Schritt ist zielgerichtet, und Claude erhält nach jeder Aktion einen aktualisierten Kontext.
Nutzen Sie es zur Diagnose von Vorfällen und zur Analyse der Ursachen, in komplexen Support-Prozessen, bei denen jede Antwort bestimmt, was als Nächstes überprüft werden muss, sowie bei Sicherheitsuntersuchungen, bei denen Beweise stückweise und unvollständig einfallen.
Vermeiden Sie dessen Einsatz, wenn der Plan stabil und der Ablauf klar ist – wie beim ETL-basierten Dokumentenverarbeitungsprozess –, wenn die Durchsatzrate so hoch ist, dass das Schritt-für-Schritt-Handeln zu aufwendig wird, oder wenn der Handlungsspielraum so eng ist, dass zusätzliche Überlegungen nichts bringen.
3. Reflektieren und überarbeiten
Hier folgen auf zwei Phasen – Erstellung und Kritik – ein Überarbeitungsschritt. Dies bietet eine sinnvolle Standardlösung für alles, was vor der Übermittlung an einen Kunden, eine Aufsichtsbehörde oder ein Produktionssystem überprüft werden muss. Der wichtige Punkt ist die Trennung: Der Kritiker kann eine weitere Anfrage sein, ein günstigeres Modell oder sogar ein Regelsystem.
async function reflectReviseLoop(draftInput: string) {
// 1. GENERATE
const draft = await claude.chat({
model: "claude-3-opus",
messages: [
{
role: "user",
content: `
Write a customer-facing email explaining a declined payment due to suspected fraud.
Constraints:
- empathetic but clear
- no admission of fault
- no promises about future approvals
Context:
${draftInput}
`
}
]
});
// 2. CRITIQUE (using a cheaper model as checker)
const critique = await claude.chat({
model: "claude-3-haiku",
messages: [
{
role: "user",
content: `
You are a compliance checker.
Review the following email for:
- policy violations
- misleading statements
- over-commitments
Output a JSON with:
- issues: list of strings
- safe: boolean
Email:
${draft.content}
`
}
]
});
const review = JSON.parse(critique.content);
if (review.safe) {
return draft.content;
}
// 3. REVISE
const revised = await claude.chat({
model: "claude-3-opus",
messages: [
{
role: "user",
content: `
You wrote this email:
${draft.content}
Compliance issues:
${review.issues.join("\n")}
Rewrite the email to resolve all issues while preserving intent.
`
}
]
});
return revised.content;
}
Dieses Muster eignet sich für Kundenmitteilungen zu sensiblen Themen wie Betrug, Rückerstattungen oder regulatorischen Änderungen, für interne Nachbesprechungen, die gegebenenfalls auditiert werden, sowie für alle Inhalte, bei denen die Einhaltung von Richtlinien Vorrang vor Stil hat.
Es eignet sich hingegen nicht für risikofreies internes Brainstorming, bei dem Kritik nur zu Verzögerungen führt und kein echter Schutz bietet, für sehr kurze Chatantworten, bei denen eine zweite Überprüfung überflüssig ist, oder für latenzkritische Abläufe wie Nachrichten während einer Transaktion, bei denen nur eine einzige Übermittlung ausreicht.
4. Entwurf, Test, Korrektur
Ingenieurteams bevorzugen oft diesen Zyklus, da das Ergebnis objektiv ist und außerhalb des Modells liegt: Die Testsuite zeigt grün an oder bleibt rot. In jeder Runde schlägt der Agent eine Änderung vor, führt die Tests durch und prüft, was fehlschlug. Anschließend behebt er die Probleme und wiederholt den Vorgang, bis das System in einem bekannten guten Zustand ist oder eine Obergrenze für die Iterationen erreicht wird.
async function draftTestFixLoop(issue: Issue) {
const maxIterations = 4;
let iteration = 0;
while (iteration < maxIterations) {
iteration++;
// DRAFT: Claude proposes code changes
const patch = await claude.chat({
model: "claude-3-opus",
messages: [
{
role: "user",
content: `
You are an autonomous coding agent.
Ticket:
${issue.title}
${issue.body}
Current failing tests:
${issue.failingTests}
Propose a minimal patch as a diff that makes tests pass
without changing public APIs.`
}
]
});
applyPatchToGitRepo(patch.content);
// TEST: run CI locally or via API
const testResult = await runCi(issue.branchName);
if (testResult.success) {
// FIX_DONE: open a PR with the diff
await openPullRequest(issue, patch.content);
return { status: "done" };
}
// FEEDBACK: update failingTests for next iteration
issue.failingTests = testResult.failureSummary;
}
return { status: "needs_human_review" };
}
Es funktioniert bei risikofreien, gut abgegrenzten Tickets, die als bereit für einen Agenten gekennzeichnet sind, bei internen Tools, bei denen ein Rollback unkompliziert ist, sowie bei nicht kritischen Abläufen, die Verzögerungen und Kosten in Kauf nehmen können.
Vermeiden Sie es bei jeglichen Änderungen, die Geld direkt über zentrale Transaktionswege leiten, bei Schema-Änderungen, Migrationsprozessen und querschnittsbezogenen Refaktorisierungen sowie bei regulierten Logiken, bei denen eine automatisierte Bearbeitung Richtlinien verletzen könnte.
5. Kritiker und Ersteller
Ein Agent erstellt die Änderung und ein anderer überprüft sie. Bei Zahlungen ähnelt dies dem bereits für hochriskante Operationen genutzten Maker-Checker-Prinzip, wodurch es einfach ist, dieses Verfahren den Risiko- und Compliance-Teams vorzustellen.
Es eignet sich überall dort, wo bereits ein zweiter Blick erwartet wird, bei der Automatisierung von systemnahen Prozessen wie Konfiguration, Routing oder Benachrichtigungen sowie bei hochrelevanten Berichten oder Dashboards, die von der Führungsebene gelesen werden.
Es eignet sich nicht für triviale Aufgaben, bei denen die zusätzliche Überprüfung teurer ist als der Schutz, für latenzempfindliche Prozesse, die sofort antworten müssen, oder für Pipelines, in denen schwache Regeln den Prüfer dazu zwingen würden, alles zu akzeptieren, was gut genug aussieht.
6. Wiederholen mit Speicherung
Die meisten naiven Schleifen versuchen einfach erneut. Eine Schleife mit Wiederholung und Speicherung protokolliert die Fehlerzustände und nutzt sie, um denselben Fehler nicht erneut zu machen.
def retry_with_memory_loop(task, max_attempts=3):
failures = []
for attempt in range(1, max_attempts + 1):
# Ask Claude to consider past failures before deciding the next move
decision = claude.chat(
model="claude-3-opus",
messages=[
{
"role": "user",
"content": f"""
You are handling a task with a flaky external API.
Task:
{task.description}
Past failures:
{failures}
Decide whether to:
- RETRY_API
- FALLBACK_TO_CACHE
- ESCALATE_TO_HUMAN
Explain briefly and output JSON: {{ "choice": "...", "reason": "..." }}
"""
}
]
)
choice = parse_json(decision)
if choice["choice"] == "RETRY_API":
result = call_api(task)
elif choice["choice"] == "FALLBACK_TO_CACHE":
result = use_cache(task)
else:
return {"status": "escalated", "failures": failures}
if result.success:
return {"status": "success", "attempts": attempt}
failures.append(result.error_summary)
return {"status": "max_attempts_exhausted", "failures": failures}
Geeignete Ziele sind instabile Integrationen, auf Geschwindigkeit beschränkte APIs sowie externe Systeme, die außerhalb Ihrer Kontrolle liegen, Dokumentenparsing mit inkonsistentem Formatierungsschema sowie nicht-kritische Workflows, in denen Wiederholungsversuche akzeptabel sind.
Nicht geeignete Fälle sind Kerntransaktionsabläufe, bei denen ein Wiederholungsversuch möglicherweise dieselben Effekte erzeugt, Operationen, die nicht idempotent sind und daher ein Wiederholungsversuch nicht sicher ist, sowie Szenarien, in denen ein Fehler unverzüglich und sichtbar auftreten muss und nicht stumm erneut versucht werden darf.
7. Menschliche Eskalation
Dies ist das Schutzkonzept für alles, was mit echtem Geld, echten Kunden oder regulatorischen Anforderungen zu tun hat. Der Prozess läuft zunächst selbstständig bis zu einem bestimmten Punkt, wird anschließend sauber weitergeleitet, sobald das Vertrauen schwindet oder das Risiko steigt.
async function triageLoop(ticket: Ticket) {
const autoActions = ["LABEL", "ROUTE_TO_QUEUE", "REQUEST_MORE_INFO"];
const decision = await claude.chat({
model: "claude-3-opus",
messages: [
{
role: "user",
content: `
You are a support triage agent in a payments company.
Ticket:
${ticket.body}
Decide one of:
- LABEL (low risk)
- ROUTE_TO_QUEUE (medium risk)
- ESCALATE_TO_HUMAN (high risk / unclear)
Return JSON with:
- choice
- risk_level
- rationale
`
}
]
});
const choice = JSON.parse(decision.content);
if (choice.choice === "ESCALATE_TO_HUMAN") {
await createHumanTask(ticket, choice.rationale);
return { status: "escalated" };
}
// LABEL or ROUTE_TO_QUEUE are automated but bounded
await applyAutomatedTriage(ticket, choice);
return { status: "auto_treated" };
}
Verwenden Sie es für jede Automatisierung, die die Kundenerfahrung oder das Wahrnehmungsniveau an Fairness beeinflussen kann, für Prozesse, bei denen teilweise Automatisierung hilft, aber vollständige Autonomie riskant ist, sowie für frühe Implementierungen, die lernen müssen, bevor die Kontrollen gelockert werden.
Lassen Sie es bei rein internen, risikofreien Aufgaben weg, bei denen Menschen lediglich Störungen verursachen würden, bei Batch-Arbeiten im Hintergrundbüro, bei denen eine menschliche Überprüfung nicht skalierbar ist, sowie in Situationen, in denen eine Eskalation die Mitarbeiter überlastet, ohne die Ergebnisse zu verbessern.
Praktische Auswahl
Wenn sich eine neue Möglichkeit für einen Agenten ergibt, ist die falsche erste Frage: „Wie soll ich diesen Prozess anstoßen?“ Vier bessere Fragen lauten:
- Welches Signal bestätigt das Ergebnis: Tests, Schemata, Regeln, Metriken oder menschliches Urteil?
- Wie viele Schritte benötigt die Aufgabe realistisch?
- Was passiert, wenn das System versagt?
- Wer wird betroffen, wenn Fehler auftreten?
Die Antworten deuten auf ein Muster hin:
- Eine starke, binäre Überprüfung legt den Schluss nahe, dass es sich um Entwurf, Test und Korrektur handelt.
- Ein explorativer Ansatz deutet auf ReAct hin.
- Bedenken hinsichtlich Richtlinien und Tonfall deuten auf Reflexion und Überarbeitung oder auf Kritik und Entwicklung hin.
- Eine instabile Umgebung erfordert einen Neversuch unter Berücksichtigung des Speichers.
- Hohes Risiko bedeutet, von Anfang an eine menschliche Eskalationsstufe einzubauen.
Loop Engineering dreht sich weniger um clevere Orchestrierung und mehr um diszipliniertes Denken über Systeme.