Alejandro Rioja.
AI Agents

Waarom je AI-Agent Blijft Falen in Productie (En Hoe je het Oplost)

Alejandro Rioja
Alejandro Rioja
6 min lezen
TL;DR

De meeste productieagentstoringen komen voort uit vijf oorzaken: breekbare prompts die randgevallen niet afhandelen, ontbrekende herhaalpoginglogica voor tijdelijke API-fouten, geen observeerbaarheid om te zien wat stuk gaat, ongecontroleerde lussen zonder uitstapconditie en tooldefinities die ambiguïs genoeg zijn dat het model de verkeerde kiest. Alle vijf zijn oplosbaar zonder modellen of frameworks te wijzigen.

Gratis nieuwsbrief

Elke woensdag. 28.400+ operators. Geen opvulling.

Inhoudsopgave

Bijgewerkt juni 2026.

TL;DR: De meeste productieagentstoringen komen voort uit vijf oorzaken: breekbare prompts die randgevallen niet afhandelen, ontbrekende herhaalpoginglogica voor tijdelijke API-fouten, geen observeerbaarheid om te zien wat stuk gaat, ongecontroleerde lussen zonder uitstapconditie en tooldefinities die ambiguïs genoeg zijn dat het model de verkeerde kiest. Alle vijf zijn oplosbaar zonder modellen of frameworks te wijzigen.

[Operator’s lezing] Ik run meer dan 30 agenten in productie. Ik heb al deze storingen gehad. De storingen die het meeste tijd kostten waren niet de exotische — het waren de saaie infrastructuurstoringen waarvan ik dacht dat ik ze had afgehandeld.

Storing 1: Breekbare prompts die op randgeval-invoer kapotgaan

Een prompt die werkt op je testgevallen zal falen op invoer die je niet had geanticipeerd. Dat is geen modellimitatie — het is een instructieschrijfprobleem.

Symptomen: De agent produceert zinloze uitvoer, roept het verkeerde tool aan of levert malformateerde JSON bij invoer die enigszins verschilt van wat je hebt getest.

Oorzaak: Je systeemprompt beschrijft alleen het gelukkige pad. Het zegt het model niet wat te doen wanneer gegevens ontbreken, malformateerd of dubbelzinnig zijn.

Oplossing: Voeg expliciete randgeval-afhandeling toe aan je systeemprompt:

code
If the input data is missing a required field, return:
{ "status": "error", "reason": "missing_field", "field": "<fieldname>" }
Do NOT attempt to infer or hallucinate missing values.

If you are uncertain which tool to call, call no tool and return:
{ "status": "clarification_needed", "question": "..." }

Het model volgt expliciete instructies voor randgevallen betrouwbaar. De fout is aannemen dat het de gelukkig-pad instructies zal generaliseren om de rommelige gevallen af te handelen.

Storing 2: Geen herhaalpoginglogica voor tijdelijke API-fouten

Elke externe API die je agent aanroept zal op een gegeven moment falen. De Claude API, de Meta Graph API, je database — ze geven allemaal 5xx-fouten terug, times out, of rate-limiten. Als je agent geen herhaalpoginglogica heeft, doodt één tijdelijke fout de hele run.

Symptomen: Agenten-runs falen willekeurig op verschillende stappen. De logs tonen een 503 of 429 zonder vervolgpoging.

Oplossing: Wikkel elke externe aanroep in een exponentieel-backoff herhalingpoging:

typescript
async function withRetry<T>(fn: () => Promise<T>, retries = 3, baseDelayMs = 500): Promise<T> {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return await fn();
    } catch (err: any) {
      const isTransient = err.status === 429 || err.status >= 500 || err.code === "ECONNRESET";
      if (!isTransient || attempt === retries) throw err;
      const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * 100;
      await new Promise((r) => setTimeout(r, delay));
    }
  }
  throw new Error("unreachable");
}

// Usage
const result = await withRetry(() => client.messages.create({ ... }));

Drie herhalingspogingen met exponentieel backoff behandelt ~99% van de tijdelijke storingen. Voeg dit toe aan elke externe aanroep en de helft van je willekeurige storingen verdwijnt.

Storing 3: Geen observeerbaarheid — je kunt niet zien wat stuk gaat

Dit is de meest voorkomende storingsmodus in productie en degene die het meeste tijd kost om te debuggen: de agent faalt stil of produceert verkeerde uitvoer, en je hebt geen idee waar in de keten het fout ging.

Symptomen: Je weet dat er iets mis is maar kunt de stap niet identificeren. Je voegt console.log-instructies toe en voert handmatig opnieuw uit om te proberen te reproduceren.

Oplossing: Gestructureerde logging bij elke stap, met een run-ID die de hele uitvoering traceert:

typescript
function createLogger(runId: string, agentName: string) {
  return {
    step: (step: string, data: object) =>
      console.log(JSON.stringify({ runId, agent: agentName, step, ts: new Date().toISOString(), ...data })),
    error: (step: string, err: unknown) =>
      console.error(JSON.stringify({ runId, agent: agentName, step, error: String(err), ts: new Date().toISOString() })),
  };
}

const log = createLogger(crypto.randomUUID(), "newsletter-agent");
log.step("fetch_topic", { topicId: topic.id, topic: topic.name });
// ... do work ...
log.step("draft_complete", { subject: draft.subject, wordCount: draft.body.split(" ").length });

Als je op Cloudflare Workers bent, gaan deze logs naar Logpush of Workers Tail. Als je lokaal of op een VPS draait, stuur ze naar een logaggregator. De gestructureerde JSON betekent dat je op runId kunt filteren om precies te zien wat er in een enkele run is gebeurd.

Storing 4: Ongecontroleerde lussen zonder uitstapconditie

Agentische lussen — waar het model tools aanroept en itereert totdat een conditie is voldaan — kunnen voor altijd draaien als die conditie nooit wordt voldaan of het model hem verkeerd identificeert.

Symptomen: Agent geeft honderden dollars uit aan API-kosten voor time-out. Of het voert dezelfde toolaanroep steeds opnieuw uit zonder voortgang te boeken.

Oplossing: Heb altijd een harde iteratielimiet en een voortgangscontrole:

typescript
const MAX_ITERATIONS = 10;
let iterations = 0;
let lastToolCallName = "";
let sameToolCallCount = 0;

while (true) {
  iterations++;
  if (iterations > MAX_ITERATIONS) {
    log.error("loop", { reason: "exceeded_max_iterations" });
    break;
  }

  const response = await client.messages.create({ ... });

  // Detect stuck loops: same tool called 3x in a row
  const toolCall = response.content.find(b => b.type === "tool_use");
  if (toolCall?.name === lastToolCallName) {
    sameToolCallCount++;
    if (sameToolCallCount >= 3) {
      log.error("loop", { reason: "stuck_loop", tool: toolCall.name });
      break;
    }
  } else {
    sameToolCallCount = 0;
    lastToolCallName = toolCall?.name ?? "";
  }

  if (response.stop_reason === "end_turn") break;
}

Dit vangt zowel de “te lang gelopen” als de “in de ronde gedraaid” storingsmodi. De limiet moet royaal genoeg zijn voor het gelukkige pad maar strak genoeg om de explosieradius te beperken.

Storing 5: Dubbelzinnige tooldefinities die het model verkeerd oplost

Als je het model twee tools geeft met overlappende beschrijvingen, zal het soms de verkeerde aanroepen. Dit is vooral gebruikelijk met tools zoals search_database vs get_record of send_email vs create_draft.

Symptomen: Het model roept de juiste categorie tool aan maar kiest de verkeerde specifieke. Of het roept een tool in de verkeerde context aan (gebruikt een schrijftool terwijl alleen lezen gepast was).

Oplossing: Maak tooldefinities wederzijds exclusief en voeg expliciet “wanneer NIET te gebruiken” toe:

typescript
const tools = [
  {
    name: "get_subscriber",
    description: "Fetch a single subscriber record by email. Use ONLY when you have a specific email address. Do NOT use for searching or listing subscribers.",
    input_schema: { ... }
  },
  {
    name: "search_subscribers",
    description: "Search subscribers by tag, segment, or status. Use when you need to find subscribers matching a criteria — NOT when you have a specific email address.",
    input_schema: { ... }
  }
];

De “NIET gebruiken wanneer X”-clausule is het deel dat de meeste mensen overslaan. Het is het belangrijkste deel. Modellen zijn beter in het volgen van expliciete negatieve beperkingen dan ze te infereren uit positieve beschrijvingen.

Nog één ding: test je agenten op slechte invoer

De meeste agenten worden alleen getest op schone, gelukkig-pad invoer. Productie heeft vuile invoer: lege strings, null-velden, Unicode-randgevallen, API-antwoorden die 200 teruggeven maar met een onverwacht schema.

Voeg een testsuite toe die expliciet uitoefent:

Als je agent op een van deze kapotgaat, los het dan op voor het live gaat. De productieomgeving zal elke aanname die je hebt gemaakt vinden.

De conclusie van de operator

De meeste agentstoringen in productie zijn infrastructuurproblemen die zich voordoen als modelproblemen. Voeg voor je van model wisselt herhalingspogingen, gestructureerde logging, luslimieten en expliciete randgeval-afhandeling toe aan je prompts. Los de dubbelzinnige tooldefinities op. Test dan op slechte invoer. Doe dat allemaal voor je het model de schuld geeft — in mijn ervaring is het model doorgaans het laatste dat veranderd moet worden.

Lees verder

Ontvang het AI-playbook in je inbox

Elke woensdag. 28.400+ operators. Geen opvulling.

↵ alle resultaten bekijken esc esc om te sluiten