Engineering the Agentic Stack · Deel 6

Harness Engineering voor AI agents: control loops ontwerpen

Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.

Artikelupdate

Oorspronkelijk gepubliceerd op 22 juli 2026. Gereviewd en bijgewerkt op 6 september 2026. De update voegt nieuwere evidence uit harness benchmarks en gevallen van provider-interventie toe en verduidelijkt wat de gerapporteerde resultaten aantonen.

Een agent kan zijn beurt beëindigen terwijl het werk nog niet af is. Voor een coding agent zijn het gewijzigde artifact en de vereiste testresultaten de nuttige evidence. Een eindbericht met “klaar” bewijst geen van beide.

De harness is de control code rond de reasoning loop. Deze levert context, valideert en autoriseert tool calls, legt resultaten vast en bepaalt of de evidence voldoende is om het werk te accepteren. De runtime houdt daaronder de uitvoering en state actief.

Bij het reviewen van een harness zou ik twee vragen stellen: wat voorkomt dat de harness incompleet werk accepteert, en welke failures rechtvaardigen de toegevoegde controls? Dit artikel behandelt acceptance checks, retries en handoffs en laat vervolgens zien hoe je een control vergelijkt met een vaste baseline. De store-voorbeelden zijn fictief; het companion lab is een deterministische simulatie en geen meting van een live agent.

De eenvoudigste acceptance check is makkelijk te schrijven voor een kleine research agent zoals die waarmee deze serie is begonnen — een LangGraph agent die marktdata ophaalt en een analyst report schrijft. Een hook buiten het model valideert het rapport tegen een schema en controleert of het daadwerkelijk stock tickers bevat; een malformed report houdt de run open. Twaalf regels gewone code, en het model mag zijn eigen output niet als well-formed verklaren. De repo gebruikt een zachtere check: een fresh-context evaluator brengt een stem uit, waarna een mens het resultaat reviewt. (Part 4 schetst de deterministische versie.)

Wat dit voorbeeld niet laat zien, is het interessante deel: wat er gebeurt wanneer de evidence ambigu is, wanneer een retry iemand dubbel zou kunnen belasten, of wanneer het werk langer duurt dan de session waarin het is gestart. Daarvoor is een task nodig met een scherpere pass/fail-grens dan een research report heeft. De research agent blijft het voorbeeld voor de acceptance check; een kleine fictieve store-repository wordt toegevoegd voor de retry- en handoff-cases. De coding task is het verlagen van de drempel voor een automatische korting van 10% van $100 naar $75 in src/checkout.py. De repository heeft twee vereiste checks:

  • pytest tests/test_checkout.py verifieert de kortingsberekening.
  • pnpm playwright test tests/checkout_discount.spec.ts voegt een item van $80 toe aan een lokale test store en controleert of de checkoutpagina een korting van $8 toont.

Het voorbeeld is een teaching fixture, geen echte applicatie of benchmark. Elke poging start vanaf dezelfde commit en met dezelfde seeded testdata. De harness mag de wijziging alleen accepteren wanneer beide commando’s slagen en een durable acceptance record beide resultaten koppelt aan een clean committed candidate of aan een digest van de volledige geteste snapshot, inclusief relevante untracked files.

Het diagram volgt de kortingswijziging van voorstel tot evidence. De harness levert de task en files, controleert de voorgestelde argumenten en permissions van edit_file en dispatcht de geaccepteerde call. Nadat de runtime de edit heeft toegepast, voert de harness de genoemde unit- en browser acceptance tests uit. Een gefaald commando gaat als evidence terug naar het model voor een nieuwe beurt; twee geslaagde commando’s maken de wijziging eligible for acceptance.

Een kortingswijziging door de harness control loopEen kortingswijziging door de harness control loop


Wat de harness beheert

OpenAI’s Codex loop walkthrough beschrijft de basiscyclus. De harness stelt een prompt samen, vraagt het model om de volgende actie, stuurt een geaccepteerde tool call naar de runtime en voegt het resultaat toe. Daarna vraagt de harness het opnieuw. Dit herhaalt zich totdat de harness het resultaat accepteert of de control teruggeeft aan de gebruiker.

Implementaties kunnen meerdere verantwoordelijkheden in één process combineren. De failure boundaries blijven echter verschillend:

TermTaakVoorbeeld voor een coding agent
ModelStelt text, een tool call of een final answer voorStelt een edit voor naar src/checkout.py
Reasoning loopKiest de volgende move uit de beschikbare contextInspecteren, editen, testen, opnieuw inspecteren
HarnessLevert context, valideert voorstellen, autoriseert deze, dispatcht geaccepteerde calls, legt resultaten vast en controleert completionStaat edits onder src/ toe en vereist beide genoemde tests
RuntimeVoert geaccepteerde calls uit en houdt state actief buiten het worker processSession log, sandbox, checkpoint store, trace backend

De runtime-rij omvat vier zaken: session, sandbox, checkpoint en trace. Alle vier slaan state op of beperken de uitvoering. Het model stelt de actie voor en de reasoning loop kiest de volgende move. De harness bepaalt of een voorgestelde call mag worden uitgevoerd en of de evidence voldoende is om te stoppen. Daarom krijgt de harness een eigen artikel. Part 5 telt de harness naast deze vier als een van de vijf primitives die je vóór shipping moet plaatsen; dit artikel splitst hem weer uit.

Wanneer een failure optreedt, diagnosticeer je de boundary die erop moet reageren. Een slecht plan kan betere instructies of betere model reasoning vereisen. Als edit_file naar een path buiten src/ verwijst, moet de harness dit weigeren. Een sandbox-process dat sterft voordat de edit wordt uitgevoerd, hoort bij de runtime, die de worker moet herstarten of de crash moet rapporteren.

Waar de eerdere delen terechtkomen

De harness-rij hierboven doet het meeste werk in die tabel en is waar Parts 2, 3 en 4 eindigen. Elk deel beslist één ding over een enkele beurt:

Eerder deelWat het voor deze beurt beslistWaar het werkt in de walkthrough van de volgende sectie
Part 2 — memoryWelke eerdere state in de prompt komtStap 1, de context builder
Part 3 — tool useWelke acties bestaan en hoe een gevalideerd resultaat eruitzietArgumentvalidatie in stap 3 en de result shape in stap 4
Part 4 — securityOf deze specifieke call nu mag worden uitgevoerdStap 3, de path check en de approval decision
Part 6 — dit artikelOf de resulterende evidence de run beëindigtStappen 5 tot en met 7, de acceptance checks en trace

Waar elk deel van de Engineering the Agentic Stack-serie zich bevindtWaar elk deel van de Engineering the Agentic Stack-serie zich bevindt

Parts 3 en 4 delen stap 3, en die overlap is precies het argument om ze als één programma te behandelen. Dezelfde laag harness code die een malformed argument weigert, weigert ook een call die wel is toegestaan maar nog niet approved. Als validatie en autorisatie in aparte services plaatsvinden, moet je de gevalideerde arguments over die boundary behouden, zodat de authorization decision van toepassing is op de call die wordt uitgevoerd.

De splitsing blijft belangrijk voor debugging: een edit in het verkeerde bestand is een Part 4 path rule, geen Part 2 retrieval-probleem. Een sectie verderop in dit artikel zet dit om in een routing table.

OpenAI’s eigen harness-engineering case study beschrijft een bootable application instance voor elke worktree. Het team koppelde ook browser automation aan de agent environment en stelde logs, metrics en traces beschikbaar.

Een task zoals “geen span in deze vier kritieke user journeys duurt langer dan twee seconden” werd testbaar doordat de agent de applicatie kon uitvoeren en dezelfde signals kon bevragen die een engineer zou inspecteren. De case study is product-specific. Wat overdraagbaar is, is de voorwaarde achter het resultaat: de applicatie en haar performance signals moesten binnen de agent environment beschikbaar zijn.

Lopopolo, de auteur van die case study, onderhoudt een field guide voor harness engineering. Deze benoemt de twee levers die dit artikel gebruikt: houd het model en de coding agent als black box vast en engineer de context en tools eromheen. Zijn framing verklaart ook waarom zo veel van de harness uit gewone code bestaat.

De quality bar, procedures, exception history en authority relationships van een organisatie vallen buiten wat een general model kan weten. De harness maakt ze zichtbaar als repository instructions, permission rules en acceptance checks. Elke geaccepteerde run kan zijn lessen terugvoeren naar die artifacts, in plaats van erop te vertrouwen dat de volgende session ze opnieuw ontdekt.


Volg de kortingswijziging van voorstel tot acceptatie

Voor de hierboven gedefinieerde discount task stelt het model voor om calculate_discount in src/checkout.py te wijzigen. Voordat die edit als progress telt, gebeurt het volgende:

  1. De context builder levert de task, repository instructions, relevante files, eerdere tool results en het huidige plan.
  2. Het model stelt een edit_file call voor met een path en replacement text.
  3. De tool boundary (de harness code tussen voorstel en uitvoering) valideert de arguments, controleert het path tegen de toegestane scope en vraagt om approval als de operatie dat vereist.
  4. De runtime past de edit toe in de sandbox en retourneert een structured result.
  5. De harness voert pytest tests/test_checkout.py uit, gevolgd door pnpm playwright test tests/checkout_discount.spec.ts, en leest beide exit codes. De browser test controleert de zichtbare korting van $8 op de seeded cart van $80.
  6. De harness bepaalt wat de resultaten betekenen. Een gefaalde check wordt nieuwe context voor de volgende modelturn en een geslaagde run maakt de task een completion candidate.
  7. Een geslaagd resultaat wordt pas completion evidence nadat de harness het commando, de exit code, de geteste snapshot, de grader en de environment versions durable heeft vastgelegd; een trace kan naar dat record verwijzen.

Na stap 2 is er nog geen file gewijzigd. De harness kan ../../secrets.env weigeren, approval vereisen voor een destructive command of een run stoppen die zijn budget heeft verbruikt. Dat is het laatste goedkope moment. Nadat de tests zijn uitgevoerd, leest de harness hun exit codes zelf. Het model kan zijn eigen edit niet als geslaagd markeren.

Het acceptance record moet de geteste snapshot, beide commands en resultaten en de grader- en environment versions identificeren; traces kunnen naar dat record verwijzen. Houd vereiste tests buiten de writable scope van de agent, of keur wijzigingen onafhankelijk goed voordat je ze graded. Elke latere file-edit maakt het resultaat ongeldig. Deze checks implementeren de stable-environment- en bypass-resistant-grader-principes uit Anthropic’s evaluation guidance. Een final done-message zonder die records bewijst niet dat deze wijziging de vereiste checks heeft doorstaan.


Bepaal waar elke rule wordt afgedwongen

De requirement dat tests/checkout_discount.spec.ts slaagt, hoort in deterministische code en niet in de prompt. De harness dispatcht het Playwright-commando naar de runtime, leest de exit code en weigert de run te beëindigen zolang de test faalt. Een prompt kan het model eraan herinneren de test uit te voeren. Hij kan niet voorkomen dat het model succes verklaart zonder evidence.

Andere rules passen in andere layers:

Plaats de rule inGeschikt voorVoorbeeld
Prompt of skillZoekvolgorde, coding conventions en plan formatLees AGENTS.md vóór het editen van checkout code
Tool boundaryArgumentvalidatie, toegestane paths, approvals en tool accessSta writes alleen toe onder src/
Deterministische codeBudgets, timeouts, retries, test exit codes en release requirementsHoud de run open zolang de Playwright-test faalt
Fresh-context evaluatorVisual review of criteria die human-like judgment vereisenVergelijk een gegenereerd diagram met een geschreven rubric

Tool contracts scheiden voorstel en permission

De discount task heeft alleen file edits en test commands nodig. Een state-changing API heeft een ander failure mode, dus voor deze sectie wisselen we van voorbeeld. Stel dat de agent create_test_order kan aanroepen tegen een staging order service tijdens het opzetten van testdata. Deze tool is geen acceptance check van de discount task. Hij is hier nuttig omdat een timeout kan verbergen of de service een order heeft aangemaakt.

De tool boundary heeft meer nodig dan een beschrijving in natural language. Er is een expliciet tool contract nodig. Part 3 pleitte voor zo’n contract vanuit het modelperspectief: duidelijke acties, compacte feedback en recoverable errors. De harness heeft om een andere reden hetzelfde contract nodig. Zij moet zonder het model te vragen bepalen of een call mag worden uitgevoerd en of een gefaalde call mag worden herhaald. Voor create_test_order betekent dit een contract met:

  • gevalideerde arguments, zodat malformed input vóór execution wordt geweigerd
  • een structured result zoals { "order_id": "123", "created": true }, zodat latere checks geen free-form text hoeven te parsen
  • een effect category die vastlegt of de call alleen informatie ophaalt of een file, database record of external service wijzigt. Ook wordt vastgelegd of herhaling van de call veilig is. Dit label vertelt de harness of een automatic retry werk kan dupliceren. De harness kan get_order_status retrien wanneer de service deze lookup als read-only definieert. Ze mag create_test_order niet blind retrien, omdat de eerste call de order al kan hebben aangemaakt
  • een timeout- en retry policy, zodat een verloren response geen ongelimiteerde reeks calls triggert
  • een permission rule die aangeeft welke approval nodig is. Het lezen van order status kan automatisch worden uitgevoerd, terwijl het aanmaken van een order confirmation kan vereisen

De beschrijving in natural language is tekst die aan het model wordt getoond. Die kan zeggen: “Create a test order for checkout verification.” Deze zin helpt het model bepalen wanneer het create_test_order moet voorstellen. Hij autoriseert de call niet. In dit voorbeeld valideert de MCP-client van de harness de arguments, past hij zijn eigen rules toe en controleert hij server trust, approval requirements en retry safety voordat er iets wordt gedispatcht. Daarmee worden de permission rules en pre-tool checks uit Part 4 gecombineerd, met één extra vraag: of een call die al is gefaald opnieuw mag worden verstuurd.

Een MCP server publiceert tool descriptions en optionele behavior annotations aan de client. Een faulty of malicious server kan een state-changing tool als harmless beschrijven. Een client die die claim automatisch accepteert, kan create_test_order zonder approval uitvoeren of retrien en zo een duplicate creëren. De MCP specification vereist daarom dat clients tool annotations als untrusted behandelen tenzij de server zelf trusted is.

De specification schrijft geen universele trust setting voor. Je hebt daarom een expliciet trust policy nodig voor je deployment; een server kan zijn eigen annotations niet trustworthy maken. Dat policy bepaalt welke metadata permission- of retry-beslissingen mag beïnvloeden en welke annotations alleen advisory blijven.

Een state-changing call retrien vereist replay protection

Part 5 vereist een durable operation identity voor side effects die bij een retry kunnen dupliceren. De harness bepaalt wanneer die key nodig is. create_test_order maakt de order aan, maar de HTTP-response gaat verloren. De harness ziet een timeout en kan niet bepalen of de server het request heeft voltooid. De call herhalen kan een tweede order creëren.

Persist een application-owned operation ID vóór dispatch en bind deze aan de approved arguments. Hergebruik dezelfde ID bij het herstellen van dezelfde intended order, ook als het model een nieuwe tool-call ID genereert; bewaar model-ID’s afzonderlijk voor correlation. Reconcile gewijzigde payloads of verlopen provider deduplication windows in plaats van blind opnieuw te verzenden. Het contract van Stripe staat bijvoorbeeld toe keys na minimaal 24 uur te verwijderen.

Een status lookup kan worden geretried wanneer de service deze als read-only definieert. Een creation call heeft de key nodig: de client voegt een unique request identifier toe en de service retourneert het eerste resultaat in plaats van een nieuwe order te maken wanneer deze identifier opnieuw wordt gezien. Zonder deze bescherming moet de harness controleren of de order bestaat of om een human decision vragen voordat een nieuwe poging wordt gedaan. AWS documenteert dit patroon in zijn idempotent API guidance.

Acceptance vereist onafhankelijke evidence

Een succesvolle response van create_test_order bewijst alleen dat de tool data heeft geretourneerd. Dit bewijst niet dat een coding task de tests heeft doorstaan. Als een latere browser test afhankelijk is van de staged order, moet de harness het response schema valideren en die test nog steeds uitvoeren voordat de codewijziging wordt geaccepteerd.

Sommige criteria kunnen niet tot een exit code worden gereduceerd. Voor een aparte visual-design task kan een fresh-context evaluator een rendered page of diagram vergelijken met een geschreven rubric — “fresh-context” betekent een tweede model session die zonder history van de run start en de geproduceerde artifacts leest in plaats van het transcript. Vergelijk deze evaluator met human reviews voordat je zijn resultaat laat bepalen of de task compleet is.


Een migratie van een payment adapter heeft een handoff nodig

We wisselen opnieuw van task, maar blijven in de fictieve store-repository. De agent moet checkout nu migreren van payment adapter v1 naar v2. Het werk omvat de checkout handler, payment client, configuratie en tests en kan dus langer duren dan één model session — één doorlopende periode van modelcontext die eindigt door een restart of een bewuste fresh start, in plaats van te worden voortgezet.

Voordat de eerste session zijn contextlimiet bereikt, heeft deze meerdere files gewijzigd, een lokale payment sandbox gestart en tests/payment_migration.spec.ts falend achtergelaten. Die browser acceptance test voltooit één payment via adapter v2 en verifieert de geregistreerde provider-ID. Een conversation summary kan de volgende model session oriënteren, maar kan de sandbox niet herstarten en niet bewijzen welke files momenteel gewijzigd zijn.

De volgende session moet drie zaken herstellen:

Wat moet worden hersteldWat het omvatHoe het kan falen
Conversation historyMessages, tool calls en geretourneerde resultsOude details verdringen de huidige task
Working environmentFiles, payment sandbox en browser-test stateHet transcript zegt dat een service draait nadat deze is gestopt
Task progressPlan, voltooide checks, pending approval, volgende actieDe volgende session herhaalt voltooid werk

Compaction vervangt oudere messages door een kortere summary, zodat de huidige session kan doorgaan. Een progress handoff legt vast wat de volgende session nodig heeft: de huidige branch, gewijzigde files, het laatste test command en de output daarvan en de volgende unresolved step.

Een handoff file is document memory voor de volgende model session. Een checkpoint kan het plan, voltooide stappen, resultaten en resterend werk al bewaren. Voeg een handoff toe wanneer die details in de volgende context ontbreken of onbruikbaar zijn en verifieer files en draaiende services tegen de live environment.

Als de oude conversation stale assumptions bevat, kan de harness een fresh model session starten met die handoff en de huidige workspace. Een gecrashte worker vervangen en zijn processes herstellen is een aparte runtime recovery job.

Een kleine documentation edit heeft mogelijk geen van deze mechanisms nodig. De payment migration heeft een handoff nodig als de opgeslagen state geen bruikbare task progress bevat, omdat de volgende model session zowel de workspace als de task status moet reconstrueren.

Anthropic’s experimenten met long-running coding agents gebruikten git history en een progress file tussen sessions. Anthropic’s latere harness-design report scheidt compaction van een fresh-context handoff en rapporteert dat handoffs orchestration, token use en wall time toevoegen, zonder cijfers te publiceren die enige van die overhead aan de handoff zelf toeschrijven.


Gebruik traces om drie failures van elkaar te onderscheiden

De volgende drie rijen zijn illustratieve trace sketches, geen gemeten runs of output uit het companion lab. Elke rij toont een andere failure en dus een andere harness response.

Wat de trace vastlegtWat er gebeurdeJuiste response
De read-only get_order_status call retourneert 503; er is geen state-changing call actiefEen transient lookup faaldeRetry de lookup met een limiet en backoff
create_test_order timed out, waarna een status lookup order 123 vond onder idempotency key checkout-42De service maakte de order aan, maar de response ging verlorenRetourneer de bestaande order; maak geen nieuwe aan
De edit en unit test slagen, maar de trace bevat geen result voor tests/checkout_discount.spec.ts op de geteste snapshotVereiste acceptance evidence ontbreektHoud de run open en dispatch de browser acceptance test

Een failure die transient lijkt, maakt niet elke call veilig om te retrien. De eerste rij is een read-only lookup. De tweede rij is een state-changing request, dus de idempotency key en server-side status bepalen of een nieuwe creation attempt is toegestaan. De derde rij is helemaal geen tool failure; de harness heeft de evidence voor het accepteren van de discount change nog niet verzameld.

Een chat transcript legt vast wat het model zag. Het kan niet bewijzen of de order service een request committe voordat de response verdween. Een trace kan die evidence alleen leveren als hij het relevante serverresultaat of de status lookup bevat; een client-side timeout alleen laat de uitkomst onopgelost. De durable operation- en acceptance records moeten de client call, approval decision, operation identity, serverresultaat of status lookup, tested snapshot en acceptance-testresultaat aan elkaar koppelen. Traces kunnen die links voor debugging zichtbaar maken zonder de recovery ledger te worden. Deze velden vertellen de harness op welk van de drie paden zij zich bevindt.

Terugkerend symptoomKleine wijziging om te proberenWat je meet
Read-only lookups falen transientBounded retry met backoffRecovery rate, extra calls, wall time
Hervatte sessions herhalen voltooid werkStructured progress handoffDuplicate tool actions na resume
Vereiste tests ontbreken bij completionWeiger completion totdat elke vereiste check slaagtTaken die zonder alle vereiste checks worden geaccepteerd
Visual defects overleven deterministische checksFresh-context evaluator met een rubricGevonden defects, false rejections, reviewtijd
De agent editt buiten zijn scopeSmallere tool permissionGeblokkeerde calls en manual overrides
Recalled memory verdringt de huidige taskBeperk recalled facts; rank ze vóór injectionTokens besteed aan recall, voltooide tasks, cost per task

Voor optional assistance zoals planning aids, summaries en extra evaluators moet je de failure benoemen en meten of het component zijn kosten terugverdient. Authorization, isolation, privacy requirements en verplichte acceptance checks blijven van kracht, ook als ordinary tasks zonder deze voorzieningen slagen. Test deze constraints met adversarial cases en expliciete invariants; een kleine success benchmark kan het verwijderen ervan niet rechtvaardigen.

Het omzetten van die terugkerende failures in een versioned regression suite is een afzonderlijke taak. Ik heb die apart beschreven in AI Agent Evaluation in Production.


Meet één wijziging per keer

Een ablation meet of een harness-component het verwachte effect veroorzaakt door dat component te wijzigen of te verwijderen terwijl de rest van het experiment gelijk blijft. Helpt editor linting dit model bijvoorbeeld op deze task suite?

Gebruik het volgende protocol:

  1. Fixeer de modelversie, task instances, environment, grader en prompts buiten het component dat wordt getest.
  2. Geef beide varianten hetzelfde totale token-, tijd- en dollarbudget.
  3. Kies het aantal trials of de stopping rule voordat je de vergelijking uitvoert.
  4. Voer dezelfde task instances in beide varianten uit. Omdat modeloutputs variëren, herhaal je elke task meerdere keren.
  5. Rapporteer het gemiddelde samen met de spreiding of het confidence interval.
  6. Tel elke gestarte trial mee, inclusief timeouts, policy stops, harness crashes en evaluator failures.

Success rate alleen kan een duur component verbergen. Track minimaal als completed geaccepteerde broken tasks, cost en wall time per completed task, tool errors, duplicate orders, review minutes en manual permission overrides. Kies de metric die de echte cost voor je product draagt. Een stijging van twee punten in completed tasks is een slechte trade-off als daardoor je review queue verdubbelt.

Een paired payment-migration experiment maakt de progress handoff meetbaar. Elk control/treatment-paar start vanaf dezelfde repository commit en seeded checkpoint, met hetzelfde model, dezelfde task, grader en hetzelfde totale budget. De handoff is de enige switch. De primary metric telt duplicate tool actions na resume: een action is duplicate wanneer de operation en het artifact overeenkomen met een step die de vorige session al had voltooid.

Een paired ablation test van de progress handoffEen paired ablation test van de progress handoff

Het SWE-agent paper fixeert GPT-4 Turbo op de 300-task SWE-bench Lite split en rapporteert 18,0% resolved met zijn volledige interface, tegenover 11,0% voor een shell-only agent met een uitgewerkte demonstration en 7,3% voor dezelfde agent zonder die demonstration. De headline gap van 10,7 punten in het paper wordt gemeten ten opzichte van die baseline van 7,3%; Part 3 werkt dezelfde drie cijfers uit vanuit het perspectief van interface design. Het paper wijzigde ook individuele interface features:

InterfacewijzigingResolved
Volledige SWE-agent-interface (reference, ongewijzigd)18,0%
Editor zonder linting15,0%
Volledig bestand in plaats van een viewer van 100 regels12,7%
Volledige observation history in plaats van de laatste vijf15,0%

Deze cijfers horen bij dat model, die benchmark en die limiet van $4 per task. De drie rijen onder de reference zijn de nuttige one-feature tests: telkens werd één interface feature gewijzigd terwijl het model en de evaluation setup gelijk bleven.

LangChain publiceerde een bredere fixed-model comparison voor deepagents-cli. Daarin wordt een stijging op Terminal-Bench 2.0 van 52,8% naar 66,5% gemeld met gpt-5.2-codex als fixed, terwijl het team de system prompt, tools en middleware wijzigde. De post bundelt meerdere wijzigingen en bevat geen confidence interval, geen vergelijking met een vast totaalbudget en geen ablation table per wijziging. Dit resultaat kan niet identificeren welke wijziging hielp. De modelnamen in deze sectie zijn de modellen die elke studie op het moment van uitvoering fixeerde; het protocol is overdraagbaar, niet de modellijst.

Een nieuwere vergelijking laat zien waarom de API-configuratie onderdeel moet zijn van de frozen baseline. In zijn ARC-AGI-3-rapport van 29 juli 2026 rapporteert OpenAI dat de public-set score van GPT-5.6 Sol steeg van 13,3% naar 38,3% toen de harness reasoning behield en compaction gebruikte in plaats van reasoning te verwijderen en history af te kappen. De metric is Relative Human Action Efficiency, niet het percentage opgeloste tasks. Dit is een vendor-reported, bundled comparison; de vergelijking isoleert de twee settings niet en stelt geen production effect size vast. Leg bij een upgrade de API, reasoning retention, compaction policy en budgets vast naast de model-ID. Anders kan een schijnbare modelregression in werkelijkheid een ontbrekende capability in de adapter zijn.

Neem provider intervention op in de failure suite. Een misalignment_policy_violation moet ook na streamed output een stop-and-review-pad bereiken; dit is geen transient retry-case. Part 4 behandelt de API-dependent scope ervan. Test of de harness dispatch stopt en reeds voltooide effects vastlegt.

Anthropic’s long-running application report is een kwalitatieve, product-specifieke case study en geen controlled benchmark. De applicatie is RetroForge, een 2D retro game maker; in Sprint 3 controleerde de harness evaluator 27 criteria voor de level editor. Het werk begon op eerdere Opus-modellen en toen Opus 4.6 verscheen, verwijderde het team harness-components één voor één om te zien welke door het nieuwere model redundant waren geworden. Het rapport stelt dat evaluator calls overhead werden bij tasks die Opus 4.6 betrouwbaar alleen kon voltooien, maar nog hielpen aan de rand van de modelcapaciteit. Het voorbeeld is een reden om oude scaffolding opnieuw te valideren wanneer het model verandert; het schat geen algemene effect size.


Houd de harness bewerkbaar nadat deze haar plek heeft verdiend

Ablation houdt een harness klein, maar de code kan langer meegaan dan het model waarvoor deze is getuned. Een verzoek zoals “mask secrets in every capture path” benoemt gedrag, geen file. In een production harness kan dat gedrag meerdere execution stages en shared state omvatten. Voordat je het veilig kunt wijzigen, moet je elke implementation site vinden — en dat geldt ook voor de coding agent waaraan je dit delegeert.

Een optie voor de researchfase is een preprint uit 2026 van Wang et al., de Harness Handbook, waarin dit behavior localization wordt genoemd. Het handbook bouwt een behavior-centric map van de harness codebase. Static analysis, waarvoor geen model calls nodig zijn, extraheert een program graph, waarna een LLM de units organiseert in execution stages.

De maintainer of coding agent begint met een system overview, opent de relevante execution stage en daalt af naar source-grounded entries voor een function of file. Een state register legt vast waar shared state tussen stages wordt geschreven en gelezen. Deze hiërarchie houdt het overzicht klein en behoudt tegelijk een path naar de source.

Freshness is een afzonderlijke rule. De map is een navigation aid; live source bepaalt het gedrag. Elke locator moet tegen de live repository resolven. Het handbook bevriest stale entries in plaats van te gokken en elke non-empty diff synchroniseert de entries die hij beïnvloedt opnieuw.

Het diagram comprimeert de modification loop: een behavior-only request daalt af door de levels van het handbook, elke candidate locator wordt tegen de live repository geverifieerd voordat het plan wordt geschreven en elke toegepaste diff synchroniseert de map opnieuw.

Een behavior change door een harness handbook routenEen behavior change door een harness handbook routen

De Handbook evaluation vergelijkt matched arms op 30 requests per repository. De evaluatie stelt geen gelijke totale budgets, herhaalde stochastic trials of uncertainty estimates vast en de gerapporteerde vergelijkingen sluiten missing outputs en planner errors uit. Ze illustreert daarom slechts een deel van het bovenstaande protocol. De evaluatie omvat twee open-source harnesses: Terminus-2 (zes Python-files) en de Codex monorepo (2.267 Rust-files). In beide repositories verkende een read-only planner, aangedreven door DeepSeek-V4-Pro, de repository direct of via het handbook. Requests, repository, tool permissions en decoding waren identiek in beide arms. Drie judges (GPT-5.5, Opus 4.8, DeepSeek-V4-Pro) scoorden elk edit plan op localization, scope control en reasoning — merk op dat één judge hetzelfde model is als het model dat de plans produceerde. Een win betekent dat de quality score van de ene arm op een schaal van 0–100 minimaal drie punten hoger lag dan die van de andere; anders was die judge–request comparison een tie. De gerapporteerde rate is wins gedeeld door het aantal valid judge–request comparisons:

HarnessBaseline win rateHandbook-assisted win ratePlanner tokens
Terminus-2 (6 files)26,7%45,6%−8,6%
Codex monorepo (2.267 files)28,3%38,3%−12,7%

De handbook-assisted planner won in beide repositories vaker en gebruikte minder planner tokens. De voorwaarden blijven aan dat resultaat verbonden: drie LLM judges scoorden edit plans die door één planner model op twee harnesses waren geproduceerd. De studie evalueerde plans, geen uitgevoerde diffs of production defect rates.


Probeer de methode in het companion lab

Het harness-demo-project op commit 517353f3 is een kleine, deterministische exercise met 12 generieke synthetic tasks rond codewijzigingen zoals fix-parser-edge-case, split-large-module en wire-browser-test. Het implementeert de fictieve store-repository niet.

Elke task fixture definieert een difficulty plus vier boolean conditions: een flaky tool, lost progress, een gemiste implementation gap en ambiguous completion. De simulator leidt een vijfde condition af voor difficult tasks die ook een progress file nodig hebben: zonder context_reset bewaart compaction stale assumptions. Een deterministische grader markeert een task alleen als passed wanneer de geselecteerde configuratie elke toepasselijke condition afhandelt. Er draait geen model en geen external service.

De commando’s beantwoorden verschillende vragen:

  • make check voert Ruff en zeven unit tests uit, waaronder de validator die elke ablation pair weigert die meer dan één component wijzigt.
  • make run print een cumulative teaching matrix en vervolgens vijf geldige leave-one-component-out comparisons.
  • make failures noemt de unhandled condition voor elke gefaalde task. De volledige harness hoort te eindigen met all synthetic tasks pass.
make check
make run
make failures

De causal section van make run ziet er als volgt uit:

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

Voor elke rij is de control de volledige configuratie met één component verwijderd; de treatment herstelt alleen dat component. De eerdere cumulative matrix is nuttig voor oriëntatie, maar sommige aangrenzende rijen voegen meerdere components tegelijk toe en kunnen daarom geen oorzaak identificeren.

Het lab valideert elk gedeclareerd pair voordat het wordt uitgevoerd. De regression tests bevatten ook een opzettelijk ongeldig pair dat zowel retry policy als evaluator wijzigt; de validator weigert dit.

Het lab vergelijkt alle vijf component fields bij het valideren van een pair. Dit runnable excerpt toont dezelfde guard op een geldig progress-handoff-pair:

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",)

Welke layer open je wanneer een run misgaat?

De serie bewoog van de reasoning loop naar buiten. Begin met de eerste failure die je ziet en onderzoek vervolgens het component dat die taak beheert. Een run kan meer dan één component omvatten:

Wat de run deedWaar de fix zitPart
Koos een slechte volgende stap terwijl de juiste informatie al beschikbaar wasReasoning loop of het model1
Herhaalde werk of verloor een beslissing die een uur eerder was genomenContext assembly en handoffs2
Kon de benodigde actie niet uitdrukken of las een geretourneerd resultaat verkeerdTool contract3
Deed iets waartoe hij nooit in staat had mogen zijnPermission rules4
Verloor alles toen een worker midden in een call stierfSession, checkpoint, sandbox5
Verklaarde succes bij werk dat niet was uitgevoerdAcceptance checks en traces6

Vier rijen wijzen naar harness code, terwijl rij 5 naar de runtime wijst. Instructions kunnen gedrag beïnvloeden, maar geen permission check, durable checkpoint of acceptance test vervangen.


Begin met één loop en één acceptance check

Ik zou een coding-agent harness beginnen met één capable model, repository instructions, enkele narrow tools, een sandbox en één expliciete acceptance test. Ik zou tool calls, resultaten, costs en die final test in één trace vastleggen, zodat de eerste nuttige failures zichtbaar zijn zonder ze uit terminal logs en chat transcripts te moeten reconstrueren. Dit is een voorgestelde baseline en geen evidence uit een deployed system.

Voeg vanaf daar alleen toe wat een trace rechtvaardigt. Leg vast wie elk component onderhoudt, hoeveel tokens of seconden het toevoegt en welke regression test het verwijderen ervan na een modelupgrade zou rechtvaardigen.

Zes maanden later zou iemand die progress_handoff=True ziet, de failed traces moeten kunnen vinden die het component rechtvaardigden en de regression cases die het nog steeds op zijn plaats houden. De traces verklaren waarom het component bestaat; een actuele behavior map verklaart waar je het moet aanpassen.

Als je via een search hier bent gekomen, hebben de vijf voorgaande artikelen een systeem rond een reasoning loop gebouwd:

  1. De loop kiest de volgende move.
  2. Memory levert context en een echte Postgres checkpoint store bewaart deze.
  3. Tool contracts definiëren acties en de result shapes die latere checks kunnen lezen.
  4. Security voegt de deny hook en stop-hook validator toe. Beide blijven in het voorbeeld sketches, maar markeren de control points.
  5. De runtime houdt het process actief over sessions en failures heen.

De serie voegde ook een optioneel MCP server surface en een evaluator node toe die het draft report controleert voordat een mens het ziet. Het routen van de worker via een credential-holding proxy blijft een voorgestelde extension. Dit zijn gewone codecomponenten rond een model call. De router is om dezelfde reden harness code: hij kiest het reasoning pattern voordat de reasoning loop start.

Voor het volgende optional assistance-component houd je de failed trace, de acceptance rule en de vergelijking met dat component disabled bij elkaar. Laat het component weg als je het voordeel niet kunt identificeren. Vereiste security- en acceptance constraints zijn niet afhankelijk van die vergelijking.


References


The Market Analyst Agent code staat op GitHub.