Harness Engineering für AI Agents: Control Loops designen
Automatische Übersetzung Dieser Artikel wurde automatisch aus der englischen Originalversion übersetzt.
Der Reasoning Loop eines Agents wählt die nächste Aktion. Sein Harness liefert Kontext, validiert vorgeschlagene Tool Calls, autorisiert sie, führt akzeptierte Calls aus, zeichnet die Ergebnisse auf und entscheidet, ob die Aufgabe abgeschlossen ist.
Für die ersten drei dieser Aufgaben gibt es bereits jeweils einen Artikel. Memory liefert den Kontext, Tool Use definiert, was vorgeschlagen werden kann, und Security entscheidet, was ausgeführt wird. Sie erschienen als separate Beiträge, weil es sich um separate Engineering-Probleme handelt. Die Entscheidung zwischen Qdrant und pgvector hat nichts mit dem Schreiben einer PreToolUse-Deny-Regel zu tun.
Sie haben jedoch einen gemeinsamen Moment: die Lücke zwischen dem Benennen einer Aktion durch das Model und ihrer Ausführung durch die Maschine. Jede Komponente beantwortet eine Frage zu dieser Lücke, und der Harness ist der Code, der sie lange genug offenhält, um alle drei Fragen zu stellen.
Für Engineers, die Coding-Agent-Harnesses entwickeln oder prüfen, besteht die verbleibende Aufgabe darin festzustellen, ob abgeschlossene Arbeit tatsächlich vollständig ist, und nachzuweisen, dass jede Control im Loop den dafür anfallenden Aufwand rechtfertigt. Part 5 behandelte den Runtime, der den Prozess im Hintergrund am Leben hält.
Über den ersten expliziten Acceptance Check hinaus ist jeder zusätzliche Retry, Handoff oder Evaluator eine Hypothese über einen beobachteten Fehler. Er verdient nur dann einen Platz, wenn ein kontrollierter Vergleich zeigt, dass er hilft.
Der einfachste Acceptance Check lässt sich für einen kleinen Research Agent wie den schreiben, den diese Serie entwickelt hat — einen LangGraph Agent, der Marktdaten abruft und einen Analystenbericht verfasst. Ein Hook außerhalb des Models validiert den Bericht gegen ein Schema und prüft, ob er tatsächlich Stock Tickers enthält; ein fehlerhafter Bericht hält den Run offen. Zwölf Zeilen gewöhnlichen Codes reichen aus, und das Model darf seine eigene Ausgabe nicht als wohlgeformt deklarieren. Das eigene Gate des Repos ist weniger strikt: Ein Evaluator mit frischem Kontext gibt eine Stimme ab, anschließend entscheidet ein Mensch. (Part 4 skizziert die deterministische Variante.)
Was dieses Beispiel nicht zeigen kann, ist der interessante Teil: Was geschieht, wenn die Evidenz mehrdeutig ist, ein Retry jemandem möglicherweise doppelte Kosten berechnet oder die Arbeit die Session überdauert, in der sie gestartet wurde? Dafür braucht es einen Task mit einer schärferen Pass/Fail-Grenze als ein Research Report. Der Research Agent bleibt das Beispiel für den Acceptance Check; für die Fälle Retry und Handoff kommt ein kleines fiktives Store-Repository hinzu. Beim Coding-Task soll der Schwellenwert für einen automatischen Rabatt von 10 % von $100 auf $75 in src/checkout.py gesenkt werden. Das Repository hat zwei erforderliche Checks:
pytest tests/test_checkout.pyüberprüft die Rabattberechnung.pnpm playwright test tests/checkout_discount.spec.tsfügt einem lokalen Test-Store einen Artikel für $80 hinzu und prüft, ob die Checkout-Seite einen Rabatt von $8 anzeigt.
Das Beispiel ist ein Lehr-Fixture, keine echte Anwendung und kein Benchmark. Jeder Versuch startet beim selben Commit und mit denselben initialisierten Testdaten. Der Harness darf die Änderung nur akzeptieren, wenn beide Commands erfolgreich sind und der Trace diese Ergebnisse mit dem getesteten Commit verknüpft.
Das Diagramm verfolgt die Änderung des Rabatts von der Planung bis zum Nachweis. Das Harness stellt die Aufgabe und die Dateien bereit, prüft die vorgeschlagenen edit_file-Argumente und Berechtigungen und führt den akzeptierten Call aus. Nachdem der Runtime die Änderung angewendet hat, führt das Harness die benannten Unit- und Browser-Acceptance-Tests aus. Ein fehlgeschlagener Befehl wird dem Model als Nachweis für einen weiteren Turn zurückgegeben; zwei erfolgreiche Befehle machen die Änderung zur Abnahme bereit.
Was das Harness verwaltet
OpenAIs Codex-Loop-Walkthrough beschreibt den grundlegenden Zyklus. Das Harness stellt einen Prompt zusammen, bittet das Model um die nächste Aktion, sendet einen akzeptierten Tool Call an den Runtime und hängt das Ergebnis an. Danach fragt es erneut. Dies wiederholt sich, bis das Harness das Ergebnis akzeptiert oder die Kontrolle an den Benutzer zurückgibt.
Implementierungen können mehrere Verantwortlichkeiten in einem Prozess zusammenfassen. Die Fehlergrenzen bleiben dennoch unterschiedlich:
| Begriff | Aufgabe | Beispiel aus einem Coding Agent |
|---|---|---|
| Model | Schlägt Text, einen Tool Call oder eine abschließende Antwort vor | Schlägt eine Änderung an src/checkout.py vor |
| Reasoning Loop | Wählt anhand des verfügbaren Kontexts den nächsten Schritt | Inspizieren, ändern, testen, erneut inspizieren |
| Harness | Stellt Kontext bereit, validiert Vorschläge, autorisiert sie, führt akzeptierte Calls aus, protokolliert Ergebnisse und prüft die Fertigstellung | Erlaubt Änderungen unter src/ und verlangt beide benannten Tests |
| Runtime | Führt akzeptierte Calls aus und hält den Zustand außerhalb des Worker-Prozesses aufrecht | Session-Log, Sandbox, Checkpoint Store, Trace Backend |
Die Runtime-Zeile umfasst vier Dinge: Session, Sandbox, Checkpoint und Trace. Alle vier speichern Zustand oder begrenzen die Ausführung. Das Model schlägt die Aktion vor, und der Reasoning Loop wählt den nächsten Schritt. Das Harness entscheidet, ob ein vorgeschlagener Call ausgeführt werden darf und ob der Nachweis zum Abschluss ausreicht. Deshalb erhält es einen eigenen Artikel. Teil 5 zählt das Harness zusammen mit diesen vier als eines von fünf Primitives, die vor dem Deployment platziert werden müssen; dieser Artikel behandelt es wieder separat.
Wenn ein Fehler auftritt, diagnostiziere die Grenze, die darauf reagieren sollte. Ein schlechter Plan erfordert möglicherweise bessere Anweisungen oder besseres Reasoning des Models. Wenn edit_file auf einen Pfad außerhalb von src/ zielt, sollte das Harness ihn ablehnen. Ein Sandbox-Prozess, der stirbt, bevor die Änderung ausgeführt wird, gehört zur Runtime; sie muss den Worker neu starten oder den Crash melden.
Wo die früheren Teile landen
Das Harness übernimmt in der obigen Tabelle den größten Teil der Arbeit; hier laufen die Teile 2, 3 und 4 zusammen. Jeder dieser Teile entscheidet eine Sache für einen einzelnen Turn:
| Früherer Teil | Was für diesen Turn entschieden wird | Wo dies im Walkthrough des nächsten Abschnitts geschieht |
|---|---|---|
| Teil 2 — Memory | Welcher frühere State in den Prompt gelangt | Schritt 1, der Context Builder |
| Teil 3 — Tool Use | Welche Aktionen verfügbar sind und wie ein validiertes Ergebnis aussieht | Argumentvalidierung in Schritt 3 sowie die Result-Form in Schritt 4 |
| Teil 4 — Security | Ob dieser konkrete Call jetzt ausgeführt werden darf | Schritt 3, die Pfadprüfung und die Approval-Entscheidung |
| Teil 6 — dieser Artikel | Ob die daraus hervorgehenden Belege den Run beenden | Schritte 5 bis 7, die Acceptance Checks und der Trace |
Teil 3 und Teil 4 teilen sich Schritt 3. Genau diese Überschneidung ist das zentrale Argument dafür, sie als ein gemeinsames Programm zu behandeln. Dieselbe Harness-Code-Schicht, die ein fehlerhaftes Argument ablehnt, lehnt auch einen Call ab, der zwar zulässig, aber noch nicht freigegeben ist. Werden diese beiden Ablehnungen auf zwei Services verteilt, driften sie auseinander: Ein Call, der an einer Stelle die Schema-Validierung besteht, wird an einer anderen Stelle autorisiert, die das Schema nie gesehen hat.
Für das Debugging bleibt die Trennung dennoch relevant: Eine Änderung an der falschen Datei ist eine Pfadregel aus Teil 4 und kein Retrieval-Problem aus Teil 2. Ein Abschnitt gegen Ende dieses Artikels überführt das in eine Routing-Tabelle.
Die Fallstudie zum Harness Engineering von OpenAI beschreibt eine bootfähige Application-Instanz für jedes Worktree. Das Team integrierte außerdem Browser Automation in die Agent-Umgebung und stellte Logs, Metriken und Traces bereit.
Eine Aufgabe wie „Kein Span in diesen vier kritischen User Journeys darf länger als zwei Sekunden dauern“ wurde testbar, weil der Agent die Application ausführen und dieselben Signale abfragen konnte, die auch ein Engineer untersuchen würde. Die Fallstudie ist produktspezifisch. Übertragbar ist die Bedingung hinter dem Ergebnis: Die Application und ihre Performance-Signale mussten innerhalb der Agent-Umgebung verfügbar sein.
Lopopolo, der Autor dieser Fallstudie, pflegt einen Praxisleitfaden für Harness Engineering. Darin benennt er die beiden Hebel, an denen dieser Artikel ansetzt: Das Model und den Coding Agent als Black Box unverändert lassen und den Context sowie die Tools darum herum entwickeln. Sein Ansatz erklärt auch, warum ein so großer Teil des Harness aus gewöhnlichem Code besteht.
Der Qualitätsmaßstab einer Organisation, ihre Verfahren, die Historie von Ausnahmen und ihre Autoritätsbeziehungen liegen außerhalb dessen, was ein General Model wissen kann. Das Harness macht sie als Repository-Instruktionen, Permission-Regeln und Acceptance Checks zugänglich. Jeder akzeptierte Run kann seine Erkenntnisse in diese Artefakte zurückführen, statt darauf zu vertrauen, dass die nächste Session sie erneut entdeckt.
Die Änderung am Rabatt von der Planung bis zur Akzeptanz verfolgen
!!! byte „Byte sagt“
Ich ließ das Modell eine Woche lang seinen eigenen Bericht bewerten, und es bestand jedes Mal. Daher muss der Evaluator außerhalb des Loops sitzen.
Für die oben definierte Rabattaufgabe schlägt das Modell vor, calculate_discount in src/checkout.py zu ändern. Bevor diese Änderung als Fortschritt zählt, passieren mehrere Dinge:
- Der Context Builder stellt die Aufgabe, Repository-Anweisungen, relevanten Dateien, vorherige Tool Results und den aktuellen Plan bereit.
- Das Modell schlägt einen
edit_file-Aufruf mit einem Pfad und Ersatztext vor. - Die Tool-Grenze (der Harness-Code zwischen Vorschlag und Ausführung) validiert die Argumente, prüft den Pfad gegen den zulässigen Bereich und fordert eine Freigabe an, wenn die Operation dies erfordert.
- Der Runtime wendet die Änderung in der Sandbox an und gibt ein strukturiertes Ergebnis zurück.
- Der Harness führt
pytest tests/test_checkout.pyund anschließendpnpm playwright test tests/checkout_discount.spec.tsaus und liest beide Exit-Codes. Der Browser-Test prüft den sichtbaren Rabatt von $8 im vorbereiteten $80-Warenkorb. - Der Harness entscheidet, was die Ergebnisse bedeuten. Ein fehlgeschlagener Check wird zum neuen Context für den nächsten Model-Turn, und ein erfolgreicher Lauf macht die Aufgabe zu einem Kandidaten für den Abschluss.
- Ein erfolgreiches Ergebnis wird erst dann zur Completion-Evidence, wenn der Harness den Befehl, den Exit-Code und die getestete Artifact-Version im Trace erfasst hat.
Nach Schritt 2 wurde noch keine Datei geändert. Der Harness kann ../../secrets.env ablehnen, für einen destruktiven Befehl eine Freigabe verlangen oder einen Lauf stoppen, der sein Budget ausgeschöpft hat. Das ist der letzte günstige Zeitpunkt dafür. Nach der Ausführung der Tests liest der Harness ihre Exit-Codes selbst. Das Modell kann seine eigene Änderung nicht als erfolgreich markieren.
Der Trace sollte den vorgeschlagenen Pfad und Ersatztext, die Berechtigungsentscheidung, die geänderten Dateien, den getesteten Commit sowie die Ergebnisse beider Befehle zeigen. Eine abschließende done-Nachricht ohne diese Einträge beweist nicht, dass diese Änderung ihre erforderlichen Checks bestanden hat.
Entscheiden, wo die einzelnen Regeln durchgesetzt werden
Die Anforderung, dass tests/checkout_discount.spec.ts erfolgreich ist, gehört in deterministischen Code und nicht in den Prompt. Der Harness dispatcht den Playwright-Befehl an den Runtime, liest dessen Exit-Code und verweigert das Beenden des Laufs, solange der Test fehlschlägt. Ein Prompt kann das Modell daran erinnern, den Test auszuführen. Er kann jedoch nicht verhindern, dass das Modell ohne Nachweis Erfolg meldet.
Andere Regeln gehören in andere Layer:
| Regel platzieren in | Geeignet für | Beispiel |
|---|---|---|
| Prompt oder Skill | Suchreihenfolge, Coding-Konventionen und Planformat | Vor Änderungen am Checkout-Code AGENTS.md lesen |
| Tool-Grenze | Argumentvalidierung, zulässige Pfade, Freigaben und Tool-Zugriff | Schreibzugriffe nur unter src/ erlauben |
| Deterministischer Code | Budgets, Timeouts, Retries, Test-Exit-Codes und Release-Gates | Den Lauf offen halten, solange der Playwright-Test fehlschlägt |
| Evaluator mit frischem Context | Visuelle Prüfung oder Kriterien, die menschenähnliches Urteilsvermögen erfordern | Ein generiertes Diagramm mit einer schriftlichen Bewertungsrichtlinie vergleichen |
Tool Contracts trennen Vorschlag und Berechtigung
Für die Discount-Aufgabe sind nur Dateiänderungen und Testbefehle erforderlich. Eine API mit Zustandsänderungen hat einen anderen Fehlermodus; wechseln wir daher für diesen Abschnitt die Beispiele. Angenommen, der Agent kann beim Einrichten von Testdaten create_test_order gegen einen Staging-Order-Service aufrufen. Dieses Tool gehört nicht zu den Akzeptanzprüfungen der Discount-Aufgabe. Hier ist es nützlich, weil ein Timeout verschleiern kann, ob der Service eine Bestellung angelegt hat.
Die Tool-Grenze benötigt mehr als eine Beschreibung in natürlicher Sprache. Sie benötigt einen expliziten Tool Contract. Teil 3 hat einen solchen aus Sicht des Models gefordert: klare Aktionen, kompakte Rückmeldungen und behebbare Fehler. Das Harness benötigt denselben Contract aus einem anderen Grund. Es muss ohne Rückfrage beim Model entscheiden, ob ein Call ausgeführt werden darf und ob ein fehlgeschlagener Call wiederholt werden darf. Für create_test_order bedeutet das einen Contract mit:
- validierten Argumenten, damit fehlerhafte Eingaben vor der Ausführung abgewiesen werden
- einem strukturierten Ergebnis wie
{ "order_id": "123", "created": true }, damit spätere Prüfungen keinen Freitext parsen müssen - einer Effektkategorie, die festhält, ob der Call nur Informationen abruft oder eine Datei, einen Datenbankeintrag oder einen externen Service verändert. Sie hält außerdem fest, ob eine Wiederholung des Calls sicher ist. Dieses Label teilt dem Harness mit, ob ein automatischer Retry Arbeit duplizieren könnte. Das Harness kann
get_order_statuswiederholen, wenn der Service diese Abfrage als schreibgeschützt definiert.create_test_orderdarf es nicht blind wiederholen, weil der erste Call die Bestellung möglicherweise bereits angelegt hat - einer Timeout- und Retry-Policy, damit eine verlorene Antwort keine unbegrenzte Folge von Calls auslöst
- einer Berechtigungsregel, die festlegt, welche Genehmigung erforderlich ist. Das Lesen des Bestellstatus kann automatisch erfolgen, während das Anlegen einer Bestellung eine Bestätigung erfordern kann
Die Beschreibung in natürlicher Sprache ist Text, der dem Model angezeigt wird. Sie könnte lauten: „Erstelle eine Testbestellung zur Verifizierung des Checkouts.“ Dieser Satz hilft dem Model zu entscheiden, wann es create_test_order vorschlagen sollte. Er autorisiert den Call jedoch nicht. In diesem Beispiel validiert der Model Context Protocol (MCP)-Client des Harness die Argumente, wendet seine eigenen Regeln an und prüft Serververtrauen, Genehmigungsanforderungen sowie Retry-Sicherheit, bevor überhaupt etwas dispatcht wird. Diese Prüfung entspricht der geordneten Deny/Ask/Hook/Allow-Leiter aus Teil 4, ergänzt um eine Frage: ob ein Call, der bereits fehlgeschlagen ist, erneut gesendet werden darf.
Ein MCP-Server veröffentlicht Tool-Beschreibungen und optionale Verhaltensannotationen für den Client. Ein fehlerhafter oder bösartiger Server könnte ein Tool mit Zustandsänderungen als harmlos beschreiben. Ein Client, der diese Angabe automatisch akzeptiert, könnte create_test_order ohne Genehmigung ausführen oder wiederholen und dadurch ein Duplikat anlegen. Die MCP-Spezifikation verlangt daher, dass Clients Tool-Annotationen als nicht vertrauenswürdig behandeln, sofern der Server selbst nicht vertrauenswürdig ist.
Die Spezifikation schreibt keine universelle Trust-Einstellung vor. Daher benötigen Sie für Ihre Deployment-Umgebung eine explizite Trust-Policy; ein Server kann seine eigenen Annotationen nicht vertrauenswürdig machen. Diese Policy entscheidet, welche Metadaten Berechtigungs- oder Retry-Entscheidungen beeinflussen dürfen und welche Annotationen lediglich beratenden Charakter haben.
Für einen zustandsändernden Aufruf ist beim Wiederholen ein Replay-Schutz erforderlich
Teil 5 versieht jeden Tool Call mit Seiteneffekten mit einem Idempotency Key. Der Harness entscheidet, wann dieser Key relevant wird. create_test_order erstellt die Bestellung, aber die HTTP-Antwort geht verloren. Der Harness sieht einen Timeout und kann nicht feststellen, ob der Server die Anfrage abgeschlossen hat. Eine Wiederholung des Aufrufs könnte eine zweite Bestellung erstellen.
Eine Statusabfrage kann wiederholt werden, wenn der Service sie als schreibgeschützt definiert. Ein Erstellungsaufruf benötigt den Key: Der Client fügt eine eindeutige Request-ID hinzu, und der Service gibt beim erneuten Auftreten dieser ID das erste Ergebnis zurück, anstatt eine weitere Bestellung zu erstellen. Ohne diesen Schutz sollte der Harness prüfen, ob die Bestellung bereits existiert, oder vor einem weiteren Versuch eine Entscheidung durch einen Menschen einholen. AWS dokumentiert dieses Muster in seiner Anleitung zu idempotenten APIs.
Für die Abnahme sind unabhängige Nachweise erforderlich
Eine erfolgreiche Antwort von create_test_order bestätigt lediglich, dass das Tool Daten zurückgegeben hat. Sie beweist nicht, dass eine Coding-Aufgabe ihre Tests bestanden hat. Wenn ein späterer Browser-Test von der vorgemerkten Bestellung abhängt, muss der Harness das Response-Schema validieren und diesen Test trotzdem ausführen, bevor er die Codeänderung akzeptiert.
Manche Kriterien lassen sich nicht auf einen Exit-Code reduzieren. Bei einer separaten Aufgabe zum visuellen Design kann ein Evaluator mit frischem Kontext eine gerenderte Seite oder ein Diagramm mit einer schriftlich formulierten Bewertungsrichtlinie vergleichen — „frischer Kontext“ bedeutet hier eine zweite Model-Session, die ohne Verlauf des Runs startet und die erzeugten Artefakte statt des Transkripts liest. Vergleiche diesen Evaluator mit menschlichen Reviews, bevor du ihn als Gate für den Abschluss einsetzt.
Eine Migration des Payment-Adapters benötigt eine Übergabe
Wechsle erneut die Aufgabe, bleibe aber im fiktiven Store-Repository. Der Agent muss den Checkout nun von Payment Adapter v1 auf v2 migrieren. Die Arbeit umfasst den Checkout-Handler, den Payment Client, die Konfiguration und die Tests und kann daher länger dauern als eine Model-Session — eine zusammenhängende Phase des Model-Kontexts, die durch einen Neustart oder einen bewusst begonnenen neuen Start beendet wird, statt fortgeführt zu werden.
Bevor die erste Session ihr Context Limit erreicht, hat sie mehrere Dateien geändert, eine lokale Payment Sandbox gestartet und tests/payment_migration.spec.ts fehlschlagen lassen. Dieser Browser-Acceptance-Test führt eine Zahlung über Adapter v2 vollständig aus und verifiziert die aufgezeichnete Provider-ID. Eine Zusammenfassung der Konversation kann die nächste Model-Session orientieren, aber sie kann die Sandbox nicht neu starten und nicht nachweisen, welche Dateien aktuell geändert sind.
Die nächste Session muss drei Dinge wiederherstellen:
| Was wiederhergestellt werden muss | Was darin enthalten ist | Wie es fehlschlagen kann |
|---|---|---|
| Konversationsverlauf | Nachrichten, Tool Calls und zurückgegebene Ergebnisse | Alte Details verdrängen die aktuelle Aufgabe |
| Arbeitsumgebung | Dateien, Payment Sandbox und Browser-Teststatus | Das Transkript behauptet, ein Service laufe, obwohl er beendet wurde |
| Aufgabenfortschritt | Plan, abgeschlossene Prüfungen, ausstehende Freigabe, nächste Aktion | Die nächste Session wiederholt bereits abgeschlossene Arbeiten |
Compaction ersetzt ältere Nachrichten durch eine kürzere Zusammenfassung, damit die aktuelle Session fortgesetzt werden kann. Ein Progress-Handoff hält fest, was die nächste Session benötigt: den aktuellen Branch, geänderte Dateien, den letzten Test-Befehl samt Ausgabe sowie den nächsten noch offenen Schritt.
Eine Handoff-Datei ist Document Memory, die für einen Leser — die nächste Model-Session — geschrieben wird. Sie ist ein anderes Artefakt als der Checkpoint, den die Runtime wiederherstellt. Der Checkpoint beantwortet, wo die Ausführung angehalten wurde. Der Handoff beantwortet, was die Arbeit bedeutet und was noch aussteht. Wird ein Checkpoint ohne Handoff wiederhergestellt, erhält die nächste Session einen fortsetzbaren Prozess, aber keine Information darüber, welchen der vier bearbeiteten Bereiche — Handler, Client, Konfiguration oder Tests — sie bereits abgeschlossen hat. Genau dadurch entsteht doppelte Arbeit.
Wenn die alte Konversation veraltete Annahmen enthält, kann das Harness eine frische Model-Session mit diesem Handoff und dem aktuellen Workspace starten. Das Ersetzen eines abgestürzten Workers und das Wiederherstellen seiner Prozesse ist eine separate Aufgabe der Runtime-Recovery.
Eine kleine Dokumentationsänderung benötigt möglicherweise keinen dieser Mechanismen. Für die Payment-Migration ist ein Handoff erforderlich, sobald sich die Arbeit über mehrere Sessions erstreckt, da die nächste Model-Session sowohl den Workspace als auch den Aufgabenstatus rekonstruieren muss.
Anthropics Experimente mit Long-Running Coding Agents nutzten die Git-Historie und eine Progress-Datei zwischen Sessions. Der spätere Harness-Design-Report von Anthropic trennt Compaction von einem Handoff in einen frischen Kontext und berichtet, dass Handoffs zusätzliche Orchestration, Token-Nutzung und Wall-Clock-Zeit verursachen, ohne Zahlen zu veröffentlichen, die einen dieser Overheads dem Handoff selbst zuordnen.
Mit Traces drei Fehlerarten unterscheiden
Die folgenden drei Zeilen sind illustrative Trace-Skizzen, keine gemessenen Runs und keine Ausgaben aus dem begleitenden Lab. Jede Zeile zeigt einen anderen Fehler und daher eine andere Reaktion des Harness.
| Was der Trace aufzeichnet | Was passiert ist | Korrekte Reaktion |
|---|---|---|
Der schreibgeschützte get_order_status-Call gibt 503 zurück; kein zustandsändernder Call läuft | Eine vorübergehende Abfrage ist fehlgeschlagen | Die Abfrage mit Begrenzung und Backoff wiederholen |
create_test_order läuft in einen Timeout, anschließend findet eine Statusabfrage die Bestellung 123 unter dem Idempotency Key checkout-42 | Der Service hat die Bestellung angelegt, aber die Antwort ging verloren | Die bestehende Bestellung zurückgeben; keine weitere anlegen |
Die Änderung und der Unit-Test sind erfolgreich, aber der Trace enthält für tests/checkout_discount.spec.ts im getesteten Commit kein Ergebnis | Erforderliche Akzeptanz-Evidenz fehlt | Den Run offen halten und den Browser-Akzeptanztest dispatchen |
Ein vorübergehend wirkender Fehler macht nicht jeden Aufruf sicher wiederholbar. Die erste Zeile enthält eine schreibgeschützte Abfrage. Die zweite Zeile ist eine zustandsverändernde Anfrage; daher entscheiden der Idempotency Key und der serverseitige Status, ob ein weiterer Erstellungsversuch zulässig ist. Die dritte Zeile ist überhaupt kein Tool-Fehler; das Harness hat die erforderlichen Nachweise für die Annahme der Rabattänderung noch nicht erfasst.
Ein Chat-Transkript hält fest, was das Model gesehen hat. Es kann nicht beweisen, ob der Order-Service eine Anfrage verarbeitet hatte, bevor die Antwort verloren ging. Das Transkript ist der Bericht des Agents über die Ereignisse; der Trace zeigt, was die Maschine tatsächlich getan hat. Wenn beide voneinander abweichen, ist dem Trace zu vertrauen. Der Trace muss den Client-Aufruf, die Approval-Entscheidung, den Idempotency Key, das Server-Ergebnis oder die Statusabfrage, den getesteten Commit und das Ergebnis des Acceptance-Tests verknüpfen. Anhand dieser Felder erkennt das Harness, welcher der drei Pfade aktiv ist.
| Wiederkehrendes Symptom | Kleine Änderung zum Ausprobieren | Zu messender Wert |
|---|---|---|
| Schreibgeschützte Abfragen schlagen vorübergehend fehl | Begrenztes Retry mit Backoff | Recovery Rate, zusätzliche Aufrufe, Wall Time |
| Fortgesetzte Sessions wiederholen abgeschlossene Arbeit | Strukturiertes Progress-Handoff | Doppelte Tool-Aktionen nach dem Fortsetzen |
| Beim Abschluss fehlen erforderliche Tests | Fail-Closed-Acceptance-Gate | Ohne alle erforderlichen Checks akzeptierte Tasks |
| Visuelle Fehler überstehen deterministische Checks | Evaluator mit frischem Context und Rubrik | Gefundene Fehler, falsche Ablehnungen, Review-Zeit |
| Der Agent bearbeitet Bereiche außerhalb seines Scopes | Engere Tool-Berechtigung | Blockierte Aufrufe und manuelle Overrides |
| Abgerufene Memory verdrängt die aktuelle Aufgabe | Anzahl abgerufener Fakten begrenzen; vor dem Injizieren ranken | Für Recall ausgegebene Tokens, abgeschlossene Tasks, Kosten pro Task |
Bevor du eine Komponente hinzufügst, benenne den wiederkehrenden Fehler, den sie reduzieren soll, und die Kennzahl, die du verfolgen wirst. Entferne die Komponente, wenn ein kontrollierter Vergleich diese Kennzahl nicht ausreichend verbessert, um ihre Kosten zu rechtfertigen. Die meisten Harnesses, die ich gesehen habe, wachsen anders: Jemand stößt auf einen fehlerhaften Run, fügt einen Guard hinzu, und der Guard bleibt für immer bestehen, weil niemand beweisen kann, dass er gefahrlos gelöscht werden kann. So entsteht ein Loop, den niemand anfassen möchte.
Diese wiederkehrenden Fehler in eine versionierte Regression Suite zu überführen, ist eine eigene Aufgabe. Ich habe das separat in AI Agent Evaluation in Production beschrieben.
Eine Änderung nach der anderen messen
Ein Ablation misst, ob eine Harness-Komponente den erwarteten Effekt verursacht, indem diese Komponente geändert oder entfernt wird, während der Rest des Experiments unverändert bleibt. Hilft beispielsweise Editor-Linting diesem Model bei dieser Task Suite?
Verwende das folgende Protokoll:
- Frieren Sie die Model-Version, die Task-Instanzen, die Umgebung, den Grader und die Prompts außerhalb der zu testenden Komponente ein.
- Geben Sie beiden Varianten dasselbe Gesamtbudget für Tokens, Zeit und Kosten.
- Legen Sie die Anzahl der Trials oder die Abbruchregel fest, bevor Sie den Vergleich durchführen.
- Führen Sie in beiden Varianten dieselben Task-Instanzen aus. Da Model-Outputs variieren, wiederholen Sie jeden Task mehrere Male.
- Berichten Sie den Mittelwert zusammen mit der Streuung oder einem Konfidenzintervall.
- Zählen Sie jeden gestarteten Trial, einschließlich Timeouts, Policy-Stopps, Harness-Crashes und Fehlern des Evaluators.
Die Erfolgsrate allein kann eine teure Komponente verbergen. Erfassen Sie mindestens als abgeschlossen akzeptierte fehlerhafte Tasks, Kosten und Wall Time pro abgeschlossenem Task, Tool-Fehler, doppelte Bestellungen, Review-Minuten und manuelle Permission-Overrides. Wählen Sie die Metrik, die für Ihr Produkt die tatsächlichen Kosten abbildet. Ein Anstieg der abgeschlossenen Tasks um zwei Prozentpunkte ist ein schlechter Trade-off, wenn sich dadurch Ihre Review-Warteschlange verdoppelt.
Ein gepaartes Experiment zur Migration von Zahlungsdaten macht die Übergabe des Fortschritts messbar. Jedes Control-/Treatment-Paar startet mit demselben Repository-Commit und demselben gesetzten Checkpoint sowie mit demselben Model, Task, Grader und Gesamtbudget. Die Übergabe ist der einzige Schalter. Die primäre Metrik zählt doppelte Tool-Aktionen nach dem Resume: Eine Aktion ist doppelt, wenn ihre Operation und ihr Artefakt mit einem Schritt übereinstimmen, den die vorherige Session bereits abgeschlossen hatte.
Das SWE-agent-Paper verwendet GPT-4 Turbo unverändert auf dem 300-Task-Split SWE-bench Lite und berichtet mit seinem vollständigen Interface 18,0 % gelöste Tasks, verglichen mit 11,0 % für einen Shell-only-Agent mit einer ausgearbeiteten Demonstration und 7,3 % für denselben Agent ohne Demonstration. Die im Paper hervorgehobene Lücke von 10,7 Prozentpunkten wird gegenüber der 7,3-%-Baseline gemessen; Teil 3 leitet dieselben drei Zahlen aus der Perspektive des Interface-Designs her. Das Paper änderte außerdem einzelne Interface-Features:
| Interface-Änderung | Gelöst |
|---|---|
| Vollständiges SWE-agent-Interface (Referenz, unverändert) | 18,0 % |
| Editor ohne Linting | 15,0 % |
| Vollständige Datei statt eines Viewers mit 100 Zeilen | 12,7 % |
| Vollständige Observation-History statt der letzten fünf | 15,0 % |
Diese Zahlen gelten für jenes Model, jenen Benchmark und das $4-Limit pro Task. Die drei Zeilen unterhalb der Referenz sind die aussagekräftigen One-Feature-Tests: In jedem Fall wurde ein Interface-Feature geändert, während Model und Evaluations-Setup unverändert blieben.
LangChain veröffentlichte einen umfassenderen Fixed-Model-Vergleich für deepagents-cli. Darin wird ein Anstieg bei Terminal-Bench 2.0 von 52,8 % auf 66,5 % berichtet, wobei gpt-5.2-codex unverändert blieb, während das Team den System Prompt, die Tools und die Middleware änderte. Der Post bündelt mehrere Änderungen und enthält weder ein Konfidenzintervall noch einen Vergleich mit einem fixierten Gesamtbudget oder eine Ablation-Tabelle pro Änderung. Dieses Ergebnis kann daher nicht bestimmen, welche Änderung geholfen hat. Die Model-Namen in diesem Abschnitt entsprechen den Models, die die jeweilige Studie zum Zeitpunkt ihrer Durchführung fixiert hatte; übertragbar ist das Protokoll, nicht die Liste der Models.
Anthropics Bericht zu Long-Running Applications ist eine qualitative, produktspezifische Fallstudie und kein kontrollierter Benchmark. Bei der Anwendung handelt es sich um RetroForge, einen 2D-Retro-Game-Maker. In Sprint 3 prüfte der Harness-Evaluator 27 Kriterien für dessen Level-Editor. Die Arbeit begann mit früheren Opus-Modellen. Nach dem Release von Opus 4.6 entfernte das Team die Harness-Komponenten nacheinander, um festzustellen, welche durch das neuere Modell redundant geworden waren. Dem Bericht zufolge wurden Evaluator-Aufrufe bei Aufgaben zum Overhead, die Opus 4.6 allein zuverlässig erledigen konnte, halfen aber weiterhin nahe an der Leistungsgrenze des Modells. Das Beispiel ist ein Anlass, alte Scaffolding-Komponenten bei einem Modellwechsel erneut zu validieren; es schätzt keinen allgemeinen Effect Size.
Das Harness editierbar halten, nachdem es sich bewährt hat
Ablation hält ein Harness klein, doch sein Code kann das Modell überdauern, für das er optimiert wurde. Eine Anforderung wie „Secrets in jedem Capture-Pfad maskieren“ beschreibt ein Verhalten, keine Datei. In einem Production-Harness kann sich dieses Verhalten über mehrere Ausführungsstufen und gemeinsam genutzten State erstrecken. Bevor du es sicher ändern kannst, musst du jede Implementierungsstelle finden — und das gilt auch für den Coding Agent, an den du die Aufgabe delegierst.
Ein Preprint von Wang et al. aus dem Jahr 2026, das Harness Handbook, bezeichnet diese Suche als Behavior Localization. Das Handbook erstellt eine verhaltensorientierte Karte der Harness-Codebasis. Eine statische Analyse, die keine Model-Aufrufe benötigt, extrahiert einen Programmgraphen. Anschließend organisiert ein LLM dessen Einheiten in Ausführungsstufen.
Der Maintainer oder Coding Agent beginnt mit einer Systemübersicht, öffnet die relevante Ausführungsstufe und steigt zu quellcodebasierten Einträgen für eine Funktion oder Datei hinab. Ein State Register hält fest, wo Shared State zwischen den Stufen geschrieben und gelesen wird. Diese Hierarchie hält die Übersicht klein und bewahrt zugleich einen Pfad bis zum Quellcode.
Aktualität ist eine separate Regel. Jeder Locator muss sich gegen das Live-Repository auflösen lassen. Das Handbook friert veraltete Einträge ein, statt zu raten, und jeder nichtleere Diff synchronisiert die davon betroffenen Einträge erneut.
Das Diagramm komprimiert den Modification Loop: Eine reine Verhaltensanforderung durchläuft die Ebenen des Handbooks, jeder potenzielle Locator wird vor dem Schreiben des Plans gegen das Live-Repository verifiziert, und jeder angewendete Diff synchronisiert die Map erneut.
Die Handbook-Evaluation folgt dem in diesem Artikel beschriebenen Protokoll. Sie umfasst zwei Open-Source-Harnesses: Terminus-2 (sechs Python-Dateien) und das Codex-Monorepo (2.267 Rust-Dateien). In beiden Fällen erkundete ein Read-only-Planner auf Basis von DeepSeek-V4-Pro entweder das Repository direkt oder nutzte das Handbook als Routing-Schicht. Requests, Repository, Tool-Berechtigungen und Decoding waren in beiden Varianten identisch. Drei Judges (GPT-5.5, Opus 4.8, DeepSeek-V4-Pro) bewerteten jeden Edit-Plan anhand von Localization, Scope Control und Reasoning — dabei ist zu beachten, dass einer der Judges dasselbe Modell ist, das die Pläne erstellt hat:
| Harness | Baseline-Siegrate | Mit Handbook-Unterstützung | Planner-Tokens |
|---|---|---|---|
| Terminus-2 (6 Dateien) | 26,7 % | 45,6 % | −8,6 % |
| Codex-Monorepo (2.267 Dateien) | 28,3 % | 38,3 % | −12,7 % |
Der mit dem Handbook unterstützte Planner gewann in beiden Repositories häufiger und verwendete weniger Planner-Tokens. Die Bedingungen bleiben an dieses Ergebnis geknüpft: Drei LLM-Judges bewerteten Edit-Plans, die von einem Planner-Modell auf zwei Harnesses erstellt wurden. Die Studie bewertete Pläne, nicht ausgeführte Diffs oder Fehlerraten in der Produktion.
Methode im begleitenden Lab ausprobieren
Das harness-demo-Projekt bei Commit 517353f3 ist eine kleine, deterministische Übung mit zwölf generischen synthetischen Tasks, die Codeänderungen wie fix-parser-edge-case, split-large-module und wire-browser-test abdecken. Das fiktive Store-Repository wird darin nicht implementiert.
Jedes Task-Fixture definiert einen Schwierigkeitsgrad sowie vier boolesche Bedingungen: ein flakiges Tool, verlorenen Fortschritt, eine übersehene Implementierungslücke und einen mehrdeutigen Abschluss. Der Simulator leitet für schwierige Tasks, die außerdem eine Progress-Datei benötigen, eine fünfte Bedingung ab: Ohne context_reset bewahrt die Komprimierung veraltete Annahmen. Ein deterministischer Grader markiert einen Task nur dann als bestanden, wenn die ausgewählte Konfiguration jede zutreffende Bedingung behandelt. Es wird kein Model und kein externer Service ausgeführt.
Die Befehle beantworten unterschiedliche Fragen:
make checkführt Ruff und sieben Unit-Tests aus, einschließlich des Validators, der jedes Ablation-Paar ablehnt, das mehr als eine Komponente ändert.make rungibt zunächst eine kumulative Teaching-Matrix und anschließend fünf gültige Leave-One-Component-Out-Vergleiche aus.make failuresnennt für jeden fehlgeschlagenen Task die nicht behandelte Bedingung. Das vollständige Harness sollte mitall synthetic tasks passenden.
make check
make run
make failures
Der kausale Abschnitt von make run sieht so aus:
component control treatment delta
retry_policy 8/12 12/12 +4
progress_handoff 7/12 12/12 +5
evaluator 8/12 12/12 +4
fail_closed_acceptance 7/12 12/12 +5
context_reset 10/12 12/12 +2
Für jede Zeile ist der Control die vollständige Konfiguration abzüglich einer Komponente; der Treatment stellt ausschließlich diese Komponente wieder her. Die frühere kumulative Matrix ist zur Orientierung nützlich, aber einige ihrer benachbarten Zeilen fügen mehrere Komponenten gleichzeitig hinzu und können daher keine Ursache identifizieren.
Das Lab validiert jedes deklarierte Paar, bevor es ausgeführt wird. Seine Regressionstests enthalten außerdem absichtlich ein ungültiges Paar, das Retry-Policy und Evaluator gleichzeitig ändert; der Validator weist es zurück.
Das Lab vergleicht bei der Validierung eines Paars alle fünf Komponentenfelder. Dieser ausführbare Ausschnitt zeigt dieselbe Absicherung anhand eines gültigen Progress-Handoff-Paars:
from dataclasses import dataclass, fields
@dataclass(frozen=True)
class Config:
progress_handoff: bool = False
evaluator: bool = False
retry_policy: bool = False
fail_closed_acceptance: bool = False
context_reset: bool = False
def changed_components(control: Config, treatment: Config) -> tuple[str, ...]:
return tuple(
field.name
for field in fields(control)
if getattr(control, field.name) != getattr(treatment, field.name)
)
control = Config(progress_handoff=False, evaluator=True, retry_policy=True)
treatment = Config(progress_handoff=True, evaluator=True, retry_policy=True)
assert changed_components(control, treatment) == ("progress_handoff",)
Welche Schicht öffnen, wenn ein Run fehlschlägt
Die Serie verlief von innen nach außen, und an dieser Stelle zahlt sich diese Reihenfolge aus. Bei einem fehlschlagenden Agent Run gibt es in der Regel genau einen Verantwortlichen:
| Was der Run getan hat | Wo der Fix liegt | Teil |
|---|---|---|
| Trotz der bereits verfügbaren richtigen Informationen den nächsten Schritt schlecht gewählt | Reasoning Loop oder Model | 1 |
| Arbeit wiederholt oder eine vor einer Stunde getroffene Entscheidung verloren | Context Assembly und Handoffs | 2 |
| Die erforderliche Aktion nicht ausdrücken oder ein zurückgegebenes Ergebnis falsch interpretieren können | Tool Contract | 3 |
| Etwas getan, das überhaupt nie möglich sein sollte | Permission Rules | 4 |
| Beim Tod eines Workers während eines Calls alles verloren | Session, Checkpoint, Sandbox | 5 |
| Erfolg für eine nicht erledigte Arbeit gemeldet | Acceptance Checks und Traces | 6 |
Vier dieser sechs Zeilen betreffen Harness-Code. Zeile 5 ist die zugrunde liegende Runtime, und Zeile 1 ist die einzige, die ein Prompt noch beeinflussen kann.
Mit einem Loop und einem Acceptance Check beginnen
Ich würde ein Coding-Agent-Harness mit einem leistungsfähigen Model, Repository-Anweisungen, einigen eng gefassten Tools, einer Sandbox und einem expliziten Acceptance Test starten. Ich würde Tool Calls, Tool Results, Kosten und diesen abschließenden Test in einem Trace erfassen, damit die ersten nützlichen Fehler sichtbar werden, ohne sie aus Terminal-Logs und Chat-Transkripten rekonstruieren zu müssen. Das ist eine vorgeschlagene Baseline, kein Nachweis aus einem produktiv eingesetzten System.
Füge anschließend nur hinzu, was ein Trace rechtfertigt. Halte fest, wer die jeweilige Komponente pflegt, wie viele Tokens oder Sekunden sie hinzufügt und welcher Regression Test nach einem Model-Upgrade ihre Entfernung rechtfertigen würde.
Sechs Monate später sollte jemand, der progress_handoff=True sieht, die fehlgeschlagenen Traces finden können, die diese Komponente gerechtfertigt haben, ebenso wie die Regression Cases, die sie weiterhin erforderlich machen. Die Traces erklären, warum die Komponente existiert; eine aktuelle Behavior Map erklärt, wo Änderungen vorgenommen werden müssen.
Wenn du über eine Suche hierher gelangt bist, haben die fünf vorhergehenden Artikel ein System rund um einen Reasoning Loop aufgebaut:
- Der Loop wählt den nächsten Schritt.
- Die Memory liefert den Kontext, und ein echter Postgres Checkpoint Store bewahrt ihn.
- Tool Contracts definieren Aktionen und die Result Shapes, die spätere Checks auswerten können.
- Security ergänzt den Deny Hook und den Stop-Hook Validator. Beide bleiben im Beispiel Skizzen, markieren aber die Control Points.
- Die Runtime hält den Prozess über Sessions und Fehler hinweg am Leben.
Die Serie hat außerdem einen MCP Sidecar ergänzt, um zu zeigen, wo Tokens von Data Providern hingehören, sowie einen Evaluator Node, der den Draft Report prüft, bevor ihn ein Mensch sieht. Das sind gewöhnliche Code-Komponenten rund um einen Model Call. Der Router ist aus demselben Grund Harness-Code: Er wählt das Reasoning Pattern, bevor der Reasoning Loop startet.
Dein nächster Schritt besteht darin, einen kleinen Loop zu instrumentieren. Erfasse Tool Calls, Tool Results, Kosten und einen expliziten Acceptance Test. Füge eine Control erst hinzu, wenn ein Trace den Fehler zeigt, den sie beheben soll. Vergleiche sie mit einer festen Control und entferne sie, sobald der gemessene Nutzen verschwindet.
Referenzen
- OpenAI, Unrolling the Codex agent loop.
- OpenAI, Harness engineering: leveraging Codex in an agent-first world.
- Lopopolo, Harness engineering: anthology, field guide, and agent context bundle.
- Anthropic Engineering, Effective harnesses for long-running agents.
- Anthropic Engineering, Harness design for long-running application development.
- LangChain, Improving Deep Agents with harness engineering.
- Yang et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering.
- Wang et al., Harness Handbook: Making Evolving Agent Harnesses Readable, Navigable, and Editable, arXiv:2607.13285, 2026.
- AWS, Making retries safe with idempotent APIs.
- Model Context Protocol, Tools specification.
- Market Analyst Agent Repository
Der Code des Market Analyst Agent befindet sich auf GitHub.