Hoofdstuk 17 · agentisch werken
De agent
De chat van hoofdstuk 15 kan praten; dit hoofdstuk leert het model wérken. De opdracht luidt: "bouw een HTML-pagina" — en het model schrijft die zelf, ziet automatische controles over zijn werk heen gaan, en mag pas afronden als alles groen is. De les van dit hoofdstuk is de belangrijkste van het hele slot: de betrouwbaarheid van een agent zit niet in het model, maar in de lus eromheen.
Deel 01 Van praten naar werken
Een agent is geen ander model — het is dezelfde forward pass, dezelfde sampler, hetzelfde sjabloon als in hoofdstuk 15. Het verschil is de lus eromheen: het model krijgt gereedschap aangeboden, kiest zelf zijn stappen, en ziet na elke stap het resultaat. Het protocol daarvoor zat al die tijd al in het modelbestand: het gesprekssjabloon van hoofdstuk 15 heeft een aparte tak die gereedschapsschema's als JSON in <tools>-tags aankondigt, waarna het model antwoordt met een <tool_call>-blok en het resultaat als <tool_response> terugkrijgt — woord voor woord de verpakking waarmee het getraind is.
Deel 02 Het harnas: zekerheid buiten het model
Hoofdstuk 15 eindigde met een wiebelig model in een stevig harnas; hier wordt dat het ontwerpprincipe. Alles wat zeker moet zijn, doet het harnas; alleen wat creatief moet zijn, doet het model. Het model schrijft de pagina. Het harnas doet de rest: het keurt elke geschreven pagina meteen met deterministische Java-code (HtmlControles.java: doctype, basisstructuur, tag-balans met een stapel, en de letterlijke eisen van de opdracht), het bewaakt paden en bestandsgroottes, het verpakt het gesprek exact volgens het sjabloon — en het weigert finish zolang één controle rood staat.
Er zijn maar twee gereedschappen: write_file en finish. Elke extra keuze is voor een half miljard parameters een extra kans op de verkeerde; zelfs lezen bleek overbodig, want de controle-uitslag komt toch al na elke schrijfactie terug. En omdat een gereedschapsaanroep een heel HTML-bestand als ontsnapte JSON-string bevat, kon het veldjes-grepen van de eerdere hoofdstukken niet meer: Json.java is een volledige mini-parser, met duidelijke foutmeldingen die de lus aan het model teruggeeft.
Deel 03 Op gang krijgen: het voorbeeld en de voorzet
De allereerste run was ontnuchterend. Het model kreeg zijn gereedschap keurig volgens het boekje — en antwoordde eerst met een leeg bericht, daarna elf stappen lang met: "Sorry, I can't generate HTML directly." Een model dat nét gereedschap kreeg om HTML te schrijven, verontschuldigt zich dat het geen HTML kan schrijven; en bij temperatuur 0 is die weigering een dwangbuis, want dezelfde context geeft greedy hetzelfde vervolg. Twee klassieke ingrepen brachten het vlot:
- Het voorbeeldgesprek. Vóór de echte opdracht speelt het harnas één volledig rondje voor: voorbeeldtaakje, write_file-aanroep, groene uitslag, finish. Eén keer vóórdoen zegt een klein model meer dan welke instructie ook.
- De voorzet. Het harnas begint elk antwoord alvast met <tool_call>: "sorry" is dan geen bereikbare uitweg meer — het antwoord is al een aanroep begonnen. Staat er een controle rood, dan stuurt de voorzet harder en begint hij een write_file voor precies het falende bestand.
En één valkuil verdient een eervolle vermelding: <tool_call> en </tool_call> zijn zélf speciale tokens, en de generatielus van hoofdstuk 15 stopt op elk speciaal token — waardoor de sluittag van elk antwoord werd afgeknipt voordat het harnas hem kon lezen. De protocol-tokens hebben nu een uitzondering: zij horen bíj het antwoord.
Deel 04 De proef: twee stappen naar een groene pagina
Met beide steuntjes aan is de basistaak — een koffiepagina met een kop en een lijst, eisen <h1> en <ul> — in één keer raak, greedy en dus exact herhaalbaar:
-- stap 1 --
model: write_file page.html (221 tekens)
harnas: Wrote page.html. Checks: no problems found.
-- stap 2 --
model: finish — page.html created and checked.
KLAAR - alle controles groen
De pagina is naar de vorm keurig: doctype, lang="nl", titel, kop, lijst met drie koffiesoorten. (Eén eigenwijsheid: het model noemde het bestand page.html waar de opdracht om pagina.html vroeg — de controles toetsen de inhoud, niet de bestandsnaam.) De inhoud is een ander verhaal — "Ik ben een koffie die koud is", dicht het model — en dat is meteen de grens: het harnas garandeert de vorm, niet de inhoud. De meetladder eromheen (elk steuntje apart uitgezet) staat in de vervolgstudie bij dit boek: zonder voorbeeld schrijft het model de opdrachttekst als bestandsinhoud, zonder beide komt het niet eens op gang — en in álle gevallen hield de poort.
Deel 05 Bouwen gaat, verbouwen niet
Het echte experiment is een rode controle. Geef de opdracht een eis die het model geheid vergeet — <meta charset="UTF-8"> — en kijk of de terugkoppeling tot herstel leidt:
-- stap 2 --
model: write_file page.html (221 tekens)
harnas: Error: that is exactly the same content as before. It still has
1 problem(s): - de opdracht eist '<meta charset="UTF-8">' …
-- stap 3 --
model: write_file page.html (221 tekens) ← alweer identiek
(harnas: tweemaal dezelfde inhoud — temperatuur naar 0,3)
-- stap 5 --
model: write_file page.html (221 tekens) ← nog steeds identiek
(harnas: het kopiëren houdt aan — temperatuur naar 0,8)
-- stap 12 --
model: write_file page.html (221 tekens) ← nóg steeds identiek
MISLUKT - stappenbudget op zonder groene controles
Elf stappen lang — van stap 2 tot en met 12 — kopieert het model zijn eigen bestand, byte voor byte — dwars door de foutmelding, een letterlijke hint, de sturende voorzet en twee temperatuurverhogingen heen. Vooral dat laatste is leerzaam: wie een lange identieke tekst kopieert, heeft per token een extreem spitse kansverdeling, dus zelfs temperatuur 0,8 verandert niets — de dobbelsteen van hoofdstuk 15 kan een kopieerlus niet breken. En de omgekeerde route (de eis vooraf in de opdracht) verschuift het probleem alleen: toen de meta-regel er wel in kwam, viel de titel eruit. Wat de eerste worp mist, blijft gemist.
Deel 06 De sterkere bestuurder
De vervolgstap liet niet lang op zich wachten: qwen2.5:3b (1,9 GB, dezelfde qwen2-architectuur) door exact dezelfde lus — zonder één regel code te wijzigen. Het verschil is als dag en nacht:
| proef | 0,5B (qwen2.5:0.5b) | 3B (qwen2.5:3b) |
|---|---|---|
| basistaak, met steuntjes | 2 stappen — maar "page.html" en wiebelig proza | 2 stappen — het gevraagde pagina.html, spontaan mét meta-charset en viewport |
| herstel na rode controles | kopieerlus: elf keer byte-identiek, MISLUKT | één herschrijfslag: footer én tabel ingebouwd, origineel intact, KLAAR |
| kaal, zonder steuntjes | komt niet op gang (lege antwoorden, weigerlus) | 3 stappen KLAAR — inclusief zelfherstel van een vergeten doctype |
De herstelproef kreeg dit keer twéé eisen die niet in de opdrachttekst stonden (<footer> en <table>):
-- stap 1 --
model: write_file pagina.html (359 tekens)
harnas: Wrote pagina.html. Checks found 2 problem(s):
- de opdracht eist '<footer>' en dat staat er niet in
- de opdracht eist '<table>' en dat staat er niet in …
-- stap 2 --
model: write_file pagina.html (722 tekens)
harnas: Wrote pagina.html. Checks: no problems found.
-- stap 3 --
model: finish — pagina.html created and checked.
KLAAR - alle controles groen
Waar de 0,5B elf stappen lang zijn eigen bestand kopieerde, verwerkt de 3B de terugkoppeling in één slag — en chirurgisch: de oorspronkelijke pagina bleef intact, de footer en de tabel kwamen erbij (compleet met een voettekst "Voetbal is ook leuk!" — de vorm is gegarandeerd, de inhoud blijft van het model). Ook kaal, zonder voorbeeldgesprek en voorzet, werkt de 3B gewoon: de eerste worp miste een doctype, de tweede zette hem er zelf in. De steigers die voor een half miljard parameters onmisbaar waren, zijn voor drie miljard al overbodig.
Slotwoord De cirkel voorbij
Zestien hoofdstukken lang groeide hier één neuron uit tot een pratend taalmodel; dit zeventiende laat zien wat er gebeurt als je dat model aan het werk zet. Het antwoord is verrassend symmetrisch. De architectuur — gereedschap aanbieden, elke stap deterministisch keuren, terugkoppelen, en "af" laten bepalen door controles — is dezelfde waarmee de grote agent-systemen werken. Alleen de bestuurder verschilt. Een half miljard parameters kan één ding goed: in één keer iets kleins bouwen dat aan de meeste eisen voldoet. Herstellen op aanwijzing kan het niet — daarvoor moet een model tegen zijn eigen eerdere uitvoer in durven gaan.
Die vervolgstap is in deel 06 meteen gezet, en het antwoord was eenduidig: de herstelvaardigheid begint ergens tussen een half en drie miljard parameters, en het harnas hoefde er inderdaad geen regel voor te veranderen. Dat is het punt van het ontwerp — en misschien wel van het hele boek: begrijpen waar de zekerheid vandaan komt, is belangrijker dan hopen dat het model haar levert.
De volledige meetladder, het ontwerp en de kerntranscripten staan in de vervolgstudie "Agentisch werken met een half miljard parameters" naast dit boek.
# de zelftest (zonder model) en een echte agent-run, vanuit code/
java --add-modules jdk.incubator.vector src/AgentTest.java
java --add-modules jdk.incubator.vector src/Agent.java $MODEL \
--taak "Maak pagina.html: een Nederlandse pagina over koffie, met een kop
en een lijst van drie koffiesoorten." --eis "<h1>" --eis "<ul>"