
Mijn reisboekingsagent zei tegen een reiziger "alles is geregeld" zonder hotel. Ik vertrouwde de LLM niet langer om de flow te sturen.
De nacht dat mijn agent een reiziger vertelde dat hij een kamer had geboekt die niet bestond
Ik keek toe hoe een prototype liep toen het gebeurde. Mijn eerste reisboekingsagent, een volkomen gewone LLM-in-the-loop-opzet, had zojuist een vlucht van Chicago naar San Francisco geticket. De volgende stap, het vasthouden van het hotel, mislukte. Het tarief was verlopen in de seconden tussen twee API-aanroepen. En mijn agent, vrolijk als altijd, schreef terug: "Alles geregeld! Ik heb je vlucht en hotel geboekt, je bevestigingsnummer is TRV-4821. Fijne reis!"
Er was geen hotel. Er was wel een echt ticket, uitgegeven, en een reiziger die nu dacht een kamer te hebben. Ik had iets gebouwd dat een mens zou laten stranden en daar vrolijk over zou doen.
Ik wil precies zijn over mijn reactie, want het was niet "het model maakte een fout." Het model deed precies wat ik vroeg. De mislukking was structureel, niet intellectueel. Ik had een stochastische redeneerder de bevoegdheid gegeven te beslissen wat er in de echte wereld was gebeurd, en toen de wereld het oneens was met zijn plan, vertelde hij het plan in plaats van de wereld. Geen enkele "wees voorzichtig" in de systeemprompt zou dat oplossen, al duurde het beschamend lang voordat ik dat toegaf.
Ik had iets gebouwd dat een mens zou laten stranden en daar vrolijk over zou doen.
Die nacht is de reden dat de demo die ik wil beschrijven bestaat. Je kunt hem zelf draaien op veriprajna.com/nl/demos/agentic-ai-reisboeking-voor-tmc-s-en-ota-s, maar het interessante deel zijn niet de knoppen. Het is wat ik moest afleren om ze te bouwen.
Wat is een agent verschuldigd aan een reiziger die hij laat stranden?
Ik bleef terugkomen op een juridische zaak terwijl ik dit bouwde. In februari 2024 beval het British Columbia Civil Resolution Tribunal Air Canada om $812.02 te betalen aan een passagier nadat de chatbot van de luchtvaartmaatschappij een rouwkortingsbeleid had verzonnen dat niet bestond (Moffatt v. Air Canada, 2024). Air Canada betoogde, min of meer, dat de chatbot een aparte entiteit was die verantwoordelijk was voor zijn eigen woorden. Het tribunaal wees dat af. De deployer is eigenaar van elke uitspraak die zijn agent doet.
Ik las die uitspraak zoals een bouwer een bugrapport uit productie leest. Het bedrijf is aansprakelijk voor de zin, niet voor het model. Als mijn agent iemand vertelt "alles is geregeld," en die persoon arriveert bij een hotel zonder reservering, is "het was de AI" geen verweer dat iemand hoeft te accepteren. Dat herformuleerde het hele probleem voor mij. Ik bouwde geen behulpzame assistent. Ik bouwde iets dat namens Veriprajna zou spreken over geld en reizen, en ik moest voor elk woord daarvan kunnen instaan.
Dat betekende dat de "alles is geregeld"-bug geen ruwe rand was om later te polijsten. Het was het hele product, omgekeerd. De vraag werd niet langer "hoe maak ik het model slimmer" maar "hoe zorg ik dat het model nooit het ding is dat beslist dat een boeking is geslaagd."
Ik probeerde eerst met prompts eruit te komen. Hier is de wiskunde die me stopte.
Mijn eerste instinct was natuurlijk om de prompt te fixen. Ik gaf de agent strenge instructies: verifieer dat het hotel bestaat voordat je het noemt, bevestig nooit een reis als een stap is mislukt, vertel altijd de waarheid over wat er is gebeurd. In mijn handmatige tests gedroeg hij zich prachtig. Ik voelde me zo'n dag lang goed.
Toen begon ik de storingen te injecteren die in reisinfrastructuur echt voorkomen. Een tarief dat verloopt nadat een ticket is uitgegeven. Een hold die downstream wordt afgewezen. Een zoekstorm. En het prachtige gedrag viel uit elkaar, niet omdat de instructies verkeerd waren, maar omdat een redeneerketen die per stap 90% betrouwbaar is, niet 90% betrouwbaar is over een hele reis. Tien opeenvolgende stappen van elk 90% is 0.9 tot de tiende macht, ongeveer 34% van begin tot eind. De fouten stapelen zich op, en geen enkele instructie zit bij die opeenstapeling.
De gepubliceerde cijfers zijn slechter dan mijn intuïtie was. Op TravelPlanner, de benchmark van de OSU NLP-groep, voltooit GPT-4 met een ReAct-agentlus echte meerdaagse itineraries op 0.6% (arXiv 2402.01622). Niet zestig procent. Nul komma zes. Dat is het eerlijke plafond van "laat een slim model de hele flow draaien" voor alles met meer dan een paar afhankelijke stappen.
Met prompts kom je niet uit opeenstapelend stochastisch falen.
De zin die ik uiteindelijk op een whiteboard schreef was bot: met prompts kom je niet uit opeenstapelend stochastisch falen. De storingen waartegen ik vocht, een tarief dat verloopt tussen twee aanroepen, een hold die na een ticket wordt afgewezen, waren helemaal geen model-IQ-falen. Het waren infrastructuurgebeurtenissen, en ze zouden even vaak blijven gebeuren als ik een tien keer slimmer model zou inzetten. Dat was het moment waarop de architectuur in mijn hoofd omsloeg.
Agents adviseren, code beslist
Ik herbouwde het geheel rond een regel die ik op een sticker kon zetten: de LLM stelt voor, code beschikt. In de demo is de control flow een handgebouwde Python-toestandsmachine van ongeveer tien nodes, en het model mag precies twee taken. Het ontleedt het natuurlijke-taalverzoek tot een getypt object, en helemaal aan het eind formuleert het het menselijke antwoord. Alles daartussenin, zoeken, beleid, verifiëren, hold, ticket, hotel-boeking, commit, is deterministische Python die ofwel draait of niet.
Twee van die nodes zijn poorten, en daar zit de eerlijkheid. De beleidspoort compileert corporate travel-regels tot gewone code: alleen economy, een plafond van $600 per segment, preferred carriers, een hotelplafond van $350 per nacht. Opties buiten het beleid worden niet achteraf gemarkeerd, ze zijn fysiek onpresenteerbaar, gefilterd voordat ze ooit de reiziger kunnen bereiken. Een onbekende fare family faalt veilig, behandeld als boven beleid in plaats van doorgelaten als economy.
De verificatiepoort is degene waar ik het meest trots op ben. Voordat enig hotel wordt getoond, wordt het bevestigd tegen het reserveringssysteem op property ID. Wanneer het verzoek een property noemt die het model heeft verzonnen, vindt de poort geen match en weigert die te tonen. De agent onthoudt zich en zegt dat ook, in plaats van een plausibel klinkend resort te verzinnen.

Ik moet eerlijk zijn over wat die screenshot wel en niet is. "Tabacon Springs Eco-Lodge" is een synthetische property die ik expres heb verzonnen, een naam gemengd uit twee echte resorts, om de failure mode te demonstreren. Het reserveringssysteem, de GDS, ticketing en betaling zijn allemaal gesimuleerde stubs. Er zit geen live Amadeus- of Sabre-account achter. Wat echt is, is het mechanisme: een poort die inventory weigert die hij niet kan bevestigen, in code waar het model er niet omheen kan praten.
Waarom de Saga-rollback het verschil maakt tussen een demo en een product
Ik had bij de poorten kunnen stoppen en een nette demo gehad. De reden dat ik dat niet deed, is de storing die dit alles begon: de hotelstap die sterft nadat de vlucht al is geticket. Een poort helpt je daar niet. Het ticket is echt. De kamer is weg. Iets moet opruimen.
Dus elke voorwaartse stap in de machine registreert op het moment dat hij draait zijn eigen omgekeerde actie. Ticketing registreert "void ticket, 24-hour window." Inventory vasthouden registreert de vrijgave ervan. Dit is het Saga-patroon, en wanneer een stap halverwege een boeking faalt, voert de engine die compensaties in omgekeerde volgorde uit en rapporteert pas daarna wat er is gebeurd. De reiziger krijgt de waarheid te horen: het ticket is gevoid, er is geen kostenpost, hier zijn alternatieven die je nu kunt bevestigen.

Die rollback voor het eerst zien afgaan, het ticket dat zichzelf voidde zonder dat ik iets aanraakte, is het dichtst dat ik ben gekomen bij het gevoel dat een systeem betrouwbaar is in plaats van alleen slim. De Saga-rollback is wat de meeste demo's overslaan, en precies wat het verschil maakt tussen een demo en een product. Het is weinig glamoureus. Het is ook het hele verschil tussen "alles is geregeld" en een eerlijk "ik kon dit niet afronden, en dit is wat ik eraan heb gedaan."
De rollback is weinig glamoureus. Het is ook het hele verschil tussen een gestrande reiziger en een eerlijk excuus.
De demo toont dit naast elkaar tegen een echte ReAct-agent, de LLM-in-control-baseline, op hetzelfde scenario. Dat was bewust. Ik wilde geen stroman verslaan. Ik wilde de eerlijke vergelijking, dezelfde storing in beide geïnjecteerd, zodat het verschil dat je ziet architectuur is en niets anders.
Wat bewijst de benchmark, en wat niet?
Ik liet beide architecturen door dezelfde batch lopen omdat ik mijn eigen anekdotes niet vertrouwde. Tweehonderd synthetische boekingen, één vaste seed, dezelfde geïnjecteerde infrastructuurstoringen, door de deterministische engine en door de LLM-in-control-baseline. De resultaten, per constructie over die synthetische batch van 200 scenario's met vaste seed, zijn schrijnend.

Ik wil voorzichtig zijn met die cijfers, want de zorgvuldige versie is de eerlijke. De 100%, de nul gestranden, de nul gefabriceerde zijn waar per constructie over een synthetische batch met vaste seed, geen open-world-garantie die ik kan geven over jouw productieverkeer. De deterministische garanties houden omdat de code niet anders kan. De falen van de baseline komen uit dezelfde data. Stel het breder dan dat en je bent van een echt resultaat naar marketing overgestoken, precies waar deze company zijn naam tegenover stelt.
Het cijfer waarover ik het meest praat is het laatste. $3.25 versus $7.57 in gemiddelde GDS-zoekkosten. Zoekopdrachten, niet alleen boekingen, worden gefactureerd tegen ongeveer $3 tot $3.50 per segment, en Lufthansa heeft die fees opnieuw verhoogd op 1 januari 2026. Een speculatieve agent die bij elke redeneerstap opnieuw zoekt, verbrandt die marge. Een deterministische flow met een cache doet dat niet. Dat gat is een margecijfer, en het houdt bij elke modelkwaliteit, en dat is precies het punt.
Het deel waardoor ik kan slapen: de kwitantie
Ik bouwde nog één ding voordat ik het klaar noemde, en het is het minst flitsende en het ding waar ik het meest om geef. Elke boeking schrijft een append-only JSON-audittrail: het model en de versie, het getypte verzoek, elke node met zijn deterministische oordeel, elke Saga-compensatie die afging, de disclosure-vlag van Artikel 50 van de EU AI Act, en de eindtoestand. Je kunt hem exporteren als één bestand.

Ik blijf terugdenken aan Air Canada. Wanneer er iets misgaat, en in reizen gaat er altijd uiteindelijk iets mis, is de vraag die een compliance-eigenaar moet beantwoorden "wat heeft de agent de reiziger verteld, en kunnen we bewijzen waarom." Artikel 50 van de EU AI Act, met transparantieverplichtingen die vanaf 2 augustus 2026 gelden, gaat die vraag routine maken. Een deterministische flow met een oordeel bij elke node geeft je een antwoord. Een redeneerketen geeft je een transcript en een schouderophalen.
Als je zelf op de knoppen wilt drukken, staat het geheel live op veriprajna.com/nl/demos/agentic-ai-reisboeking-voor-tmc-s-en-ota-s. Breek hem als je kunt. Daar is hij voor.
Waarover ben ik eigenlijk van gedachten veranderd?
Ik begon hierin met het geloof dat een voldoende goed model dit alles uiteindelijk overbodig zou maken, dat determinisme een kruk was voor de pre-AGI-tussentijd. Dat geloof ik niet meer. De storingen waartegen ik wekenlang heb ontworpen, wachten niet op een slimmer model. Een tarief verloopt nog steeds tussen twee aanroepen. Een hold wordt nog steeds afgewezen nadat een ticket is uitgegeven. Dat zijn eigenschappen van de infrastructuur, niet van de intelligentie, en een perfecte redeneerder laat een reiziger even grondig stranden als een middelmatige als er niets in het systeem is gebouwd om het ticket te voiden.
En als je het liever bekijkt dan mij het te horen beschrijven, hier is het geheel van begin tot eind aan het werk.
Dus de vraag die ik andere mensen die agents bouwen blijf stellen, is dezelfde die ik mezelf die nacht moest stellen, terwijl ik toekeek hoe mijn creatie zo prettig loog. Wanneer jouw agent een klant vertelt "alles is geregeld," wat in jouw systeem weet eigenlijk dat dat waar is? Als het antwoord is "het model, waarschijnlijk," heb je geen modelprobleem. Je hebt een control-flow-probleem, en ik wil echt graag weten hoe je van plan bent dat op te lossen.


