Naar inhoud
lightbulb Welkom op de nieuwe kennisbank | We hebben de docs volledig vernieuwd met meer dan 160 features. Bekijk wat nieuw isarrow_forward

Multi-agent systemen bouwen

Hoe je een multi-agent systeem opzet met een message bus, gedeeld geheugen en een supervisor-agent die gespecialiseerde agents laat samenwerken.

Van enkelvoudige naar multi-agent systemen

Een enkelvoudige agent met veel tools schaalt slecht: de context groeit, het model raakt afgeleid en er is geen specialisatie. Multi-agent systemen lossen dit op door taken te verdelen over gespecialiseerde agents die samenwerken.

Het verschil met orkestratie zit in de mate van autonomie. Bij orkestratie stuurt een centrale orchestrator alle agents aan. In een echt multi-agent systeem communiceren agents ook met elkaar, handelen ze deels autonoom en delen ze geheugen.

warning

Multi-agent is niet gratis

Onafhankelijke multi-agent configuraties kosten al snel zo'n 50 tot 60 procent meer tokens, en sterk centrale opstellingen kunnen oplopen tot enkele honderden procenten overhead. Zet meerdere agents pas in als de taak echt baat heeft bij specialisatie, parallelisme of onderlinge kritiek. Voor de rest is één goede agent vaak sneller en goedkoper.

Welke topologie kies je

In de praktijk van 2026 domineren drie patronen. Kies bewust en houd het zo simpel mogelijk.

Patroon Hoe het werkt Wanneer
Supervisor (hiërarchisch) Een coördinator deelt taken uit aan workers en voegt de resultaten samen Duidelijke deeltaken met een eindredacteur
Orchestrator-worker Een orchestrator plant en roept workers aan, workers praten niet onderling Veruit het meest gebruikt in productie
Swarm (peer-to-peer) Agents praten direct met elkaar, geen centrale baas Onvoorspelbare, sterk verweven taken

Dit artikel werkt het supervisor-patroon uit, omdat dat het beste te bewaken en te debuggen is.

Systeem-architectuur

De opzet bestaat uit een supervisor die drie workers aanstuurt (research, schrijven, review), met daaronder een gedeeld geheugen dat alle agents kunnen lezen en schrijven.

  • Supervisor: maakt het plan, deelt stappen uit, bewaakt timeouts en voegt het eindresultaat samen.
  • Research-agent: verzamelt en verifieert informatie, schrijft tussenresultaten naar het geheugen.
  • Writer-agent: stelt de output op met de research uit het geheugen als context.
  • Reviewer-agent: controleert de output en kan om correcties vragen.
  • Gedeeld geheugen: een vector store voor semantisch zoeken plus een sleutel-waarde store voor tussenresultaten.

Message bus implementeren

De message bus is de ruggengraat. Alle berichten lopen hierlangs, zodat je elke taak achteraf kunt volgen.

type MessageHandler = (message: AgentMessage) => Promise<void>;

class AgentMessageBus {
  private handlers = new Map<string, MessageHandler[]>();
  private messageLog: AgentMessage[] = [];

  subscribe(agentId: string, handler: MessageHandler): void {
    const existing = this.handlers.get(agentId) ?? [];
    this.handlers.set(agentId, [...existing, handler]);
  }

  async publish(message: AgentMessage): Promise<void> {
    this.messageLog.push({ ...message, timestamp: new Date().toISOString() });
    const handlers = this.handlers.get(message.to) ?? [];
    await Promise.all(handlers.map(h => h(message)));
  }

  getLog(): AgentMessage[] {
    return [...this.messageLog];
  }
}

interface AgentMessage {
  id: string;
  from: string;
  to: string;
  type: "task" | "result" | "error" | "query";
  payload: Record<string, unknown>;
  timestamp?: string;
}
lightbulb

Voeg correlation IDs toe

Geef elke taak een correlation ID en zet die op elk bericht dat eruit voortvloeit. Zo filter je in de log per taak en zie je de hele keten van research naar schrijven naar review in één oogopslag.

Gedeeld geheugen

Het geheugen scheidt vluchtige tussenresultaten (sleutel-waarde) van herbruikbare kennis (vectoren). Elke schrijfactie legt vast welke agent de eigenaar is, wat helpt bij debuggen en bij conflictdetectie.

class SharedAgentMemory {
  private kvStore = new Map<string, { value: unknown; owner: string; timestamp: string }>();
  private vectorStore: VectorStore;

  async write(key: string, value: unknown, agentId: string): Promise<void> {
    this.kvStore.set(key, { value, owner: agentId, timestamp: new Date().toISOString() });
  }

  read(key: string): unknown {
    return this.kvStore.get(key)?.value;
  }

  async storeEmbedding(content: string, metadata: Record<string, unknown>, agentId: string): Promise<void> {
    await this.vectorStore.upsert({ content, metadata: { ...metadata, agent_id: agentId } });
  }

  async queryEmbeddings(query: string, limit = 5): Promise<SearchResult[]> {
    return this.vectorStore.search(query, limit);
  }
}

Supervisor-agent

De supervisor maakt een plan, voert de stappen in volgorde uit, geeft elke stap een timeout en herstelt waar mogelijk van fouten. Resultaten van eerdere stappen komen als context bij de volgende stap binnen.

class SupervisorAgent {
  private activeAgents = new Map<string, AgentStatus>();

  async supervise(goal: string, agents: Record<string, WorkerAgent>): Promise<string> {
    const plan = await this.createPlan(goal, Object.keys(agents));

    for (const step of plan.steps) {
      const agent = agents[step.agent];
      if (!agent) throw new Error(`Agent ${step.agent} niet gevonden`);

      this.activeAgents.set(step.id, { status: "running", start: Date.now() });

      try {
        const context = step.depends_on
          .map(dep => sharedMemory.read(`result:${dep}`) as string)
          .join("

");

        const result = await Promise.race([
          agent.execute(step.task, context),
          this.timeout(step.timeout_ms ?? 30000, step.id),
        ]);

        await sharedMemory.write(`result:${step.id}`, result, step.agent);
        this.activeAgents.set(step.id, { status: "done", start: Date.now() });
      } catch (err) {
        this.activeAgents.set(step.id, { status: "failed", start: Date.now() });
        const recovery = await this.handleFailure(step, err);
        if (!recovery) throw err;
      }
    }

    return await this.synthesize(goal, plan.steps);
  }

  private timeout(ms: number, stepId: string): Promise<never> {
    return new Promise((_, reject) =>
      setTimeout(() => reject(new Error(`Stap ${stepId} timed out na ${ms}ms`)), ms)
    );
  }
}
warning

Geef de supervisor een eigen prompt

Hergebruik nooit de system-prompt van een worker voor de supervisor. De supervisor heeft een andere rol: plannen, budget bewaken, stopcriteria afdwingen en deelresultaten samenvoegen. Geef elke worker een rol-specifieke prompt en lever de eerste taak aan als een gestructureerde brief met doel, gewenst formaat, beschikbare tools en grenzen.

Communicatie tussen agents

Naast de top-down aansturing kunnen agents elkaar bevragen via de bus. Een worker abonneert zich op zijn eigen ID en beantwoordt binnenkomende queries.

class WorkerAgent {
  constructor(
    private id: string,
    private bus: AgentMessageBus,
    private memory: SharedAgentMemory,
    private tools: AgentTool[]
  ) {
    bus.subscribe(id, this.handleMessage.bind(this));
  }

  private async handleMessage(message: AgentMessage): Promise<void> {
    if (message.type === "query") {
      const result = await this.executeQuery(message.payload.query as string);
      await this.bus.publish({
        id: crypto.randomUUID(),
        from: this.id,
        to: message.from,
        type: "result",
        payload: { result, query_id: message.id },
      });
    }
  }

  async execute(task: string, context: string): Promise<string> {
    return reactAgent(task, this.tools, this.buildSystemPrompt(), context);
  }
}

Stappenplan voor een eerste systeem

Zo bouw je het stap voor stap op

  1. Begin met één agent en de volledige taak. Werkt dat goed genoeg, stop dan: je hebt geen multi-agent nodig.
  2. Splits de taak in duidelijke rollen, bijvoorbeeld research, writer en reviewer, elk met eigen tools en prompt.
  3. Bouw de message bus met logging en correlation IDs, zodat elke taak volledig traceerbaar is.
  4. Voeg gedeeld geheugen toe: een sleutel-waarde store voor tussenresultaten en een vector store voor herbruikbare kennis.
  5. Zet de supervisor erop met een plan, timeouts per stap en een herstelpad bij fouten.
  6. Stel een budget in (maximaal aantal stappen, tokens of seconden) zodat een vastgelopen agent niet eindeloos doorloopt.
  7. Meet en verfijn: vergelijk kosten en kwaliteit met je eenvoudige uitgangspunt en houd alleen agents die zich terugverdienen.

Bestaande frameworks of zelf bouwen

In juni 2026 zijn LangGraph en CrewAI de meest gebruikte keuzes, naast AutoGen (AG2) en de OpenAI Agents SDK. LangGraph is de standaard voor stateful, controleerbare workflows met trace-niveau observability. CrewAI is de snelste weg naar een werkend prototype met een rol- en taakmetafoor en native ondersteuning voor MCP en het A2A-protocol (Agent-to-Agent). Bouw je zelf, dan houd je maximale controle en begrijp je precies wat er onder de motorkap gebeurt, maar je betaalt dat met meer eigen onderhoud.

Wanneer kies ik multi-agent in plaats van één orchestrator?

Kies multi-agent als agents ook onderling moeten communiceren in plaats van alleen via de orchestrator, of als ze asynchroon en parallel werken. Voor een lineaire taak met duidelijke stappen is een enkele orchestrator met workers meestal eenvoudiger en goedkoper.

Hoe debug ik een multi-agent systeem?

Log alle berichten op de message bus met timestamps en correlation IDs. Zo kun je per taak de hele keten reconstrueren en de berichtenstroom als een gerichte graaf visualiseren. Voeg per agent een status toe (running, done, failed) zodat je ziet waar het vastloopt.

Kan ik LangGraph of CrewAI patronen hergebruiken?

Ja, de concepten zijn gelijk aan wat hierboven staat. LangGraph en CrewAI bieden kant-en-klare abstracties voor supervisor- en worker-patronen. Bouw zelf wanneer je meer controle wilt of een heel specifiek patroon nodig hebt dat het framework niet kent.

Hoe schaal ik naar honderden gelijktijdige agent-runs?

Gebruik een job queue zoals BullMQ of Celery in plaats van direct Promise.all. Elke agent-run wordt een job die door losse worker-processen wordt opgepakt, zodat je horizontaal kunt schalen en runs opnieuw kunt proberen bij een fout.

Hoe voorkom ik dat agents oneindig doorlopen of vastlopen?

Geef elke stap een timeout en stel een totaalbudget in voor de hele taak in stappen, tokens of seconden. Laat de supervisor stoppen zodra het budget op is en een net deelresultaat teruggeven in plaats van eindeloos door te gaan.

Hoe houd ik de kosten beheersbaar?

Meet tokens per agent en per taak, en vergelijk met een enkelvoudige basisversie. Snoei agents die weinig toevoegen, beperk de context die je doorgeeft tot wat een rol echt nodig heeft, en cache herbruikbare research in het gedeelde geheugen.