Vijf maanden bugs behandelen als patiënten en codeer-agents als een medisch team
Belangrijkste inzichten
- We hebben een pipeline voor codeer-agents geïmplementeerd die is gestructureerd volgens de metafoor van een opleidingsziekenhuis. Hierbij worden verschillende rollen gebruikt, zoals Triageverpleegkundigen, Fellows, Review-specialisten en Ontslagverpleegkundigen, om strikte reviews, verplichte planning en veiligheidsmechanismen af te dwingen voordat code wordt samengevoegd (merged).
- Over een periode van vijf maanden heeft deze agent-pipeline met succes meer dan een miljoen regels code verwerkt met slechts zeven reverts in totaal. Dit bewijst dat gestructureerde agent-workflows veilig complexe database-migraties kunnen bouwen en onderhouden.
- Door prioriteit te geven aan nauwkeurige verslaglegging, strikte testdekking en het reviewen van plannen voordat er code wordt geschreven, minimaliseerde het systeem kostbare regressies. Dit maakte functies mogelijk zoals de Migration Assistant, waarbij een balans werd gevonden tussen autonome output en betrouwbaarheid op enterprise-niveau.
---
Tussen een woensdagavond en een vrijdagmiddag in april kreeg MOLT — de tool die Cockroach Labs levert voor het migreren van databases naar CockroachDB — de mogelijkheid om te migreren vanuit IBM Db2-bronnen.
Db2, een van de eerste commercieel beschikbare relationele databases, heeft een rijk SQL-dialect, een complex typesysteem en een native wire-protocol. Ondersteuning hiervan in MOLT betekende: een nieuwe schema-converter, een nieuw Fetch-pad voor het ophalen van rijen en het laden ervan in CockroachDB, een nieuw Verify-pad voor het vergelijken van gegevens na het laden, een vendored ANTLR-grammatica, een Docker-image voor CI en meer dan tienduizend regels test-fixtures. Toen we in 2024 Oracle-ondersteuning toevoegden aan de MOLT-tools, nam het equivalente werk negen maanden in beslag en kostte het ongeveer $160.000 aan engineering-tijd.
De implementatie voor Db2 duurde minder dan twee dagen, en er werd geen enkele regel code door een mens geschreven. De token-rekening bedroeg $4.172: 164 keer sneller en 38 keer goedkoper.
Het begon allemaal met één enkel GitHub-issue waarin de vraag werd beschreven. Een planning-agent las dit, besloot dat het te groot was om in één keer aan te pakken en splitste het op in vijftien sub-issues met een expliciete afhankelijkheidsgrafiek: eerst de fundering, dan het typesysteem, dan de row-iterator, gevolgd door Fetch, Verify, Convert, CI en tenslotte de testdata. Twee van de sub-issues werden tijdens de uitwerking als te groot beoordeeld en opnieuw opgesplitst. Onderweg maakten de agents nog een dozijn issues aan voor hun eigen werk: gaten in fixtures, een bug in de type-mapping en een fix voor het isolatieniveau. Tegen de tijd dat het hoofdissue werd gesloten, waren er tweeëndertig sub-issues geopend, waren er zevenentwintig pull requests (PR's) gemerged, hadden reviewers het werk vijfenvijftig keer teruggestuurd en waren negen issues geëscaleerd, waarvan twee naar een mens. De testdekking was gelijkwaardig aan die van PostgreSQL (ons best geteste dialect).
Maar hoe is dit gebeurd? Wat stuurde dit aan en, belangrijker nog, wat garandeerde dat de output van hoge kwaliteit was? Voordat we het issue voor Db2-ondersteuning openden, bouwden we een "codeerziekenhuis" dat we MOLT Sinai noemen. MOLT is de naam van de migratie-toolset van CockroachDB, en toen we besloten de pipeline te modelleren naar een ziekenhuis, was MOLT Sinai een onweerstaanbare woordspeling. Mount Sinai is een prominent opleidingsziekenhuis in zowel Toronto als New York — de steden waar wij wonen. De naam bleef hangen, en daarmee ook het vocabulaire. Issues zijn patiënten. Mergen is ontslag. De mensen die de leiding hebben zijn de Chiefs of Medicine.
Dat agents snel veel code schrijven is niet uniek; "softwarefabrieken" duiken overal in de industrie op. Wat uniek is aan onze aanpak is wat er tussen die agents en de main branch staat, waarom we het als een ziekenhuis hebben ingericht en wat er gebeurde toen we het vijf maanden lang op echt werk hebben getest.
Waarom een opleidingsziekenhuis?
Het probleem met codeer-agents is dat ze weliswaar zeer capabel zijn in het schrijven van code, maar het moeilijk is om hen te vertrouwen bij het produceren van code van productiekwaliteit die goed getest is, onderhoudbaar is en binnen de gewenste scope valt. Agents zijn relatief goedkoop om te draaien, maar dat biedt weinig troost als hun code bij klanten terechtkomt. We accepteren liever dat agents er langer over doen (zelfs 10x langer) dan dat er foutieve data terechtkomt in een klantmigratie naar CockroachDB. Snelheid is belangrijk, maar kwaliteit is veel belangrijker.
Verschillende pogingen om agent-coding te automatiseren zijn het afgelopen jaar verschenen, waarvan velen zijn geoptimaliseerd voor doorvoersnelheid (throughput). Gas Town bijvoorbeeld draait veel agents parallel op een codebase met een merge-laag om botsingen op te lossen. Dat is een goed ontwerp wanneer de bottleneck de snelheid van het schrijven is. Er is ook een experiment van Cursor waarbij ze SQLite zo snel herbouwden dat ze hun eigen versiebeheersysteem moesten schrijven om het volume aan wijzigingen te verwerken. Interessant, maar duidelijk niet ontworpen om kwalitatieve database-code naar gebruikers te brengen.
Onze motivatie was anders. Wij bouwen een gedistribueerde SQL-database en een suite van tools om workloads naar die database te migreren. Een subtiele bug in een migratietool zou de data van een klant kunnen corrumperen in een database die juist juistheid boven alles moet stellen. Daarom was onze vraag niet "hoeveel PR's per uur?", maar "hoeveel van die PR's zouden we onszelf zouden schamen om te mergen?". Met die herformulering was duidelijk dat een op doorvoersnelheid geoptimaliseerde zwerm agents geen goed model was.
We zochten naar een model met lange ervaring in het beheren van risicovol werk dat wordt uitgevoerd door personeel met wisselende vaardigheden, met verplichte overdrachten, verplichte second opinions en literatuur over wat er misgaat bij slordige overdrachten. Zo kwamen we uit bij een opleidingsziekenhuis.
De metafoor gaf ons de volgende rollen:
- Triage Nurse (Triageverpleegkundige): Beoordeelt nieuwe issues en bepaalt de prioriteit en initiële aanpak.
- Fellow (Assistent-arts): De primaire agent die het onderzoek uitvoert, het plan schrijft en de code implementeert.
- Review Attending (Behandelend specialist): Een senior agent die het plan en de code kritisch beoordeelt en goedkeurt of afwijst.
- Discharge Nurse (Ontslagverpleegkundige): Controleert of alle administratieve en kwalitatieve vereisten zijn behaald voordat de patiënt (het issue) mag worden ontslagen (merged).
Om deze kern heen zitten andere actoren: een Charge Nurse die elke dertig minuten rondes loopt om vastgelopen patiënten te vinden, een Infection Control-agent die elke workflow in het gebouw kan blokkeren als main breekt, een Safety Department die wekelijkse procesreviews schrijft en post-incident conferenties organiseert, en een Research Department die nieuw werk voorstelt.
We beweren niet dat dit goedkoper is dan een zwerm of eenvoudiger dan een enkele agent. Het produceert echter een product van hogere kwaliteit. In de databasebranche ben je bereid te betalen voor die kwaliteit. Zoals hieronder te zien is, brengt het ook enkele vervelende aspecten van opleidingsziekenhuizen met zich mee (bureaucratie, wachttijden en kosten), maar we geloven dat dit waardevolle trade-offs zijn.
Hoe het is gebouwd
Alles in het ziekenhuis draait op GitHub Actions. De status van elke patiënt wordt bijgehouden in de labels van het issue, evenals in kladbestanden die het ziekenhuis maakt om de voortgang van elke patiënt te volgen.
Elke fase is een GitHub-workflow die start wanneer een specifiek "in-label" op het issue wordt geplaatst. Wanneer de agent klaar is, schrijft hij een "out-label", wat het "in-label" voor de volgende fase is. Gestippelde pijlen sturen werk terug: een afgewezen plan gaat terug naar de uitwerking, een rode CI-run of verzochte wijzigingen gaan terug naar de behandeling, en een vastgelopen fase wordt geëscaleerd naar de Chief.
Vier afdelingen draaien buiten deze flow om op hun eigen schema: de Charge Nurse start vastgelopen fasen opnieuw, Infection Control blokkeert het ziekenhuis bij breuken in main, en de Research- en Safety-afdelingen dienen nieuwe issues en beleids-PR's in, die via de Chief binnenkomen.
Het toepassen van een label activeert een GitHub-workflow die een rolspecifieke prompt laadt, zodat de agent handelt als een werknemer in het ziekenhuis. Na voltooiing voegt de agent een gestructureerde notitie toe aan het dossier van het issue. De notitie bevat een marker zoals <!-- SINAI:TREATMENT_PLAN --> zodat latere agents deze kunnen vinden en analyseren.
Enkele basisregels van het ziekenhuis, gecodeerd in de skills, waarborgen de veiligheid:
- Geen code vóór een plan, geen plan zonder review. Voordat de Fellow iets oplost, moet hij het probleem reproduceren, een differentiaaldiagnose stellen, gericht onderzoek doen en een behandelplan posten: diagnose, te wijzigen bestanden, toe te voegen tests, risico's en openstaande vragen. Een Review Attending (een andere agent-instantie met een prompt gericht op het vinden van fouten) leest het plan en keurt het goed of wijst het af. Pas daarna begint de behandeling. Deze poort is toegevoegd omdat een agent die vol vertrouwen de verkeerde fix implementeert, veel meer tijd en tokens verspilt dan een agent die stopt om zijn plan te controleren.
- Niet improviseren. Als de scope tijdens de behandeling verandert, stopt de Fellow, post hij een herzien plan en gaat hij terug naar de plan-review. De instructie in het skill-bestand is kort: "Don't improvise."
- Geen shortcuts, vooral niet bij testen. Een agent mag een test niet uitschakelen, overslaan, verzwakken of wijzigen om hem te laten slagen. Als een test faalt, is de test correct tot het tegendeel is bewezen. Als de agent echt gelooft dat de test fout is, moet de wijziging aan de test een eigen commit zijn, apart gerechtvaardigd en gereviewd. Bovendien is een geslaagde test die de wijziging niet daadwerkelijk test, erger dan geen test. Alle code-reviews beginnen met het uitschakelen van de wijziging om te controleren of alle nieuwe tests falen; zo niet, dan zijn ze buiten scope of incorrect.
- Nooit blindelings doorgaan (Never flail). Wanneer een Fellow vastloopt, probeert hij het niet simpelweg "harder". Hij schrijft een I-PASS-overdracht (Illness severity, Patient summary, Action list, Situation awareness, Synthesis) — een gestructureerd formaat uit echte opleidingsziekenhuizen — en escaleert naar een Attending. De ontvangende agent moet eerst opschrijven wat hij van de overdracht heeft begrepen voordat hij begint.
- De ontslagverpleegkundige controleert de reviewer. De laatste poort voor de merge reviewt de code niet opnieuw. Hij verifieert of de review correct is verlopen: is er een goedkeuring, is het review-template ingevuld, zijn alle threads opgelost, is de CI groen en is de commit-historie schoon.
- Check de precedenten voordat je de Chief stoort. Elke generaliseerbare beslissing van de menselijke Chief wordt opgenomen in een precedent log. Een agent die wil escaleren, moet eerst dit log lezen. Als een precedent van toepassing is, volgt de agent dit en citeert hij het in plaats van te escaleren.
Wat er is opgeleverd
We hebben een mirror van de repo gebruikt als proefterrein. Tussen 21 april en 11 september gebeurde het volgende:
In iets minder dan 5 maanden heeft de ziekenhuis-pipeline ruim een miljoen regels code opgeleverd, opgedeeld in wijzigingen die klein genoeg waren om door agents zelfverzekerd te worden gereviewd.
Bijna de helft van de issues in de repository werd aangemaakt door het ziekenhuis voor het ziekenhuis: opgesplitste sub-issues, follow-ups die de Fellow identificeerde, voorstellen van de Research Department en correctieve acties van de Safety Department. De pipeline genereert zijn eigen backlog. Een mens beslist wat wordt toegelaten, maar vanaf de tweede maand waren mensen niet langer de belangrijkste bron van werk.
Hoewel de Db2-ondersteuning het eerste grote experiment was, schakelden we daarna over op "human approval mode", waarbij elke merge door menselijke ogen moet worden bekeken. Met deze extra veiligheidslaag begonnen we aan het echte doel: het bouwen van de Migration Assistant, een AI-tool die gebruikers door een volledige migratie van Postgres naar CockroachDB leidt. Deze tool is nu in preview en is bijna volledig geschreven door de ziekenhuis-agents.
De kosten
Sinds april heeft MOLT Sinai iets meer dan $135.000 aan Claude-tokens verbruikt, wat neerkomt op ongeveer $84 per gemiddelde patiënt (issue). Issues brengen meestal één tot twee dagen door in het ziekenhuis, vaak gedomineerd door de wachttijd op een menselijke reviewer.
De gebruikte modellen zijn geëvolueerd. In het begin werd voor elke fase een Opus-model gebruikt, maar nu wordt er gepland met Fable. Het door Fable gegenereerde plan bepaalt vervolgens welk model wordt ingezet voor de implementatie. In gevallen waarin een Sonnet- of Opus-model worstelt, kan er worden geëscaleerd naar een Fable-model. Dit helpt de kosten te drukken terwijl de meest capabele modellen worden ingezet waar nodig.
Het ziekenhuis bouwde zichzelf
Toen we MOLT Sinai startten, bouwden we de initiële workflows en prompts direct in de mirror-repo. Al snel splitsten we de "Sinai"-code (de pipeline zelf) uit naar een aparte repo zodat anderen deze konden overnemen.
De Sinai-repository heeft inmiddels ongeveer 1.570 commits. Ruim 1.340 daarvan — 85% — zijn geschreven door de pipeline zelf. We hadden dit niet gepland; het raamwerk had bugs, en we stuurden die bugs door het ziekenhuis zoals elk ander issue. De Charge Nurse-workflow, die elke dertig minuten rondes loopt, bestaat omdat een agent een race-condition in GitHub Actions ontdekte, hier een issue over startte en een andere agent de fix ontwierp en implementeerde.
Vandaag de dag is het Sinai-model actief in vier repo's bij Cockroach Labs, met plannen voor uitbreiding.
De instructies werden legacy-code
Elke agent-rol is gedefinieerd door een skill-bestand: een Markdown-document met procedures, regels, templates en verboden gedragingen. Deze werden geschreven zoals kennisbanken vaak worden: door een regel toe te voegen telkens wanneer er iets misging.
In juli voerden we een audit uit op 25 skill-bestanden (ruim 100.000 woorden). Ongeveer 23% van de woorden kon worden verwijderd zonder dat dit invloed had op de werking. Het dominante patroon was redundantie: dezelfde regel die op verschillende plekken werd herhaald.
Deze redundantie kostte echt geld en tijd. De ontslagverpleegkundige laadt bijvoorbeeld ongeveer 21.800 woorden aan instructies bij elke run, nog voordat er één regel code is gelezen. Onze prompts "rotte" zoals code rot: we bleven regels toevoegen maar verwijderden ze nooit.
Geleerde lessen
Wat werkte
- Het model doet meer dan verwacht. Door rollen te definiëren (bijv. "Je bent een Fellow die een diagnostische uitwerking doet" of "Je bent een ANDERE agent-instantie die bugs moet vinden"), maakt het systeem gebruik van de interne kennis van het LLM over hoe een opleidingsziekenhuis werkt. Agents namen deze rollen zeer serieus, inclusief de nuances van professionele communicatie en hiërarchie.
- Plan-review vóór de code. Plannen die worden gereviewd, worden in minder dan 10% van de gevallen afgewezen, maar wanneer dat gebeurt, is dat de meest waardevolle review in het systeem. Het verschuift het herstelwerk naar het vroegst mogelijke punt.
- Decompositie met een hard plafond. Als een wijziging meer dan 1.000 regels code (inclusief tests) beslaat, moet de Fellow dit opsplitsen in sub-issues met een afhankelijkheidsgrafiek. Dit zorgt ervoor dat elke wijziging klein genoeg is om door een reviewer (agent of mens) volledig in het hoofd te worden gehouden.
- De verslagen. Elk issue registreert alles: het plan, de reproductietesten, elke revisie, elke I-PASS overdracht en elke review-uitspraak. Deze records leven in een aparte archive-branch, zodat de PR-diff alleen code bevat. Dit maakt retrospectieve analyses en wekelijkse safety-reviews mogelijk.
Wat we veranderden of nog moeten aanpassen
- Het model doet soms te veel. Dezelfde prompting die de rollen effectief maakt, maakt ze ook bureaucratisch. Een eenvoudige "sluit als duplicaat" actie werd soms geëscaleerd naar de Chief omdat "sluiten als duplicaat" niet expliciet in de drie gedocumenteerde uitkomsten van het protocol stond. Ook kleine typo's in PR-beschrijvingen konden leiden tot blokkades.
- Reviews hebben een "circuit-breaker" nodig. We ontdekten dat sommige issues in een oneindige loop van rework-rondes terechtkwamen. Een fix van één regel code nam eens elf rework-rondes in beslag. We hebben nu een regel ingevoerd: na vier opeenvolgende blokkerende bevindingen of zes substantiële rondes, moet de reviewer de zaak overdragen aan een Attending.
- Het ziekenhuis is té productief. De Research Department stelde zoveel nieuwe features voor dat we de hoeveelheid issues moesten begrenzen. Het lastige blijft het vinden van de "goudklompjes" in de rivier van suggesties.
- Een ziekenhuis dat niet echt onderwijst. Het huidige model is perfect voor senior engineers die snel kwaliteitswerk willen verzetten, maar minder voor junioren die het vak willen leren. We werken nu aan uitbreidingen waarbij mensen hun eigen plannen kunnen maken en deze door de hospital-agents laten reviewen, waarbij ze gedwongen worden hun beslissingen te verdedigen en alternatieven te overwegen. We moeten de software engineers van de toekomst bouwen, ongeacht hoe de wereld van agentic coding er over tien jaar uitziet.
Volgende stappen
We werken continu aan de efficiëntie, snelheid en nauwkeurigheid van de agents. Daarnaast maken we het systeem educatiever voor junior engineers. Ook zijn we bezig te verifiëren of de door het ziekenhuis geschreven IBM Db2-ondersteuning volledig correct is, aangezien we die code tijdens de initiële test niet handmatig hebben gecontroleerd. Tot slot experimenteren we met het terugbrengen van het ziekenhuis in een volledig autonome modus voor specifieke klassen van issues.
Groetjes,