Alejandro Rioja.
AI Agents Operations

Multi-Agent Orkestratiepatronen: Queues, State en Handoffs

Alejandro Rioja
Alejandro Rioja
7 min lezen
TL;DR

Betrouwbare multi-agentsystemen draaien niet om slimme prompts — ze draaien om de saaie discipline van gedistribueerde systemen: duurzame queues tussen agents, state buiten het model gehouden, en idempotente handoffs die retries overleven. Het model is de werker; de queue is de ruggengraat.

Gratis nieuwsbrief

Elke woensdag. 28.400+ operators. Geen opvulling.

Inhoudsopgave

Bijgewerkt juni 2026.

TL;DR: Betrouwbare multi-agentsystemen win je niet met slimme prompts — je wint ze met de saaie discipline van gedistribueerde systemen. Zet een duurzame queue tussen agents, houd de state buiten het model en maak elke handoff idempotent, zodat een retry niet dubbel kan handelen. Het model is de werker; de queue is de ruggengraat. Krijg die drie goed en orkestratie houdt op eng te zijn.

Blik van de operator: De meeste van mijn 100+ agents zijn enkelstaps. Degene die dat niet zijn — de pipelines die classificeren, dan verrijken, dan handelen — werden pas betrouwbaar toen ik stopte met denken in “promptketen” en begon te denken in “jobqueue met LLM-werkers”. Dit is architectuur, geen prompt engineering.

“Multi-agent” klinkt alsof de agents met elkaar praten. In de praktijk is de betrouwbare versie het tegenovergestelde: agents communiceren helemaal niet rechtstreeks. Ze laten berichten achter op een queue en pakken werk op uit een queue, en de orkestratie zit in het leidingwerk ertussen. Hier zijn de patronen die het volhouden in productie.

Patroon 1: Zet een duurzame queue tussen elke agent

De eerste neiging is om agent B rechtstreeks aan te roepen vanuit agent A. Doe het niet. Directe aanroepen koppelen de twee: is B traag, dan blokkeert A; faalt B, dan is A’s werk verloren; moet je B schalen, dan kan dat niet zonder A aan te raken.

In plaats daarvan rondt A zijn werk af en plaatst een bericht in de queue voor B. B is een aparte werker die de queue in zijn eigen tempo leegt.

typescript
// Agent A is klaar en draagt over via de queue — geen directe aanroep naar B
await env.ENRICH_QUEUE.send({
  traceId,
  type: "enrich",
  payload: classifierResult,
});
// A's job is gedaan. B pikt dit onafhankelijk op.

Op Cloudflare gebruik ik Workers Queues precies hiervoor — dezelfde primitieven achter de agent-stack die ik gebruik. De queue geeft je vier dingen gratis: buffering (B kan plat liggen zonder werk te verliezen), retries (mislukte berichten worden opnieuw bezorgd), backpressure (een piek komt in de queue in plaats van te crashen) en ontkoppeling (schaal of herimplementeer B zonder A aan te raken). Elk daarvan is iets dat je anders met de hand zou moeten bouwen en fout zou doen.

Patroon 2: Houd state altijd buiten het model

De meest voorkomende multi-agentbug is aannemen dat het model iets onthoudt tussen stappen. Dat doet het niet. Elke modelaanroep is stateless; het enige geheugen is wat je in de prompt zet. Dus de bron van waarheid voor “waar staat deze job in de pipeline” moet in een database leven, niet in een conversatie.

Ik houd één enkel jobrecord bij dat elke agent leest en bijwerkt:

typescript
interface JobState {
  traceId: string;
  stage: "classified" | "enriched" | "acted" | "done" | "failed";
  data: Record<string, unknown>;
  attempts: number;
  updatedAt: number;
}

Elke agent doorloopt dezelfde lus: de jobstate lezen, zijn werk doen, de nieuwe state schrijven, de volgende fase in de queue plaatsen. Het model houdt nooit de state — het ontvangt de relevante doorsnede als invoer en geeft een resultaat terug. Dit is wat het systeem herstartbaar maakt: sterft een werker midden in een job, dan zegt het staterecord nog steeds precies waar het stond, en het opnieuw bezorgde queuebericht pikt daar weer op. Het maakt debuggen ook behapbaar, want de statetabel is een opvraagbaar register van de reis van elke job — dezelfde instrumentatie-mindset uit hoe ik meet of een agent echt werkt.

Patroon 3: Maak elke handoff idempotent

Queues garanderen minstens-één-keer bezorging, niet precies één keer. Dat betekent dat een bericht twee keer bezorgd kan worden — netwerkhaperingen, retries, herimplementaties. Is de actie van je agent niet idempotent, dan handelt een dubbele bezorging dubbel: twee bevestigingsmails, twee boekingen, twee afschrijvingen. Dit is de naarste klasse orkestratiebug, en het is degene die teams in productie ontdekken.

De oplossing is om acties idempotent te maken met een sleutel:

typescript
async function handleEnrich(msg: QueueMessage, env: Env) {
  const job = await getJob(env, msg.traceId);
  if (job.stage !== "classified") {
    // Al voorbij deze fase verwerkt — dit is een dubbele bezorging. Overslaan.
    return;
  }
  const result = await enrich(job.data);
  await advanceJob(env, msg.traceId, "enriched", result);
  await env.ACT_QUEUE.send({ traceId: msg.traceId, type: "act" });
}

De fasecontrole maakt de operatie veilig om twee keer uit te voeren: de tweede bezorging ziet dat de job al is gevorderd en doet niets. Voor externe neveneffecten (een mail versturen, een kaart belasten) geef je een idempotentiesleutel mee aan de downstream-API zodat die ook dedupliceert. Ga ervan uit dat elk bericht twee keer bezorgd wordt en ontwerp zo dat dat onschadelijk is — want vroeg of laat gebeurt het.

Patroon 4: Orkestrator vs choreografie — kies bewust

Er zijn twee manieren om de flow te bedraden, en de juiste keuze hangt af van de complexiteit.

Choreografie (mijn standaard): elke agent kent alleen de volgende stap en plaatst die in de queue. De flow ontstaat uit de keten. Eenvoudig, gedecentraliseerd, makkelijk uit te breiden — voeg een fase toe door een queue in te voegen. Het nadeel is dat geen enkele plek de hele flow beschrijft, dus een complexe pipeline kan moeilijk te doorgronden worden.

Orkestratie (een centrale coördinator): één orkestrator bezit de flow, roept elke agent om de beurt aan en beslist op basis van resultaten wat er volgt. De hele flow leeft op één leesbare plek en de vertakkingslogica is expliciet. De prijs is een centraal component dat zelf duurzaam moet zijn — is de eigen state van de orkestrator niet geëxternaliseerd (Patroon 2), dan wordt hij het enkele punt van falen.

Mijn regel: choreografie tot de vertakking complex wordt, dan een duurzame orkestrator. Een lineaire pipeline van drie fasen is choreografie. Een flow met conditionele routering, parallelle fan-out en joins wil een orkestrator wiens state in de database leeft, zodat hij na een crash kan hervatten.

Patroon 5: Fan-out, fan-in zonder stukken te verliezen

Wanneer één job N parallelle subtaken voortbrengt (50 records verrijken, 20 documenten samenvatten) en je op ze allemaal moet wachten voordat je doorgaat, heb je een join nodig. De truc is een teller in de jobstate:

  1. De parent plaatst N child-berichten in de queue en schrijft expected: N, completed: 0 naar het jobrecord.
  2. Elk child doet zijn werk en verhoogt atomair completed.
  3. Het child dat completed opvoert tot gelijk aan expected plaatst de volgende fase in de queue.

De atomaire ophoging is dragend — zonder haar kunnen twee gelijktijdig eindigende children allebei denken dat ze niet de laatste zijn, en vuurt de join nooit. Gebruik een teller die de datastore atomair kan ophogen, of een transactie. Dit patroon laat je het dure midden van een pipeline parallelliseren (vaak Haiku-goedkoop werk — zie de Haiku-vs-Sonnet-kostenberekening) terwijl je aan het eind een schone join behoudt.

Wat ik zou overslaan

Je hebt geen zwaargewicht agent-framework nodig om iets hiervan te doen. Queues, een statetabel en idempotentiesleutels zijn primitieven die elk platform al heeft. Ik heb teams gezien die naar uitgebreide multi-agentframeworks grepen om functies te krijgen die een queue gratis geeft, en een blackbox erfden die moeilijker te debuggen was dan het leidingwerk dat hij verving. Begin met de saaie primitieven. Grijp pas naar een framework wanneer je een specifieke pijn hebt gevoeld die het oplost.

De samenvatting: agents zijn stateless werkers, queues zijn de duurzame ruggengraat, state leeft in een database, en elke handoff is veilig om twee keer uit te voeren. Dat is het hele spel.

FAQ

Moeten agents elkaar rechtstreeks aanroepen of via een queue gaan?

Via een queue. Directe aanroepen koppelen agents — het falen of de traagheid van de een plant zich voort naar de ander, en je kunt niet onafhankelijk schalen of herimplementeren. Een duurzame queue geeft je buffering, retries, backpressure en ontkoppeling gratis.

Waar moet multi-agentstate leven?

Buiten het model, in een database, als een jobrecord dat elke agent leest en bijwerkt. Modelaanroepen zijn stateless, dus de bron van waarheid voor pipelinevoortgang moet extern zijn — dat is wat het systeem herstartbaar maakt na een crash.

Hoe voorkom ik dat een agent twee keer handelt op dezelfde job?

Maak handoffs idempotent. Controleer de fase van de job voordat je handelt en doe niets als hij al is gevorderd, en geef idempotentiesleutels mee aan externe API’s. Queues bezorgen minstens één keer, dus ga ervan uit dat elk bericht twee keer kan aankomen en ontwerp zo dat duplicaten onschadelijk zijn.

Heb ik een multi-agentframework nodig?

Meestal niet. Duurzame queues, een statetabel en idempotentiesleutels dekken de meeste productiebehoeften met primitieven die je platform al biedt. Adopteer pas een framework wanneer je op een concreet probleem stuit dat het uniek oplost, niet standaard.

Lees verder

Ontvang het AI-playbook in je inbox

Elke woensdag. 28.400+ operators. Geen opvulling.

↵ alle resultaten bekijken esc esc om te sluiten