Het artikel reflecteert op de uitdaging van non-determinisme bij het gebruik van Large Language Models (LLM's) voor softwareontwikkeling. De auteur stelt dat hoewel het uiteindelijke resultaat van software exact moet zijn, de methode om daar te komen (de code) niet deterministisch hoeft te zijn.
Om de inherente willekeur van AI-modellen te beheersen, adviseert de auteur om non-deterministische output te transformeren naar deterministische tools en abstracties. Door AI-agents deze geteste en geautoriseerde tools te laten aanroepen, wordt de betrouwbaarheid verhoogd en het tokenverbruik verlaagd. De auteur ziet dit als een moderne evolutie van samengestelde automatisering, waarbij de machine zelf abstracties bouwt en beheert om efficiënter en nauwkeuriger te opereren.
Non-Determinisme doet er niet toe
Een van mijn fundamentele bezwaren tegen softwareontwikkeling op basis van LLM's was dat de output van het model non-deterministisch is. Bij dezelfde invoerprompt is de output van een model niet gegarandeerd identiek bij elke run, althans onder normale omstandigheden.
Ik dacht dat dit een ernstige beperking was van AI-tools. Hoe zouden we dit onvoorspelbare bouwblok possibly kunnen gebruiken om systemen te creëren die nauwkeurige en exacte berekeningen vereisen?
Maar toen ik meer gewend raakte aan het gebruik van AI als mijn primaire middel om code te "schrijven", kreeg ik een openbaring: hoewel het resultaat exact moet zijn, is er niet slechts één juiste manier om daar te komen. De middelen waarmee je een correct resultaat behaalt, hoeven niet deterministisch te zijn!
Voorheen was ik gewend om gedrag te specificeren in termen van code: nauwkeurige sets instructies die op een voorspelbare manier compileren en worden uitgevoerd. In mijn hoofd behandelde ik de output van LLM's als code. Maar na verloop van tijd realiseerde ik me dat LLM's een fundamenteel andere rol spelen dan code in software engineering. LLM's, en hun respectievelijke harnesses, zijn actoren in een systeem. Code is slechts een output.
Het kostte me jaren om me comfortabel te voelen bij non-deterministische codegeneratie, maar als ik terugkijk, lijkt het zo overduidelijk dat programmeren altijd slechts een middel tot een doel was. Laten we programmeertalen nemen als voorbeeld, een onderwerp dat altijd tot verhit debat leidt onder programmeurs. Er zijn oneindig veel manieren om hetzelfde resultaat te bereiken via code, en dat is dan nog maar met één enkele programmeertaal! Er zijn honderden veelgebruikte talen, en het is mogelijk om een oplossing voor een specifiek probleem in vrijwel elke taal te schrijven.
Al jaren bouwen ontwikkelaars perfect functionerende applicaties met zeer verschillende combinaties van technologieën, talen en frameworks. De keuze voor de ene tech-stack boven de andere kan het voor een mens makkelijker hebben gemaakt om een bepaalde taak te voltooien. Maar duidelijk kunnen de middelen om tot dat resultaat te komen per implementatie enorm verschillen.
Nu we werken met probabilistische actoren, is het onze taak als ingenieurs, of managers (afhankelijk van hoe je ernaar kijkt), om de waarschijnlijkheidsruimte te verkleinen tot een klein, nuttig gebied. Hier komen al de gangbare LLM-trucs om de hoek kijken: context engineering, MCP, skills, harnesses, grafieken en geheugens zijn allemaal instrumenten die worden gebruikt om de hoeveelheid willekeur in de modeloutput te verminderen. Maar willekeur zal in enige vorm altijd aanwezig zijn, wat botst met het feit dat er nog steeds behoefte is aan het juiste antwoord, vooral bij het werken aan bedrijfskritieke software.
Laten we dus meer willekeur elimineren door non-deterministische output om te zetten in deterministische tools, door software te schrijven die agents kunnen gebruiken. Agents kunnen deze tools aanroepen om nauwkeurige, geteste en geautoriseerde operaties uit te voeren die bij elke uitvoering hetzelfde gewenste resultaat hebben. Als extra bonus, afhankelijk van de complexiteit van de tool, krijgen we hetzelfde correcte resultaat met aanzienlijk minder tokens door onze nieuwe, door agents gebouwde abstracties aan te roepen.
Ik heb dit patroon zowel in de industrie gezien, met tools zoals swamp.club, als in mijn eigen werk bij het beheren van productie-infrastructuur. Dit patroon is de moderne incarnatie van de samengestelde automatisering die mij oorspronkelijk naar DevOps en softwareontwikkeling trok. Maar in plaats van onze eigen tools te schrijven, kunnen we nu AI gebruiken om eigen abstracties te creëren en de AI instrueren deze te gebruiken terwijl het de fundamenten van onze nieuwe agentische softwaresystemen bouwt.
Ik vind het fascinerend dat we vandaag willekeur kunnen inzetten op een manier die willekeur in de toekomst vermindert. Uiteindelijk is het niet veel anders dan het schrijven van je eigen automatiseringen bovenop eerdere abstracties. Alleen is het nu de machine die ze aanroept, de output verwerkt en acties onderneemt, sneller dan mensen ooit zouden kunnen.
Non-Determinisme doet er niet toe
Een van mijn fundamentele bezwaren tegen softwareontwikkeling op basis van LLM's was dat de output van het model non-deterministisch is. Bij dezelfde invoerprompt is de output van een model niet gegarandeerd identiek bij elke run, althans onder normale omstandigheden.
Ik dacht dat dit een ernstige beperking was van AI-tools. Hoe zouden we dit onvoorspelbare bouwblok possibly kunnen gebruiken om systemen te creëren die nauwkeurige en exacte berekeningen vereisen?
Maar toen ik meer gewend raakte aan het gebruik van AI als mijn primaire middel om code te "schrijven", kreeg ik een openbaring: hoewel het resultaat exact moet zijn, is er niet slechts één juiste manier om daar te komen. De middelen waarmee je een correct resultaat behaalt, hoeven niet deterministisch te zijn!
Voorheen was ik gewend om gedrag te specificeren in termen van code: nauwkeurige sets instructies die op een voorspelbare manier compileren en worden uitgevoerd. In mijn hoofd behandelde ik de output van LLM's als code. Maar na verloop van tijd realiseerde ik me dat LLM's een fundamenteel andere rol spelen dan code in software engineering. LLM's, en hun respectievelijke harnesses, zijn actoren in een systeem. Code is slechts een output.
Het kostte me jaren om me comfortabel te voelen bij non-deterministische codegeneratie, maar als ik terugkijk, lijkt het zo overduidelijk dat programmeren altijd slechts een middel tot een doel was. Laten we programmeertalen nemen als voorbeeld, een onderwerp dat altijd tot verhit debat leidt onder programmeurs. Er zijn oneindig veel manieren om hetzelfde resultaat te bereiken via code, en dat is dan nog maar met één enkele programmeertaal! Er zijn honderden veelgebruikte talen, en het is mogelijk om een oplossing voor een specifiek probleem in vrijwel elke taal te schrijven.
Al jaren bouwen ontwikkelaars perfect functionerende applicaties met zeer verschillende combinaties van technologieën, talen en frameworks. De keuze voor de ene tech-stack boven de andere kan het voor een mens makkelijker hebben gemaakt om een bepaalde taak te voltooien. Maar duidelijk kunnen de middelen om tot dat resultaat te komen per implementatie enorm verschillen.
Nu we werken met probabilistische actoren, is het onze taak als ingenieurs, of managers (afhankelijk van hoe je ernaar kijkt), om de waarschijnlijkheidsruimte te verkleinen tot een klein, nuttig gebied. Hier komen al de gangbare LLM-trucs om de hoek kijken: context engineering, MCP, skills, harnesses, grafieken en geheugens zijn allemaal instrumenten die worden gebruikt om de hoeveelheid willekeur in de modeloutput te verminderen. Maar willekeur zal in enige vorm altijd aanwezig zijn, wat botst met het feit dat er nog steeds behoefte is aan het juiste antwoord, vooral bij het werken aan bedrijfskritieke software.
Laten we dus meer willekeur elimineren door non-deterministische output om te zetten in deterministische tools, door software te schrijven die agents kunnen gebruiken. Agents kunnen deze tools aanroepen om nauwkeurige, geteste en geautoriseerde operaties uit te voeren die bij elke uitvoering hetzelfde gewenste resultaat hebben. Als extra bonus, afhankelijk van de complexiteit van de tool, krijgen we hetzelfde correcte resultaat met aanzienlijk minder tokens door onze nieuwe, door agents gebouwde abstracties aan te roepen.
Ik heb dit patroon zowel in de industrie gezien, met tools zoals swamp.club, als in mijn eigen werk bij het beheren van productie-infrastructuur. Dit patroon is de moderne incarnatie van de samengestelde automatisering die mij oorspronkelijk naar DevOps en softwareontwikkeling trok. Maar in plaats van onze eigen tools te schrijven, kunnen we nu AI gebruiken om eigen abstracties te creëren en de AI instrueren deze te gebruiken terwijl het de fundamenten van onze nieuwe agentische softwaresystemen bouwt.
Ik vind het fascinerend dat we vandaag willekeur kunnen inzetten op een manier die willekeur in de toekomst vermindert. Uiteindelijk is het niet veel anders dan het schrijven van je eigen automatiseringen bovenop eerdere abstracties. Alleen is het nu de machine die ze aanroept, de output verwerkt en acties onderneemt, sneller dan mensen ooit zouden kunnen.