AI agents
Betrouwbare AI-agents: twaalf gaten die je productie raken
Maandagochtend bij een Nederlands logistiek bedrijf: de nieuwe invoice-chase-agent heeft 47 dubbele herinneringen verstuurd dit weekend. Hetzelfde gat als bij elke rollout — en nog elf erachter.

Maandagochtend bij een logistiek bedrijf van dertig man in Eindhoven. De operations manager opent haar inbox en vindt 47 herinneringen die de nieuwe invoice-chase-agent dit weekend naar dezelfde klant heeft gestuurd — elke zes minuten, beleefd als altijd. De klant heeft twee keer geantwoord met het verzoek om te stoppen.
De agent ging niet stuk. Hij deed precies wat hem was opgedragen. Een tool call naar de email service liep na dertig seconden in een timeout, de orchestrator markeerde de stap als mislukt, de retry policy schoot in actie, en in de volgende loop besloot het model dat de factuur nog steeds niet was gechased. De verzending ging elke keer wél door. Er was geen idempotency key.
We zien dit patroon bij vrijwel elk Nederlands mkb dat zijn eerste agentic systeem in productie zet. De bugs zijn niet exotisch. Het zijn dezelfde twaalf gaten, in ongeveer dezelfde volgorde. Dit is de veldgids die we nieuwe klanten op dag één meegeven.
Zo lees je deze lijst
De twaalf gaten vallen uiteen in drie lagen, gerangschikt naar wat het je team kost om ze dicht te zetten.
- Tier 1 — een ops manager en één engineer zetten deze dicht met één retry policy en een middag testwerk.
- Tier 2 — vraagt structureel werk: idempotency keys, dead-letter queues, schema-validatie. Eén goed weekend.
- Tier 3 — vraagt een complete replay log van alle tool calls. Die heb je sowieso nodig zodra een klant of auditor vraagt "wat heeft de AI precies gedaan op 14 maart om 03:17?". Ga je voor SOC 2 of ISO 27001, begin hier.
De volgorde telt zwaarder dan het aantal. Een team dat Tier 1 en Tier 3 sluit maar Tier 2 overslaat ziet er een week lang prima uit en levert dan een ochtend met 47 dubbele mails. Een team dat Tier 1 en Tier 2 sluit draait blij door tot het eerste auditverzoek binnenkomt. De lagen stapelen; één overslaan breekt de volgende.
Tier 1 — de vijf gaten die één retry policy dichtzet
Dit zijn de saaie. Ze veroorzaken ook de meeste avondtelefoontjes die we krijgen van klanten in hun eerste productiemaand.
1. Tijdelijke 5xx van de model provider
Anthropic, OpenAI en Google geven allemaal 503's onder belasting. Dat is geen bug in jouw code. Het gebeurt op een dinsdagmiddag om 14:30 CET wanneer half tech-Europa hetzelfde endpoint aanroept. Retry met exponential backoff en jitter. Cap op vier pogingen, dan luid falen. De provider docs zijn duidelijk over hoe je backoff hoort te doen — volg ze.
2. Timeouts op tool calls
Het REST-endpoint van je CRM antwoordt meestal binnen 200 ms. Eens per week doet het er negen seconden over. Heeft je agent harness een timeout van vijf seconden, dan concludeert het model dat de call faalde en probeert iets creatiefs. Zet tool-call timeouts op de 99e-percentiel latency van de onderliggende API, plus een marge. Dan retry. Dan fail.
3. Rate-limit 429's
De provider vertelt je in de Retry-After header precies hoe lang je moet wachten. Honoreer dat. We zijn de tel kwijt hoeveel orchestrators we hebben gezien die deze header negeren en meteen retryen, waarmee het probleem in de volgende pass verdubbelt.
4. Auth token die midden in de loop verloopt
Een agent loop die negentig seconden draait kan een kortlevende OAuth-token overleven. De token was geldig toen de loop startte, verlopen bij de derde tool call. Refresh op een 401, retry de call één keer, pas dan falen. De meeste token middleware libraries doen dit al — zorg dat de jouwe daar één van is, en test het door in staging een token handmatig te laten verlopen.
5. JSON-schema parse fouten
Het model geeft een tool call terug waarin het veld amount de string "€1.250,00" is in plaats van het getal 1250. Valideer tegen je schema en geef bij een fout de validatiefout terug aan het model met een heldere instructie. Negen van de tien keer corrigeert het model zichzelf in de tweede pass. De tiende keer log je de raw output en route je naar een mens; laat de loop niet doorgokken.
Een redelijke retry policy die alle vijf dekt ziet er ruwweg zo uit:
async function callTool(name: string, args: unknown, attempt = 0): Promise<ToolResult> {
try {
const validated = ToolSchemas[name].parse(args);
return await withTimeout(tools[name](validated), p99(name) * 1.5);
} catch (err) {
if (attempt >= 4) throw err;
if (err instanceof ZodError) {
return { kind: "validation_error", message: err.message };
}
if (err.status === 429) {
await sleep(parseRetryAfter(err) ?? backoff(attempt));
return callTool(name, args, attempt + 1);
}
if (err.status >= 500 || err.code === "TIMEOUT") {
await sleep(backoff(attempt));
return callTool(name, args, attempt + 1);
}
if (err.status === 401) {
await refreshToken();
return callTool(name, args, attempt + 1);
}
throw err;
}
}
Zo'n veertig regels en je sluit de eerste vijf gaten. Heeft je stack niet zoiets om elke tool call heen, schrijf het dan eerst, voordat je iets anders doet.
Tier 2 — de vier gaten die een retry policy stiekem erger maakt
Hier gaat het bij de meeste teams mis. Een retry policy zonder de volgende laag plumbing maakt van een eenmalige hapering een vermenigvuldigde ramp. De ochtend met 47 dubbele facturen valt in deze categorie.
6. Dubbele side-effects
Elke actie die de buitenwereld raakt — mail sturen, factuur aanmaken, naar Slack posten, een webhook aanroepen — heeft een idempotency key nodig. Genereer hem deterministisch uit de actie: hash de ontvanger, het factuurnummer, de datum. De onderliggende API dedupliceert vaak al op een key die je meegeeft; Stripe, Mollie en SendGrid doen dat alle drie. Doet hij dat niet, schrijf dan zelf een dunne ledger.
Kan je agent dezelfde mail twee keer sturen, dan gaat-ie dat doen. Niet "misschien" — "zal". De enige vraag is of jij het doorhebt voordat de klant het doorheeft.
7. Vastgelopen workflows
Een tool call hangt. Je timeout vangt hem op. Maar de workflow state machine wordt nooit bijgewerkt omdat de in_progress-rij in de database er nog steeds staat. Drie dagen later ontdek je dat de queue 600 vastgelopen jobs bevat en niemand het door had. Gebruik een watchdog-proces dat rijen scant die ouder zijn dan N keer de verwachte duur en ze óf retryt óf naar een dead-letter queue verplaatst voor een mens.
8. Hallucinaties in tool-argumenten
Het model vult als ontvanger jansen@klant.nl in terwijl het echte adres j.jansen@klant.nl is. Het schema valideert. De verzending faalt — of erger, slaagt, naar de verkeerde persoon bij het verkeerde bedrijf. Bind tool-argumenten aan entiteiten die je al hebt opgehaald. Wil de agent een klant mailen, dan accepteert de tool een klant-ID, geen willekeurig adres. Je orchestration code resolvet het ID naar een geverifieerd adres. Het model typt nooit zelf een mailadres.
9. Schrijven naar twee systemen zonder rollback
Je agent updatet de CRM, probeert dan een Slack-notificatie te plaatsen, en die Slack-call faalt. De CRM staat nu niet meer synchroon met wat de rest van het team denkt dat er is gebeurd. Gebruik een saga-pattern met compenserende acties, of, eenvoudiger, kanaliseer alle side effects door één event log dat downstream systemen consumeren. De agent schrijft één rij; al het andere is een projectie.
Tier 3 — de drie gaten die SOC 2 boven tafel haalt
Deze patch je niet. Die moeten je ontwerp in. Ga je in de komende achttien maanden verkopen aan een gereguleerde koper, een bank of een beursgenoteerd bedrijf, dan moet je ze vanaf dag één hebben. Retrofitten kost ongeveer vijf keer zoveel als ze meteen goed bouwen, omdat de replay log moet worden afgestemd op side effects die je al hebt verstuurd.
10. Reconstrueren wat de agent precies heeft gedaan
Een klant belt. "Jullie AI heeft mijn abonnement op 14 maart opgezegd. Daar heb ik niet om gevraagd." Kun je binnen vijftien minuten een compleet log produceren van elke model call, elke tool call, elke input, elke output en de menselijke goedkeuring (of het ontbreken daarvan) die tot de opzegging leidde? Zo nee, dan heb je geen audit trail. De CC7 control family van SOC 2 vraagt precies hierom, en "we duiken in Sentry" gaat het daar niet redden.
Het minimale schema dat we voor de replay log uitleveren: timestamp, request ID, parent span ID, modelversie, prompt hash, input arguments (PII gestript), volledige output, latency, retry count en de uitkomst van elke side-effect call die deze rij heeft veroorzaakt. Append-only. Eén rij per tool call. Opgeslagen op object storage met versionering en een legal-hold lock — S3 met Object Lock werkt; Cloudflare R2 met dezelfde setup ook. Elke agent-beslissing is reconstrueerbaar puur uit het log, ook nadat de orchestrator-code twee keer is herschreven.
11. PII in prompts en responses
Het context window van de agent bevat klantnamen, mailadressen, soms betaalgegevens. Elk van die tokens staat nu in de logs van de model provider, in jouw replay log, in je observability tool, en waarschijnlijk in je Sentry traces. Onder AVG artikel 32 ben je voor al die kopieën verantwoordelijk. Twee praktische ingrepen: strip PII voordat je logt (tokenize, sla de mapping op in een aparte KMS-versleutelde tabel), en zet zero-retention mode aan bij de provider waar dat kan.
12. State drift na een incident
De agent draaide zes uur lang tijdens een storing waarin je CRM verouderde reads teruggaf. De helft van zijn beslissingen is gebaseerd op verkeerde data. Na het incident moet je weten welke beslissingen je moet terugdraaien. Zonder een replay log dat per read gekoppeld is aan de versie van het bronsysteem op dat moment, kun je dat niet. Mét, kun je de agent opnieuw afspelen op de huidige data, de outputs diffen en alleen ingrijpen op de divergente rijen. Dezelfde machinerie laat je een nieuwe modelversie regressietesten tegen verkeer van vorige maand: speel de trace opnieuw af, kijk alleen naar de cases waar de actie verschilt, en bepaal of dat verschil een verbetering of een regressie is.
De volgorde waarin je dit aanpakt
Tier 1 in week één. Tier 2 voordat de tweede use-case live gaat. Tier 3 voor de eerste gereguleerde klant, of de eerste agent die geld kan verplaatsen. We hebben nog nooit een team gezien dat er spijt van had Tier 3 vroeg te doen; we hebben er meerdere gezien die er spijt van hadden het uit te stellen.
Twee dingen horen in je runbook voordat dit allemaal gaat tellen. Eén: benoem één mens als eigenaar van elk model-provider-account, met betaalmethode, billing alerts en rate-limit-verhogingen allemaal naar die persoon gerouteerd. De dag dat een junior engineer vertrekt en het provider-account in zijn persoonlijke Gmail staat, ligt de rollout stil. Twee: gebruik bij voorkeur kortlevende, gescoped credentials voor elke third-party tool die de agent aanroept. Long-lived API keys hardgecodeerd in de orchestrator zijn hoe een flink deel van de post-mortems van het komende decennium gaan beginnen: "de contractor die de integratie in 2024 opzette had geen tweefactor op de key vault".
Waar deze lijst vandaan komt
Toen we vorig kwartaal de AR-chase-agent bouwden voor een Rotterdamse groothandel, was het gat #6 dat de rollout bijna om zeep hielp. De retry policy was solide. De idempotency key niet. Uiteindelijk hebben we de key-generatie stroomopwaarts van de agent zelf gezet — de orchestrator stempelt een deterministische key voordat het model de taak überhaupt ziet, zodat een retry uit welke laag dan ook dezelfde key en dezelfde rij raakt. Het model mag de send-email tool nu honderd keer aanroepen binnen één loop; call twee tot en met honderd geven allemaal het receipt van de eerste verzending terug, en de inbox van de controller blijft stil.
Sta je op het punt om je eerste AI-agent in productie te zetten, teken dan vanmiddag je tool-call graph op een whiteboard en schrijf naast elke pijl de failure mode. De twaalf gaten vinden je in ongeveer bovenstaande volgorde. Beslis vandaag welke je sluit vóór go-live, en welke je accepteert als bekend risico tot Tier 3 staat.
Kern
Een retry policy koopt je een rustige eerste week. Een replay log koopt je de komende twee jaar.
FAQ
Wat is de kleinste betrouwbaarheidsingreep voordat je een agent naar productie stuurt?
Wikkel elke tool call in een retry policy die 5xx, 429, 401, timeouts en schema-validatiefouten afhandelt. Cap op vier pogingen. Dat alleen dekt al de meeste incidenten in de eerste maand.
Heb ik écht een replay log van tool calls nodig als ik geen SOC 2 nastreef?
Ja, vanaf de eerste keer dat een klant een agent-actie aanvecht. Audit is één afnemer van replay logs; debugging, incident response en nieuwe tools toevoegen gebruiken dezelfde data.
Moet het model idempotency keys genereren, of de orchestrator?
De orchestrator, stroomopwaarts van het model, deterministisch gehasht uit de identificerende velden van de actie. Modellen hallucineren keys. Deterministische hashes niet. Het model krijgt de key nooit te zien.
Is zero-retention mode bij de model provider genoeg voor AVG-compliance?
Het dekt één hop. Je moet PII nog steeds strippen vóór je replay log, observability tools en elke errortracker. Provider zero-retention ontheft de rest van je stack niet.