← Blog

AI agents

Agent-hallucinaties: ons incidentrapport van acht regels

Vrijdag 16:47. Een agent vertelt een klant dat de factuur is betaald. Dat is niet zo. Om 17:02 staat het incidentrapport van acht regels in de map en kan het weekend beginnen.

Jacob Molkenboer· Oprichter · A Brand New Company· 4 jun 2026· 7 min
Gekreukt incidentformulier onder messing relais, groene memo, gestopt zakhorloge op 16:47, gebroken lakzegel, buispostkoker.

Vrijdag 16:47. Het on-call kanaal piept. Een agent die we bouwden voor een groothandel heeft een klant verteld dat de factuur is betaald. Dat is niet zo. De klant maakt een screenshot van het antwoord en stuurt het door naar de eigen crediteurenafdeling, die de finance-lead van de groothandel in de CC zet, die ons rustig en schriftelijk vraagt wat hier aan de hand is.

Om 17:02 staat het incidentrapport van acht regels in een gedeeld document. De on-call schrijft verder niets meer tot maandag. Geen fix, geen patch, geen prompt-tweak. De agent staat op pauze, de betrokken klant krijgt een mail van een mens, en het weekend begint op tijd.

Die tweede alinea is wat de meeste teams overslaan. Wij deden het ook niet altijd.

Waarom we überhaupt iets opschrijven

Hallucinaties bij agents in productie zijn niet zeldzaam. Het is een type fout met het ritme van een flaky integratietest: meestal weken geen, en dan ineens drie op een dag. De reflex is om de prompt te openen, de regel te zoeken die het mogelijk maakte, een "zeg X nooit onder welke omstandigheid dan ook" toe te voegen, opnieuw te deployen en door te gaan.

Die reflex is precies waarom de betrouwbaarheid van onze agents de eerste zes maanden vlak bleef toen we ze voor klanten gingen draaien. We pleisterden symptomen weg in een Slack-thread op vrijdagavond die niemand nog terugleest. Tegen de tijd dat dezelfde fout twee klanten verderop opdook, herinnerde niemand zich de eerste meer.

Dus we leenden het skelet van Google's blameless postmortem-format, stripten het tot het kleinste dat we nog konden uitstaan om in te vullen, en dwongen onszelf om het elke keer te schrijven, voordat we ook maar iets anders deden.

De acht regels

Het is een markdown-bestand in een gedeelde repo. Eén bestand per incident, met de naam YYYY-MM-DD-agent-shortname.md. Acht koppen, één of twee zinnen per kop. Het hele ding is binnen vijftien minuten geschreven, en dat is precies de bedoeling.

1. timestamp_utc:   2026-05-29T14:47:11Z
2. agent:           dunning-agent v3.4.1 (model: redacted)
3. trigger:         inbound email from finance@acme.example, subject "RE: invoice 8842"
4. output_verbatim: "Your invoice 8842 has been settled on 28 May."
5. ground_truth:    invoice 8842 status = OPEN, last reminder sent 27 May
6. blast_radius:    1 customer, 1 email, forwarded to 3 internal recipients at client
7. containment:     agent paused 14:51, client notified 14:55, customer apology sent 15:08
8. class:           tool-result misread (payments API returned an unrelated paid invoice)

Dat is het hele document. Geen analyse, geen fix-voorstel, geen schuldvraag, geen evaluatie van het model. Alleen wat er gebeurde, wat waar was, wie het zag, en wat we deden in het uur erna.

Regel 4 is de enige regel die lastig is. Mensen willen parafraseren. Ze willen het verzachten, samenvatten, context toevoegen. Wij staan dat niet toe. De output komt er letterlijk in, tussen aanhalingstekens, met de zin eromheen als die de betekenis verandert. Als we de exacte string niet kunnen reproduceren, schrijven we dat op regel 4 ("output niet bewaard, geparafraseerd uit screenshot van klant") en dat wordt vanzelf een eigen punt op de backlog: logging fixen.

Regel 8 is degene die op de achtergrond het meeste werk doet. We hebben een vaste woordenlijst voor foutklassen:

  • tool-result misread: de tool gaf de juiste data terug, de agent las het verkeerd.
  • tool-result trusted blindly: de tool gaf foute of verouderde data terug en de agent gaf het klakkeloos door.
  • prompt under-constrained: de agent deed iets wat de prompt niet verbood, maar wel had moeten verbieden.
  • prompt over-constrained: de agent weigerde of ontweek iets wat hij gewoon had moeten afhandelen.
  • retrieval miss: het juiste document stond in de kennisbank, maar haalde de context niet.
  • retrieval false positive: het verkeerde document kwam terug en werd als waarheid behandeld.
  • state confusion: de agent haalde twee gesprekken, twee klanten of twee threads door elkaar.
  • pure fabrication: geen tool in het spel, het model verzon een feit van A tot Z.

Acht klassen, met opzet. Ze passen op acht verschillende fixes, en ze houden de neiging tegen om elke hallucinatie weg te schrijven als "het model loog". Het model liegt zelden in de zin die mensen bedoelen. Bijna elk incident, als je er goed naar kijkt, is een van de eerste zeven.

Maandag

Maandagochtend openen we de week met dertig minuten op het incidentlog. Wie on-call was, neemt de rest mee door elk nieuw rapport. Drie vragen, op volgorde:

  1. Is dit een nieuwe klasse voor deze agent, of hebben we het eerder gezien?
  2. Zo ja, neemt de frequentie toe?
  3. Wat is de kleinste verandering die dit op staging zou hebben gevangen?

Die derde vraag is de dragende. Het is ook waar de meeste teams afslaan, want het eerlijke antwoord is bijna nooit "een betere prompt". Een betere prompt is de goedkoopste fix en de minst houdbare. Vier jaar deze agents draaien leert dat de houdbare fixes uiteenvallen in vier bakken, en welke bak het wordt, bepaalt regel 8.

Takeaway

Classificeer de fout voordat je hem oplost. De klasse op regel 8 kiest de bak op maandag. Sla de classificatie over en je grijpt elke keer naar een prompt-aanpassing, want prompt-aanpassingen voelen als voortgang.

Bak één: evals

Voor pure fabrication en prompt under-constrained voegen we een eval toe. Een bevroren testcase in onze eval-suite die precies het pad doorloopt dat faalde, met exact dezelfde input, tegen de huidige agent-versie. Als de eval vandaag slaagt maar volgende week niet, willen we weten op welke dag het kantelt. Als we de eval niet toevoegen, vertellen we onszelf dat het model in orde is, en dat is een hoop, geen meting.

Bak twee: guardrails

Voor tool-result trusted blindly en state confusion vertrouwen we het model niet om zichzelf te corrigeren. We bouwen een deterministische check buiten de agent-loop. Voor het incident hierboven is de guardrail ruwweg vijftien regels Python: voor elk uitgaand bericht waar "voldaan", "betaald" of "ontvangen" in staat, vragen we de payments API opnieuw voor dat specifieke factuur-ID en checken we de status. Faalt de check, dan wordt het bericht vastgehouden en wordt er een mens gepiept. De agent krijgt nooit een tweede kans om over een betaalde factuur te liegen.

PAID_WORDS = ("settled", "paid", "received", "cleared")

def guardrail_payment_claim(message: str, invoice_id: str) -> None:
    if not any(w in message.lower() for w in PAID_WORDS):
        return
    status = payments_api.get_invoice(invoice_id).status
    if status != "PAID":
        raise HoldForReview(
            f"agent asserted paid, API says {status} for {invoice_id}"
        )

Bak drie: retrieval

Voor retrieval miss en retrieval false positive kijken we naar hoe het document is geïndexeerd, niet naar hoe ermee gegenereerd is. De fout zit bijna altijd in chunking, embedding of een metadata-filter dat het juiste document stilletjes uitsloot. De prompt aanpassen is op dit punt schuiven met dekstoelen. We draaien de retrieval geïsoleerd opnieuw, met de oorspronkelijke query, en kijken welke documenten terugkomen en in welke volgorde. De fix zit in de index, niet in de prompt.

Bak vier: de prompt, eindelijk

Alleen prompt over-constrained wordt in de prompt opgelost, en zelfs daar zijn we voorzichtig. Een over-constrained prompt is meestal littekenweefsel van een eerder incident dat opgelost werd met een "doe X nooit"-regel. Die regels weghalen zonder de originele eval opnieuw te draaien is hoe je terugvalt op de fout die ze veroorzaakte. Dus bak vier loopt altijd terug naar bak één: pas de prompt aan, voeg de eval toe die bewijst dat de oude fout opgelost blijft.

Wat we niet doen

We shippen geen fix op vrijdag. We trainen niet opnieuw en wisselen geen modellen op basis van één incident. We gaan niet met de klant in discussie over of de output "echt telt" als hallucinatie. We schrijven geen lange Slack-post over hoe het gebeurde. De acht regels zíjn de uitleg.

We doen ook niet alsof het model hier vanzelf mee gaat ophouden. De AI Incident Database verzamelt al jaren publieke agent-fouten, en die curve buigt niet vanzelf naar beneden. Wat wel buigt, is het gat tussen het incident en het moment dat het team het ziet, en het gat tussen zien en een houdbare fix die landt. Allebei zijn proces-problemen, geen model-problemen.

Als het incidentlog van jouw agent een Slack-kanaal is, heb je geen incidentlog. Je hebt een ventileerkanaal. Verplaats het deze week naar een bestand in een repo.

De maandag erna

Op de maandag na het incident stond de guardrail erin, was de eval groen, en kreeg regel 8 een nieuwe inschrijving in de lopende telling van het team: tool-result misread, inmiddels vijf incidenten over vier agents. Die telling was de aanleiding om een generieke "check status voor je status beweert"-wrapper voor elke agent te bouwen die met een transactionele API praat. Eén incident is een verhaal, vijf is een patroon, en een patroon verdient een platform-fix.

Toen we de dunning-agent voor die groothandel bouwden, liepen we ertegenaan dat de payments API bij een verkeerd geformatteerd ID de meest recent betaalde factuur teruggaf in plaats van een error. We hebben dat in de guardrail-laag opgelost, niet in de prompt, en diezelfde wrapper staat nu voor elk van onze AI-agents die met geld werkt.

Heb je een agent in productie en nog geen incident-format? Kopieer de acht regels hierboven vandaag nog naar een bestand incidents/README.md in de repo van je agent. Volgende vrijdag om 16:47 ben je blij dat het er staat.

Kern

Classificeer de hallucinatie voordat je 'm patcht. Regel 8 kiest de bak, en de bak bepaalt of de fix een eval, een guardrail, retrieval of een prompt is.

FAQ

Hoe lang mag het schrijven van een incidentrapport duren?

Onder de vijftien minuten. Duurt het langer, dan is het format te uitgebreid. De bedoeling is om vast te leggen wat er gebeurde voordat de drang om het te fixen het wint van de drang om het te noteren.

Waarom de agent op vrijdag pauzeren in plaats van fixen?

Een fix op vrijdagavond door een vermoeide engineer is hoe regressies in productie belanden. De agent pauzeren kost minder dan nog één fout bericht; de echte rekening maak je maandag op, met een fris team.

Wat zet je op regel 8 als je de klasse echt niet weet?

Zet 'unknown' en behandel het uitzoeken van de klasse als maandagtaak. Een onbekende klasse betekent meestal dat je logs niet genoeg vastleggen om de call te reconstrueren.

Delen we het incidentrapport met de betrokken klant?

Nee. Het rapport van acht regels is intern. Klanten krijgen een aparte, door een mens geschreven excuusmail met de details die ze nodig hebben. Het rapport bestaat om de volgende fix beter te maken.

ai agentsoperationsworkflowarchitectureprocess automation

Iets bouwen?

Start een project