Waarom veel agentische systemen in productie falen en hoe je betrouwbare agents ontwerpt met toestandsmachines, duidelijke toolcontracten, retries en diepe observability.

Agentische systemen zijn applicaties waarbij een LLM niet alleen een prompt beantwoordt, maar bepaalt wat de volgende stap is: welke tools moeten worden aangeroepen, welke data opgehaald moet worden, welke stappen uitgevoerd worden en wanneer het “klaar” is. Ze combineren een model, een set tools (API's, databases, services), een plannings-/uitvoeringslus en infrastructuur die alles aan elkaar knoopt.
In een demo lijkt dit magisch: een agent bedenkt een plan, roept een paar tools aan en levert een perfect resultaat. Het gelukkige pad is kort, de latency laag en niets faalt tegelijk.
Onder echte workloads wordt dezelfde agent op manieren belast die de demo nooit zag:
Het resultaat: wankel gedrag dat moeilijk te reproduceren is, stille datacorruptie en gebruikersflows die af en toe hangen of voor eeuwig draaien.
Wankele agents schaden niet alleen "delight." Ze:
Dit artikel gaat over engineeringpatronen, niet over "betere prompts." We kijken naar toestandsmachines, expliciete toolcontracten, retry- en foutafhandelingsstrategieën, geheugen- en concurrencycontrole en observabilitypatronen die agentische systemen voorspelbaar maken onder belasting — niet alleen indrukwekkend op het podium.
De meeste agentsystemen zien er prima uit in één gelukkige demo. Ze falen als verkeer, tools en edge-cases samenkomen.
Naïeve orkestratie gaat ervan uit dat het model in één of twee calls "het juiste" doet. In echt gebruik zie je terugkerende patronen:
Zonder expliciete staten en eindcondities zijn dit soort gedragingen onvermijdelijk.
LLM-sampling, variabele latency en timing van tools creëren verborgen niet-determinisme. Zelfde input kan verschillende paden volgen, andere tools aanroepen of toolresultaten anders interpreteren.
Op schaal domineren toolproblemen:
Al deze zaken leiden tot schijnbare lussen, retries of foutieve eindantwoorden.
Wat zelden kapotgaat bij 10 RPS, faalt constant bij 1.000 RPS. Concurrency onthult:
Productteams verwachten vaak deterministische workflows, duidelijke SLA's en auditability. Agents, ongemodelleerd, bieden probabilistisch, best-effort gedrag met zwakke garanties.
Als architecturen dit verschil negeren — agents behandelen als traditionele services in plaats van stochastische planners — gedragen systemen zich onvoorspelbaar juist wanneer betrouwbaarheid het belangrijkst is.
Productieklare agents gaan minder over "slimme prompts" en meer over gedisciplineerd systeemontwerp. Een nuttige manier om erover te denken is: zie ze als kleine, voorspelbare machines die af en toe een LLM aanroepen, niet als mysterieuze LLM-blobs die af en toe je systemen aanraken.
Vier eigenschappen zijn het belangrijkst:
Je krijgt deze eigenschappen niet alleen van prompts. Je krijgt ze van structuur.
Het standaardpatroon waar veel teams mee beginnen is: "while not done, call the model, let it think, maybe call a tool, repeat". Dat is makkelijk te prototypen en moeilijk te opereren.
Een veiliger patroon is de agent te representeren als een expliciete workflow:
COLLECTING_INPUT, PLANNING, EXECUTING_STEP, WAITING_ON_HUMAN, DONE).Dit verandert de agent in een toestandsmachine waar elke stap inspecteerbaar, testbaar en replayable is. Vrije-lusgedrag voelt flexibel, maar expliciete workflows maken incidenten debugbaar en gedrag auditeerbaar.
Monolithische agents die "alles doen" zijn aantrekkelijk, maar creëren strakke koppeling tussen ongepaste verantwoordelijkheden: planning, retrieval, businesslogica, UI-orkestratie en meer.
Kies in plaats daarvan voor kleine, goed afgebakende agents of skills:
Elke skill kan zijn eigen toestandsmachine, tools en veiligheidsregels hebben. De compositielogica wordt dan een hogere-level workflow, niet een steeds groter wordende prompt binnen één agent.
Deze modulariteit houdt elke agent eenvoudig genoeg om over na te denken en laat je één capaciteit evolueren zonder de rest te destabiliseren.
Een nuttig mentaal model is de agent in drie lagen te splitsen:
Besluitbeleid (LLM prompts + model)
Encapsuleert hoe de agent de volgende acties kiest, geïnterpreteerd onder strikte beperkingen. Je moet het model kunnen wisselen, temperatuur aanpassen of prompts verfijnen zonder de systeemkoppelingen aan te raken.
Toestandsmachine / workflow-engine
Beheert waar je in het proces bent, welke transities mogelijk zijn en hoe voortgang persist wordt. Het beleid suggereert een stap; de toestandsmachine valideert en past deze toe.
Toolinglaag
Implementeert wat daadwerkelijk in de wereld kan gebeuren: API's, databases, queues, externe services. Tools bieden smalle, goed-getypte contracten en handhaven autorisatie, rate limits en inputvalidatie.
Door deze scheiding af te dwingen, vermijd je de valkuil businesslogica in prompts of toolbeschrijvingen te verbergen. De LLM wordt een beslissingscomponent binnen een duidelijke, deterministische schaal — niet de schaal zelf.
De meest betrouwbare agentische systemen zijn niet de meest indrukwekkende demo's — het zijn degene waarvan je gedrag op een whiteboard kunt uitleggen.
Concreet:
Deze voorkeur voor kleine, composeerbare en goed-gestructureerde agents maakt het mogelijk systemen te vergroten zonder dat ze instorten onder hun eigen complexiteit.
De meeste agentimplementaties beginnen als een lus van "think, act, observe" rond een LLM-call. Dat is prima voor demo's, maar het wordt snel ondoorzichtig en broos. Een betere aanpak is de agent te behandelen als een expliciete toestandsmachine: een eindige set staten met goed gedefinieerde transities die door events worden getriggerd.
In plaats van het model impliciet te laten beslissen wat te doen, definieer je een klein state-diagram:
Transities tussen deze staten worden getriggerd door getypte events zoals UserRequestReceived, ToolCallSucceeded, ToolValidationFailed, TimeoutExceeded of HumanOverride. Elk event, plus de huidige staat, bepaalt de volgende staat en acties.
Dit maakt retries en timeouts eenvoudig: koppel policies aan individuele staten (bijv. CALL_TOOL retryt 3 keer met exponential backoff, PLAN retryt mogelijk helemaal niet) in plaats van retrylogica verspreid over de codebase.
Persist de huidige staat en minimale context in een externe store (database, queue of workflow-engine). De agent wordt dan een pure functie:
next_state, actions = transition(current_state, event, context)
Dit maakt mogelijk:
Met een toestandsmachine is elke stap van het gedrag expliciet: in welke staat het zich bevond, welk event plaatsvond, welke transitie afging en welke bijwerkingen werden geproduceerd. Die duidelijkheid maakt debuggen sneller, vereenvoudigt incidentonderzoeken en creëert een natuurlijke audittrail voor compliance-reviews. Je kunt uit logs en stategeschiedenis bewijzen dat bepaalde risicovolle acties alleen vanuit specifieke staten en onder gedefinieerde condities worden uitgevoerd.
Agents gedragen zich veel voorspelbaarder wanneer tools minder lijken op "API's verborgen in proza" en meer op goed ontworpen interfaces met expliciete garanties.
Elke tool zou een contract moeten hebben dat dekt:
InvalidInput, NotFound, RateLimited, TransientFailure) met duidelijke semantiek.Bied dit contract gestructureerd aan het model aan, niet als een muur van tekst. De agent-planner moet weten welke fouten retrybaar zijn, welke gebruikersinterventie vereisen en welke de workflow moeten stoppen.
Behandel tool I/O als elke andere productie-API:
Dit laat je prompts vereenvoudigen: in plaats van uitgebreide instructies vertrouw je op schema-gedreven guidance. Duidelijke constraints verminderen gehallucineerde argumenten en onzinnige toolreeksen.
Tools evolueren; agents moeten niet breken bij elke verandering.
v1, v1.1, v2) en pin agents aan een versie.Planningslogica kan dan veilig agents en tools van verschillende volwassenheidsniveaus mixen.
Ontwerp contracten met gedeeltelijke fouten in gedachten:
De agent kan dan aanpassen: de workflow voortzetten met verminderde functionaliteit, de gebruiker om bevestiging vragen of naar een fallback-tool schakelen.
Toolcontracten zijn een natuurlijke plek om veiligheidslimieten te encoderen:
confirm: true).Combineer dit met server-side checks; vertrouw nooit alleen op het model om zich "fatsoenlijk" te gedragen.
Als tools duidelijke, gevalideerde en versieerde contracten hebben, worden prompts korter, orkestratielogica eenvoudiger en debugging veel makkelijker. Je verplaatst complexiteit van broze natural-language instructies naar deterministische schema's en policies, wat aantal gehallucineerde toolaanroepen en onverwachte bijwerkingen vermindert.
Betrouwbare agentische systemen gaan ervan uit dat alles uiteindelijk zal falen: modellen, tools, netwerken, zelfs je eigen coördinatielaag. Het doel is niet falen te vermijden, maar het goedkoop en veilig te maken.
Idempotentie betekent: het herhalen van hetzelfde verzoek heeft hetzelfde extern zichtbare effect als het één keer doen. Dit is cruciaal voor LLM-agents die vaak toolaanroepen opnieuw doen na gedeeltelijke fouten of ambigue reacties.
Maak tools idempotent door ontwerp:
request_id. De tool slaat dit op en geeft hetzelfde resultaat terug als hij dezelfde ID opnieuw ziet.Gebruik gestructureerde retries voor transitieve fouten (timeouts, rate limits, 5xx): exponential backoff, jitter om thundering herds te vermijden en een strikt max attempts. Log elke poging met correlatie-IDs zodat je agentgedrag kunt traceren.
Voor permanente fouten (4xx, validatiefouten, business-regel overtredingen) retry niet. Toon een gestructureerde fout aan de agentpolicy zodat die het plan kan herzien, de gebruiker kan vragen of een andere tool kan kiezen.
Implementeer circuit breakers op zowel agent- als toollagen: na herhaalde fouten blokkeer tijdelijk calls naar die tool en faal snel. Koppel dit aan goed gedefinieerde fallbacks: gedegradeerde modi, gecachte data of alternatieve tools.
Vermijd blinde retries vanuit de agentlus. Zonder idempotente tools en duidelijke foutklassen vermenigvuldig je bijwerkingen, latency en kosten.
Betrouwbare agents beginnen met helder denken over wat state is en waar het leeft.
Behandel een agent zoals een service die een request afhandelt:
Het mengen van beide leidt tot verwarring en bugs. Bijvoorbeeld: ephemere toolresultaten in "geheugen" stoppen zorgt ervoor dat agents verouderde context hergebruiken.
Je hebt drie hoofdopties:
Een goede regel: de LLM is een stateless functie over een expliciet state-object. Persist dat object buiten het model en genereer prompts op basis daarvan.
Een veelvoorkomend faalpatroon is conversatielogs, traces of ruwe prompts als de-facto geheugen te gebruiken.
Problemen:
Definieer in plaats daarvan gestructureerde geheugenschema's: user_profile, project, task_history, enz. Leid logs af van state, niet andersom.
Wanneer meerdere tools of agents hetzelfde entiteit updaten (bv. een CRM-record of taakstatus), heb je basisconsistentiecontrols nodig:
Voor hoogwaarde-operaties leg een decision log vast apart van het conversatielog: wat veranderde, waarom en op basis van welke inputs.
Om crashes, deploys en rate limiting te overleven, moeten workflows resumeable zijn:
Dit maakt ook time travel debugging mogelijk: je kunt precies inspecteren en reproduceren welke state naar een slechte beslissing leidde.
Geheugen is evenzeer een aansprakelijkheid als een hulpmiddel. Voor productie-agents:
Behandel geheugen als een productoppervlak: ontworpen, geversioneerd en beheerd — niet als een steeds groter wordende tekstdump die aan je agent vastzit.
Agents lijken sequentieel op een whiteboard maar gedragen zich als gedistribueerde systemen onder echte belasting. Zodra je veel gelijktijdige gebruikers, tools en background-jobs hebt, krijg je racecondities, dubbel werk en ordering-problemen.
Veelvoorkomende faalmodes:
Je vermindert deze risico's met idempotente toolcontracten, expliciete workflow-state en optimistische of pessimistische locking op de datalaag.
SYNCHRONE request–response flows zijn simpel maar fragiel: elke afhankelijkheid moet up zijn, binnen rate limits en snel. Zodra agents uitwaaieren naar veel tools of parallelle subtaken, zet langlopende of bijwerkende stappen achter een queue.
Queue-gebaseerde orkestratie laat je:
Agents raken typisch drie klassen limieten:
Je hebt een expliciete rate-limit laag nodig met per-gebruiker, per-tenant en globale throttles. Gebruik token buckets of leaky buckets om beleid af te dwingen, en exposeer duidelijke fouttypes (bv. RATE_LIMIT_SOFT, RATE_LIMIT_HARD) zodat agents netjes kunnen terugschakelen.
Backpressure is hoe het systeem zichzelf beschermt onder stress. Strategieën omvatten:
Monitor signals voor verzadiging: queue-diepte, worker-utilisatie, model-/tool-foutenpercentages en latency-percentielen. Oplopende queues gecombineerd met stijgende latency of 429/503-fouten zijn je vroege waarschuwing dat agents hun omgeving overrunnen.
Je kunt een agent niet betrouwbaar maken als je niet snel twee vragen kunt beantwoorden: wat deed hij? en waarom deed hij dat? Observability voor agentische systemen draait om die antwoorden goedkoop en precies te maken.
Ontwerp observability zodat een enkele taak een trace heeft die doorloopt langs:
Plaats binnen die trace gestructureerde logs voor sleutelbeslissingen (routingkeuze, planrevisie, guardrail-triggers) en metrics voor volume en gezondheid.
Een nuttige trace bevat meestal:
Log prompts, toolinputs en outputs in gestructureerde vorm, maar voer ze eerst door een redaction-laag:
Houd ruwe content achter feature flags in lagere omgevingen; productie moet standaard geredacteerde weergaven gebruiken.
Minimaal moet je bijhouden:
Als incidenten plaatsvinden laten goede traces en metrics je verschuiven van "de agent voelt wankel" naar een precieze verklaring als: “P95-taken faalden in ToolSelection na 2 retries door een nieuw schema in billing_service,” waardoor diagnose van uren naar minuten daalt en je concrete knoppen krijgt om gedrag bij te stellen.
Tests van agents betekenen het testen van zowel de tools die ze aanroepen als de flows die alles aan elkaar rijgen. Behandel het als testen van gedistribueerde systemen, niet alleen prompttuning.
Begin met unit-tests op de toolgrens:
Deze tests hangen nooit af van de LLM. Je roept de tool direct aan met synthetische inputs en assert de exacte output of foutcontract.
Integratietests oefenen de agent-workflow end-to-end: LLM + tools + orkestratie.
Modelleer deze als scenario-gebaseerde tests:
Deze tests asserten toestadovergangen en toolaanroepen, niet elk token van de LLM-woordkeuze. Controleer: welke tools werden aangeroepen, met welke argumenten, in welke volgorde en welke eindstaat/resultaat de agent bereikte.
Om tests reproduceerbaar te houden, fixture zowel LLM-responses als tooloutputs.
Een typisch patroon:
with mocked_llm(fixtures_dir="fixtures/llm"), mocked_tools():
result = run_agent_scenario(input_case)
assert result.state == "COMPLETED"
Elke prompt- of schemawijziging moet een verplichte regressierun triggeren:
Schema-evolutie (velden toevoegen, types aanscherpen) krijgt eigen regressiegevallen om agents of tools te vangen die nog van het oude contract uitgaan.
Stuur nooit een nieuw model, beleid of routingstrategie direct naar productieverkeer.
In plaats daarvan:
Pas nadat offline-gates zijn gepasseerd mag een nieuwe variant naar productie, bij voorkeur achter feature flags en in een geleidelijke rollout.
Agentlogs bevatten vaak gevoelige gebruikersdata. Testen moet dat respecteren.
Codificeer deze regels in je CI-pipeline zodat geen testartifact kan worden gegenereerd of opgeslagen zonder anonimiseringchecks.
Agents in productie draaien lijkt meer op het runnen van een gedistribueerd systeem dan het uitrollen van een statisch model. Je hebt controles voor rollout, duidelijke betrouwbaarheiddoelen en gedisciplineerd change management nodig.
Introduceer nieuwe agents of gedragingen geleidelijk:
Ondersteun dit alles met feature flags en config-gedreven policies: routeringsregels, ingeschakelde tools, temperatuur, veiligheidsinstellingen. Wijzigingen moeten configureerbaar en onmiddellijk omkeerbaar zijn, niet alleen via code-deploys.
Definieer SLO's die zowel systeemgezondheid als gebruikerswaarde reflecteren:
Koppel deze aan alerts en run incidenten zoals voor elke productie-service: duidelijke eigenaarschap, runbooks voor triage en standaardmitigaties (rollback flag, traffic drain, safe-mode gedrag).
Gebruik logs, traces en conversatietranscripten om prompts, tools en policies te verfijnen. Behandel elke wijziging als een geversioneerd artefact met review, goedkeuring en rollback-mogelijkheid.
Vermijd stille prompt- of toolwijzigingen. Zonder change control kun je regressies niet correleren aan specifieke edits en verandert incidentresponse in giswerk in plaats van engineering.
Een productieklare agentensysteem profiteert van een duidelijke scheiding van verantwoordelijkheden. Het doel is de agent slim te laten zijn in beslissingen, maar dom in infrastructuur.
1. Gateway / API-edge
Eén ingangspunt voor clients (apps, services, UIs). Het handelt af:
2. Orchestrator
De orchestrator is het "ruggenmerg", niet het brein. Het coördineert:
De LLM(s) leven achter de orchestrator en worden gebruikt door de planner en door specifieke tools die natuurlijke taalverwerking nodig hebben.
3. Tooling- en storagelaag
Businesslogica blijft in bestaande microservices, queues en datasystemen. Tools zijn dunne wrappers rond:
De orchestrator roept tools aan via strikte contracten terwijl opslagsystemen de source-of-truth blijven.
Handhaaf auth en quota's bij de gateway; handhaaf veiligheid, data-access en policy in de orchestrator. Alle calls (LLM en tools) emitten gestructureerde telemetry naar een pipeline die voedt:
Een eenvoudiger architectuur (gateway → enkele orchestrator → tools) is makkelijker te opereren; het toevoegen van aparte planners, policy-engines en modelgateways vergroot flexibiliteit, tegen de prijs van meer coördinatie, latency en operationele complexiteit.
Je hebt nu de kerningrediënten voor agents die zich voorspelbaar gedragen onder echte belasting: expliciete toestandsmachines, duidelijke toolcontracten, gedisciplineerde retries en diepe observability. De laatste stap is deze ideeën omzetten in een herhaalbare praktijk voor je team.
Zie elke agent als een stateful workflow:
Wanneer deze onderdelen op één lijn liggen, krijg je systemen die gracieus degraderen in plaats van onder edge-cases te bezwijken.
Voordat je een prototype-agent aan echte gebruikers uitlevert, controleer:
Als een item ontbreekt, zit je nog in prototype-modus.
Een duurzaam opzet verdeelt doorgaans:
Zo kunnen productteams snel bewegen terwijl platformteams betrouwbaarheid, beveiliging en kostenbeheersing afdwingen.
Zodra je stabiele fundamenten hebt, kun je verkennen:
Voortgang hier moet incrementeel zijn: introduceer nieuwe leercomponenten achter feature flags, met offline evaluatie en strikte guardrails.
Het terugkerende thema is hetzelfde: ontwerp voor falen, geef de voorkeur aan duidelijkheid boven slimmigheid en iterateer waar je kunt observeren en snel terugdraaien. Met die constraints in place stoppen agentische systemen met eng prototype-gedrag en worden ze infrastructuur waarop je organisatie kunt vertrouwen.
Een agentisch systeem is een applicatie waarin een LLM niet slechts één prompt beantwoordt, maar bepaalt wat daarna moet gebeuren: welke tools moeten worden aangeroepen, welke data moet worden opgehaald, welke stap in een workflow moet draaien en wanneer het klaar is.
In tegenstelling tot een eenvoudige chatcompletion combineert een agentisch systeem:
In productie wordt de LLM één beslissingscomponent binnen een grotere, deterministische omhulling — niet het hele systeem.
Demo's draaien meestal op één gelukkige pad: één gebruiker, ideale toolgedragingen, geen timeouts, geen schema-drift en korte gesprekken. In productie krijgen agents te maken met:
Zonder expliciete workflows, contracten en foutafhandeling veroorzaken deze factoren loops, stalls, gedeeltelijk afgerond werk en stille fouten die in demo-omgevingen niet verschijnen.
Laat de LLM binnen een heldere structuur werken in plaats van een vrije-lus:
Modelleer de agent als een workflow met benoemde staten en getypte events in plaats van while not done: call LLM.
Typische staten kunnen zijn:
Ontwerp tools als echte productie-API's, niet als proza in prompts. Elke tool zou moeten hebben:
Ga ervan uit dat elke externe call soms faalt en ontwerp eromheen.
Belangrijke patronen:
Scheid korte-termijnstate van lange-termijngeheugen, en houd de LLM zelf stateless.
Zie je agentensysteem als een gedistribueerd systeem onder belasting, zelfs als elke stroom sequentieel lijkt.
Om betrouwbaar te blijven:
Je moet kunnen beantwoorden "wat heeft de agent gedaan?" en "waarom heeft hij dat gedaan?" voor elke taak.
Praktische eisen:
Behandel agents als evoluerende services, niet als statische prompts, en beheer ze met dezelfde discipline als andere productiesystemen.
Aanbevolen praktijken:
Dit maakt het mogelijk gedrag stap voor stap uit te leggen, te testen en te debuggen in plaats van op zoek te gaan naar ondoorzichtige “agent thoughts”-lussen.
PLAN – interpreteer het verzoek en maak een stapsgewijs planCALL_TOOL – roep een specifieke tool of batch van tools aanVERIFY – controleer outputs tegen eenvoudige regels of secundaire modelcontrolesRECOVER – handel fouten af met retries, fallbacks of escalatieDONE / FAILED – terminale uitkomstenEvents (bijv. ToolCallSucceeded, TimeoutExceeded) plus de huidige staat bepalen de volgende staat. Dit maakt retries, timeouts en foutafhandeling expliciet in plaats van verspreid over prompts of plakkerige code.
InvalidInput, NotFound, RateLimited, TransientFailureValideer inputs voordat je de tool aanroept en outputs erna. Versioneer je toolcontracten en pin agents aan specifieke versies zodat schemawijzigingen niet stilletjes flows breken.
request_id of business key en geven bij herhaalde calls hetzelfde resultaat terug.Dit houdt de betrouwbaarheid hoog zonder runaway-lussen, dubbele bijwerkingen of oncontroleerbare kosten.
Vermijd het gebruik van ruwe logs of volledige conversatiegeschiedenis als “geheugen”; leid in plaats daarvan compacte, gestructureerde records af met duidelijke bewaarbeleid en privacyregels.
Monitor queue-dieptes, latency-percentielen en 429/503-percentages om overbelasting te detecteren voordat het een outage wordt.
Met dit in place verschuift incidenttriage van "de agent voelt instabiel" naar het pinpointen van de exacte staat, tool en wijziging die de regressie veroorzaakte.
Zo kun je agents continu verbeteren terwijl je fouten beperkt, diagnoseerbaar en omkeerbaar houdt.