Een visuele metafoor die het contrast toont tussen een chaotisch probabilistisch systeem en een gestructureerde deterministische graaf die een AI-agent aanstuurt, toegespitst op het boeken van reizen.
Artificial IntelligenceSoftware EngineeringMachine Learning

GPT-4 faalde in 99,4% van de gevallen — dus lieten we het geen beslissingen meer nemen

Ashutosh SinghalAshutosh Singhal16 februari 202613 min

Het was bijna middernacht, en ik keek toe hoe onze agent voor de derde keer op rij een vlucht boekte naar de verkeerde stad.

Niet elke keer een andere verkeerde stad — dezelfde verkeerde stad. Delhi in plaats van Dehradun. De gebruiker had duidelijk "Dehradun" ingetypt. Het LLM had het correct geïnterpreteerd in zijn keten-van-redenering. En vervolgens, toen het de API-aanroep genereerde, verwisselde het de luchthavencode voor die van Delhi. Zelfverzekerd. Stilzwijgend. Drie keer.

Mijn medeoprichter zat aan de lijn. Hij zei: "Het weet het juiste antwoord. Kijk naar het redeneerspoor. Er staat letterlijk Dehradun. En dan doet het iets anders."

Dat was de nacht waarop ik ophield te geloven dat betere prompts ons zouden redden.

We hadden een AI-agent gebouwd voor het boeken van reizen — het soort dat communiceert met Global Distribution Systems zoals Amadeus en Sabre, die eeuwenoude backends uit het mainframetijdperk die elke vliegtuigreservering ter wereld aandrijven. En we hadden gedaan wat iedereen in 2023 deed: GPT-4 verpakken in een dunne orkestratielaag, het tools geven, en bidden.

Het gebed werkte niet.

Het getal dat alles veranderde

Een paar weken na dat Dehradun-incident stuitte ik op de TravelPlanner-benchmark — een rigoureuze academische evaluatie die LLM's test op het plannen van meerdaagse reisschema's met echte beperkingen: budgetten, vervoer, dineren, accommodatie. Het soort werk dat een competente reisagent in twintig minuten doet.

GPT-4's algehele slagingspercentage: 0,6%.

Geen 60%. Geen 6%. Nul komma zes procent.

Ik las het drie keer. Toen haalde ik de methodologie erbij om zeker te weten dat ze geen fout hadden gemaakt. Dat hadden ze niet. Wanneer je het meest geavanceerde taalmodel ter wereld vraagt om een reis te plannen die een budget respecteert, vluchten koppelt aan hotels aan restaurants, en geen elementaire temporele logica schendt — faalt het 99,4% van de tijd.

Toen GPT-4 werd gevraagd om reizen te plannen met beperkingen uit de echte wereld, slaagde het in 0,6% van de gevallen. Een neuro-symbolische agent die hetzelfde probleem oploste scoorde 97%.

Het systeem dat 97% scoorde gebruikte geen slimmer model. Het gebruikte een fundamenteel andere architectuur — een waarin het LLM het verzoek van de gebruiker vertaalde naar gestructureerde data, en vervolgens deed een deterministische solver het eigenlijke plannen. Het LLM was de vertaler. De code was het brein.

Die benchmark bevestigde niet alleen onze frustratie. Het gaf ons een blauwdruk.

Waarom blijft jouw AI-agent falen?

Een infographic die het exponentiële betrouwbaarheidsverval van geketende LLM-stappen toont — het "Chain of Probability"-probleem — met concrete slagingspercentages bij 1, 5 en 10 stappen.

Dit is het punt waar niemand in de "AI-agent"-goudkoorts over wil praten: LLM's redeneren niet. Ze voorspellen.

Wanneer GPT-4 "besluit" om een zoek-API aan te roepen, voert het geen logica uit. Het voorspelt de statistisch meest waarschijnlijke volgende token op basis van patronen in zijn trainingsdata. In een gesprek is die voorspelling meestal goed genoeg. In een API-workflow van tien stappen waarbij elke stap afhangt van de exacte uitvoer van de vorige? Dan is het een ramp.

Ik ging dit het Chain of Probability-probleem noemen. Stel dat je LLM elke stap 90% van de tijd goed doet — een royale schatting voor complex toolgebruik. Dit is het rekensommetje:

  • 1 stap: 90% succes
  • 5 stappen: ~59% succes
  • 10 stappen: ~34% succes

Een vluchtboekingsworkflow — zoeken, filteren, selecteren, prijs bepalen, passagiersgegevens verzamelen, PNR aanmaken, valideren, betalen, ticketen — overschrijdt routinematig de tien stappen. Bij 34% theoretisch succes bouw je geen software. Je bouwt een gokautomaat.

En 34% is het plafond. De prestaties in de echte wereld zijn slechter vanwege twee verschijnselen die we telkens tegenkwamen in productie.

De hallucinatiecascade

Het eerste is wat ik de hallucinatiecascade noem. In een geketende architectuur wordt de uitvoer van Stap 2 de invoer voor Stap 3. Als het LLM vroeg een subtiele fout maakt — een aankomsttijd van een vlucht verkeerd leest als 14:00 uur in plaats van 02:00 uur — dan wordt die fout niet opgevangen. Hij plant zich voort. De agent boekt een hotelincheck voor de verkeerde dag op basis van de gehallucineerde tijd. De GDS-API kent de intentie van de agent niet, alleen zijn invoer, dus verwerkt het het verzoek met succes. De agent ziet een 200 OK-respons en versterkt zijn eigen fout.

Je eindigt met een "succesvol" uitvoeringsspoor dat een catastrofale uitkomst in de echte wereld oplevert. De agent denkt dat het geslaagd is. De klant komt op de luchthaven aan en ontdekt het tegendeel.

Het tweede verschijnsel is Context Drift. Terwijl de agent een meerstapsplan doorwerkt, vult het contextvenster zich met tussenliggende data — zoekresultaten, API-responsen, gebruikersberichten. Het aandachtsmechanisme van het model verspreidt zich steeds dunner over al die tokens. Tegen Stap 10 is het de budgetbeperking die het in Stap 2 correct had geïdentificeerd effectief "vergeten". De aandachtsscores, bepaald door de softmax-functie, verwateren over te veel irrelevante tokens.

Ik zag dit live gebeuren tijdens een demo voor een potentiële partner. De agent vond een hotel binnen budget in Stap 3. Tegen Stap 8, bij het selecteren van een restaurant, was het het overzicht op het resterende budget volledig kwijtgeraakt. Het beval een plek aan die de bestedingslimiet van de gebruiker met 40% overschreden zou hebben. De partner draaide zich naar me om en zei: "Dus het... vergeet het gewoon?"

Ja. Het vergeet het gewoon.

Wat gebeurt er wanneer AI een mainframe ontmoet?

Om echt te begrijpen waarom we een andere aanpak nodig hadden, moet je begrijpen hoe het is om met Global Distribution Systems te werken.

Amadeus, Sabre, Travelport — dit is de ruggengraat van de wereldwijde luchtvaart. Ze zijn ontworpen in het mainframetijdperk, en ze gedragen zich ernaar. Een vluchtboeking is geen enkele API-aanroep. Het is een eindige-toestandsmachine met een precieze reeks bewerkingen die niet herordend, overgeslagen of benaderd kunnen worden.

Je authenticeert en krijgt een sessietoken. Dat token moet in elke daaropvolgende header worden meegegeven — als het LLM het "vergeet" of een nieuw token hallucineert, gaat de hele transactiecontext verloren. Vervolgens zoek je naar vluchten, en de GDS retourneert enorme geneste JSON-payloads — vaak 50KB+ — met fare basis-codes, bagagemodellen, segmentreferenties. Het LLM moet een specifieke offerId uit die payload halen om verder te gaan. Maar LLM's zijn verliesgevende compressoren. Ze vatten samen. Ze kappen af. Ze "normaliseren" behulpzaam dataformaten die de GDS exact vereist, tot op de byte.

Op een nacht besteedden we vier uur aan het debuggen van een boekingsfout. Het LLM had een fare basis-code "gecorrigeerd" — een kleine letter veranderd in een hoofdletter, omdat dat er "juister" uitzag voor een model dat is getraind op Engelse tekst. De GDS wees het af met een cryptische foutmelding: ERR 1209 - SEQUENCE ERROR. Geen uitleg. Geen suggestie. Alleen een muur.

LLM's zijn verliesgevende compressoren. Wanneer ze data overdragen tussen API-aanroepen, "corrigeren" en "normaliseren" ze automatisch op manieren die de cryptografische integriteit breken die bedrijfssystemen vereisen.

En wanneer de GDS een fout retourneert zoals UC (Unable to Confirm), heeft het LLM geen idee wat het moet doen. Het is getraind om behulpzaam te zijn, dus interpreteert het de fout als een storing en probeert het exact hetzelfde verzoek opnieuw. Steeds opnieuw. En opnieuw. We keken toe hoe agents duizenden tokens verbrandden en tegen API-ratelimieten aanliepen, vastgelopen in wat we de "Loop of Death" begonnen te noemen — herhaaldelijk beukend tegen een muur die ze niet konden begrijpen.

De nacht waarop we de architectuur omdraaiden

Het keerpunt kwam tijdens een discussie.

We waren drie maanden bezig met het project. Mijn engineering lead wilde de prompts blijven verbeteren — langere systeemberichten, meer voorbeelden, keten-van-redenering-instructies. "We zijn zo dichtbij," bleef hij zeggen. "Als we de prompt maar beter structureren voor de PNR-aanmaakstap..."

Ik haalde onze logs erbij. In de voorgaande week hadden we 47 mislukte boekingspogingen gehad in onze testomgeving. Elf waren de Loop of Death. Negen waren gehallucineerde luchthavencodes. Zes waren het LLM dat probeerde een PNR vast te leggen voordat het verplichte "Received From"-veld werd toegevoegd — een volgordefout die geen enkele hoeveelheid prompting leek op te lossen, omdat het model geen inherent concept van temporele ordening had buiten wat het uit trainingsdata had opgenomen.

"We zijn niet dichtbij," zei ik. "We zitten op het plafond. De architectuur is het probleem."

Die week herschreven we alles. We stopten met het LLM te vragen om te orkestreren. We stopten met het te laten beslissen welke stap er als volgende kwam. We stopten met het voeren van ruwe GDS-responsen in de hoop dat het de juiste velden zou eruit halen.

In plaats daarvan bouwden we een graaf.

Voor de volledige technische uiteenzetting van wat we bouwden en waarom, schreef ik een gedetailleerd onderzoekspaper dat diep ingaat op de architectuur.

Hoe werkt neuro-symbolische AI eigenlijk?

Een gelabeld architectuurdiagram dat de tweelaagse neuro-symbolische splitsing toont — LLM als vertaler/interfacelaag versus deterministische graaf als uitvoerings-/managerlaag — met specifieke voorbeelden van wat elke laag afhandelt.

Het kernidee is bedrieglijk eenvoudig: control flow is geen taaltaak.

Beslissen wat je vervolgens moet doen in een strak bedrijfsproces zou geen kwestie van tokenvoorspelling moeten zijn. Het zou een kwestie van conditionele logica moeten zijn. De beslissing om "om betaling te vragen" zou alleen mogen afgaan als "vlucht is geselecteerd" EN "prijs is bevestigd." Dat is een booleaanse voorwaarde, geen probabilistische suggestie.

We splitsten ons systeem in twee lagen:

Het LLM werd de interfacelaag — de vertaler. Het ontleedt de natuurlijke taal van de gebruiker ("Ik wil een ochtendvlucht naar Dehradun, niet te duur") tot gestructureerde data: {origin: "DEL", destination: "DED", date: "2024-03-15", time_preference: "morning", budget: "economy"}. Dat is waar LLM's oprecht geweldig in zijn: het begrijpen van rommelige menselijke intentie.

De graaf werd de uitvoeringslaag — de manager. Het ontvangt die gestructureerde data en voert de bedrijfslogica uit met deterministische code. Hard-gecodeerde knopen. Getypeerde toestandsschema's. Conditionele randen die variabelen inspecteren, geen onderbuikgevoelens.

We gebruikten LangGraph om dit te bouwen, omdat het je de primitieven geeft die je nodig hebt: een gedeeld toestandsschema (ondersteund door een database, niet een chatgeschiedenis), knopen die gewoon Python-functies zijn, en conditionele randen die routeren op basis van werkelijke variabelewaarden.

Het LLM zou de werker moeten zijn — data extraheren, tekst samenvatten, JSON formatteren — terwijl de manager hard-gecodeerde software zou moeten zijn. Deze omkering van controle is het bepalende kenmerk van robuuste agentic systemen.

In onze architectuur kan het LLM letterlijk geen stappen overslaan. Het is fysiek onmogelijk voor het systeem om een boeking te proberen voordat de variabele selected_offer_id is gevuld in de toestand. Niet omdat we het LLM in een prompt hebben gezegd "doe dat niet," maar omdat de graafrand niet afgaat. Het is als proberen door een muur te rijden — de code staat het simpelweg niet toe.

Hoe ziet het daadwerkelijke systeem eruit?

Een gedetailleerde knoop-voor-knoop-stroomdiagram van de daadwerkelijke boekingspipeline die in het artikel wordt beschreven, met elk knoopstype (Collector, Retriever, Summarizer, Selector, Gatekeeper, Transactor), of het LLM of code gebruikt, en de opschort-/hervattingsmogelijkheid bij de Gatekeeper.

Laat me je meenemen door wat er gebeurt wanneer iemand zegt: "Boek een vlucht voor me van Mumbai naar Londen aanstaande dinsdag."

Eerst ontleedt een Collector-knoop — aangedreven door een LLM — die zin tot gestructureerde velden. Het gebruikt gestuurde generatie (JSON-modus) om een specifiek schema uit te voeren. Een Python-validator controleert of de luchthavencodes echt zijn. "Londen" is dubbelzinnig — Heathrow of Gatwick? — dus routeert de graaf naar een desambigueringsknoop. Het LLM raadt niet. Het vraagt.

Zodra we gevalideerde zoekcriteria hebben, roept een Retriever-knoop de Amadeus-API aan. Dit is pure code. Geen LLM betrokken. De respons komt terug, wordt gecachet in de toestand, en pas dan zet een Summarizer-knoop — een LLM — de top vijf resultaten om in een voor mensen leesbaar bericht. Maar het is strikt beperkt: het kan alleen data weergeven die aanwezig is in de gecachete JSON. Het kan geen voordelen verzinnen of prijzen wijzigen.

De gebruiker kiest een optie. Een Selector-knoop herleidt "de tweede" tot de specifieke offer_id-hash. Een Gatekeeper-knoop controleert bedrijfsregels — valt dit binnen het bedrijfsbeleid? Staat de vervoerder op de zwarte lijst? Als er een overtreding is, schort de graaf op. Het bewaart zijn toestand in de database, stuurt een goedkeuringsverzoek naar een manager, en wacht. Uren later, wanneer de manager op "Goedkeuren" klikt, herlaadt de graaf de exacte toestand en hervat bij de boekingsknoop.

Ten slotte voert een Transactor-knoop de PNR-aanmaaksequentie uit — segmenten, passagiersgegevens, prijsstelling, vastleggen — in de exacte volgorde die de GDS vereist. Als de GDS een prijswijzigingswaarschuwing retourneert (gebruikelijk in reizen), stopt de knoop en vraagt de gebruiker om te bevestigen. Het boekt niet automatisch tegen het hogere tarief.

Elke knoopovergang wordt gelogd. Elke beslissing is traceerbaar. Een auditor kan het uitvoeringslog lezen en precies begrijpen waarom het systeem een specifieke vlucht heeft geboekt — niet door een wirwar van tokens te interpreteren, maar door een gestructureerd record te lezen: Node:Gatekeeper | Input: Price=1200 | Rule: Policy_Limit=1000 | Output: REJECT_NEED_APPROVAL.

Ik schreef over de volledige architectuur, inclusief de interactieve diagrammen, in de interactieve versie van het whitepaper.

Is dit niet gewoon... reguliere software-engineering?

Mensen vragen me dit voortdurend. "Dus je zegt dat we code moeten schrijven in plaats van AI te gebruiken? Revolutionair."

Nee. Ik zeg dat de AI-industrie zo bedwelmd is geraakt door de magie van taalmodellen dat het de laatste zestig jaar informatica is vergeten. Toestandsmachines, getypeerde schema's, conditionele vertakking, transactionele integriteit — dit zijn geen verouderde concepten. Ze zijn de reden dat jouw bank niet per ongeluk geld naar de verkeerde rekening overmaakt.

De neuro-symbolische aanpak is niet anti-AI. Het is pro-architectuur. We gebruiken LLM's agressief — voor het ontleden van intentie, voor desambiguering, voor samenvatting, voor het aanpakken van het werkelijk moeilijke probleem van begrijpen wat een mens bedoelt wanneer hij iets dubbelzinnigs typt. Maar we laten het LLM het stuur niet aanraken wanneer de auto op de snelweg rijdt.

Je kunt een chatbot bouwen die práát over het doen van werk, of je kunt een agent architecteren die het werk doet. Het verschil is de graaf.

Er is ook een kostenargument dat me verraste. Pure LLM-agents zijn duur — niet omdat inferentie per aanroep kostbaar is, maar vanwege de faallussen. Wanneer een agent vastloopt bij het opnieuw proberen van een GDS-fout door nieuwe parameters te hallucineren, verbrandt het duizenden tokens voordat het een time-out krijgt. Eén vastgelopen sessie kan $5-$10 aan API-credits kosten. Onze hard-gecodeerde foutafhandelaars vangen die fouten op tegen nul tokenkosten. En omdat we het LLM alleen de 5 relevante velden uit een GDS-respons van 50KB sturen in plaats van het geheel, verminderen we het contextvenstergebruik met ongeveer 90%.

Maar worden modellen uiteindelijk niet goed genoeg?

Misschien. Ik weet oprecht niet of GPT-6 of GPT-7 betrouwbaar genoeg zal zijn om API-workflows van tien stappen te orkestreren zonder guardrails. Maar ik weet twee dingen.

Ten eerste, zelfs als modellen dramatisch verbeteren, is het Chain of Probability-probleem wiskundig, niet technologisch. Als jouw model 99% betrouwbaar is per stap — een buitengewone prestatie — faalt een workflow van tien stappen nog steeds 10% van de tijd. Voor bedrijfstransacties is dat nog steeds onaanvaardbaar. De graaf elimineert dit volledig omdat de routering niet probabilistisch is.

Ten tweede, wachten tot modellen beter worden is een luxe die de meeste bedrijven niet hebben. Ze hebben agents nodig die nu werken, die nu auditeerbaar zijn, die nu voldoen aan de transparantievereisten van de EU AI Act. De neuro-symbolische aanpak wedt niet op de toekomst. Het bouwt voort op bewezen engineeringprincipes terwijl het de beste AI-mogelijkheden gebruikt die vandaag beschikbaar zijn.

De architectuur is het product

Ik heb in genoeg vergaderruimtes gezeten met investeerders en zakelijke kopers om te weten dat de AI-industrie begint te ontwaken. De vraag verschuift van "Wie heeft het slimste model?" naar "Wie heeft het meest robuuste systeem?" De demo's die verbluffen in een conferentiepraatje — die waarin een agent feilloos een vlucht boekt in een gecontroleerde omgeving — zijn goedkoop. Wat duur is, en wat ertoe doet, is iets bouwen dat bij het tienduizendste verzoek net zo betrouwbaar werkt als bij het eerste.

We betreden een tijdperk waarin de differentiatie niet het model zal zijn. Het zal de graaf zijn. Het toestandsschema. De foutafhandelaars. De conditionele randen. De saaie, rigoureuze, deterministische software-engineering die zich om de probabilistische magie heen wikkelt en voorkomt dat die het huis platbrandt.

De magie zat nooit in de prompt. Het zat altijd in de architectuur.

Related Research

Also Published On