AI & Machine Learning

Multi-agent AI: agents die samenwerken, en waarom het misgaat bij de overdracht

Meerdere AI-agents die werk aan elkaar doorgeven: wanneer dat loont, waarom het volgens onderzoek zo vaak misgaat, wat A2A en MCP wel en niet regelen, en hoe een goede overdracht er in PHP uitziet.

Erik van de Blaak
Erik van de Blaak
14 min leestijd • 13 weergaven
Multi-agent AI: agents die samenwerken, en waarom het misgaat bij de overdracht

Vraag een groep AI-agents om samen Flappy Bird te bouwen. De ene agent maakt de achtergrond, de tweede de vogel, een derde zet het in elkaar. Grote kans dat je een achtergrond in de stijl van Super Mario krijgt, een vogel die daar niet bij past, en een derde agent die er niets meer van kan maken. Dat voorbeeld komt van Cognition, het bedrijf achter de programmeeragent Devin, uit een blog van juni 2025 met de titel Don't Build Multi-Agents.

Ruim een jaar later beweegt de sector de andere kant op. Google, Microsoft en AWS ondersteunen A2A, een open protocol waarmee agents van verschillende leveranciers werk aan elkaar doorgeven. Anthropic laat in zijn eigen onderzoeksfunctie een hoofdagent het werk verdelen over subagents die tegelijk zoeken, en meet daar een grote winst mee.

Allebei klopt. Samenwerkende agents werken goed voor het ene soort werk en slecht voor het andere, en het verschil zit bijna altijd in het moment dat de ene agent iets aan de andere geeft. Het versturen van dat bericht is inmiddels gestandaardiseerd. Wat erin staat, en wie controleert wat er terugkomt, is nog steeds jouw werk.

De feiten en cijfers in dit artikel zijn gecontroleerd op 29 september 2026. Onderzoeksresultaten, claims van bedrijven en mijn eigen inschatting staan steeds apart vermeld. De codevoorbeelden zijn in PHP.

Wat is multi-agent AI?

Bij multi-agent AI werken meerdere AI-agents aan één opdracht, elk met een eigen taak, eigen instructies en vaak eigen tools. Eén agent verdeelt het werk of geeft een deel door, een andere voert dat uit en levert een resultaat terug. Een agent is in deze zin een taalmodel dat in een lus zelf zijn volgende stap kiest: een tool aanroepen, het resultaat lezen, verder.

Onder die ene term vallen twee situaties die in de praktijk weinig met elkaar te maken hebben:

Binnen één systeemTussen systemen
Wie bouwt de agentsjij, of één leverancierverschillende teams of bedrijven
Voorbeeldeen hoofdagent met subagents, zoals in Claude Code of Anthropic's Research-functiejouw applicatie laat de agent van een andere partij een taak uitvoeren
Wat ze van elkaar wetenveel: zelfde framework, vaak gedeelde contextalleen wat in het bericht staat
Standaard nodig?neeja: A2A (Agent2Agent)
Typische foutdubbel werk, tegenstrijdige keuzesontbrekende context, vertrouwen, wie mag wat

De term agent interoperability gaat over de rechterkolom. De meeste problemen uit dit artikel spelen in allebei.

Wanneer samenwerkende agents iets opleveren

Het duidelijkste openbare cijfer komt van Anthropic. In juni 2025 beschreef het bedrijf hoe zijn Research-functie werkt: een hoofdagent (Claude Opus 4) splitst een vraag op en start subagents (Claude Sonnet 4) die elk in een eigen contextvenster een deel uitzoeken. Op Anthropic's eigen, interne onderzoeksevaluatie scoorde die opzet 90,2 procent beter dan Claude Opus 4 in zijn eentje.

Het voorbeeld dat Anthropic erbij geeft, laat zien om welk werk het gaat: zoek alle bestuursleden van de IT-bedrijven in de S&P 500. Eén agent die dat bedrijf voor bedrijf afzoekt, loopt vast. Tien agents die elk een stapel bedrijven nemen, zijn klaar voordat de eerste halverwege is. Door parallel te zoeken werd onderzoek naar complexe vragen volgens Anthropic tot 90 procent sneller.

Daar staat een rekening tegenover. Een agent gebruikt volgens dezelfde publicatie ongeveer vier keer zoveel tokens als een gewone chat, een multi-agent-systeem ongeveer vijftien keer zoveel. Op de benchmark BrowseComp verklaarde de hoeveelheid gebruikte tokens alleen al 80 procent van de verschillen in prestatie. Een deel van de winst is dus gewoon: meer rekenwerk.

Voor elk multi-agent-plan is dat de eerste vraag: valt het werk uiteen in stukken die niet van elkaar afhangen, en is het resultaat vijftien keer de tokens waard?

Anthropic zegt er zelf bij waar het niet werkt: bij taken waarin alle agents dezelfde context nodig hebben, of waarin ze veel van elkaar afhangen. De meeste programmeertaken horen daar volgens het bedrijf bij, omdat code minder echt parallelle stukken bevat dan onderzoek. Dat is het Flappy Bird-probleem van Cognition, van de andere kant bekeken. Cognition formuleerde het als twee regels: deel de volledige context en niet alleen losse berichten, en besef dat elke actie een beslissing bevat die met die van een andere agent kan botsen.

Waarom multi-agent-systemen falen

Onderzoekers van UC Berkeley analyseerden 1.642 uitvoeringen van zeven open-source multi-agent-frameworks, waaronder ChatDev, MetaGPT, Magentic-One en OpenManus. Die systemen faalden in 41 tot 86,7 procent van de gevallen. Het paper, Why Do Multi-Agent LLM Systems Fail?, verscheen op NeurIPS 2025 en deelt de fouten in veertien soorten, in drie groepen.

Staafdiagram van de veertien faalwijzen uit het MAST-onderzoek, in drie groepen. Systeemontwerp 44,2 procent: stappen herhalen 15,7, niet zien dat de taak klaar is 12,4, opdracht niet volgen 11,8, context kwijtraken 2,8, rol niet volgen 1,5. Afstemming tussen agents 32,3 procent: redeneren en doen lopen uiteen 13,2, taak ontspoort 7,4, gokken in plaats van vragen 6,8, gesprek begint opnieuw 2,2, input van andere agent negeren 1,9, informatie achterhouden 0,85. Controle 23,5 procent: verkeerde controle 9,1, geen of onvolledige controle 8,2, te vroeg stoppen 6,2.
Aandeel van elke faalwijze in de fouten die de onderzoekers in 1.642 uitvoeringen vonden. Bron: Cemri e.a., Why Do Multi-Agent LLM Systems Fail?, NeurIPS 2025.

De vaakst voorkomende fouten zijn niet exotisch. Een agent herhaalt stappen die al gedaan zijn (15,7 procent). Een agent redeneert naar A en doet B (13,2 procent). Het systeem ziet niet dat de taak klaar is en gaat door (12,4 procent), of houdt zich niet aan de opdracht (11,8 procent). In 6,8 procent gaat een agent verder op een verkeerde aanname, terwijl hij ook een vraag had kunnen stellen.

Twee bevindingen zijn voor een ontwikkelaar het nuttigst.

Controleren is geen reviewer-agent toevoegen. Veel ingebouwde controle-agents keken alleen of de code compileerde of of er nog TODO-commentaar in stond, ook als ze de opdracht kregen grondig te controleren. Een schaakprogramma van ChatDev kwam zo door de review en bleek daarna de spelregels niet te volgen. Toen de onderzoekers een controlestap op het einddoel toevoegden, slaagden 15,6 procent meer taken. Alleen duidelijkere rolbeschrijvingen leverden 9,4 procent op.

Een protocol lost afstemming niet op. De onderzoekers noemen MCP en A2A bij naam: die standaardiseren de vorm van berichten tussen tools en agents van verschillende makers. Maar de afstemmingsfouten die zij zagen, traden ook op tussen agents in hetzelfde framework die gewoon in natuurlijke taal met elkaar spraken. Het probleem is dat een agent slecht inschat wat de andere agent moet weten. Een net berichtformaat verandert daar niets aan.

Een kanttekening: de metingen zijn gedaan met modellen uit 2024 en 2025, zoals GPT-4o en Claude 3.7 Sonnet. Nieuwere modellen maken minder van deze fouten. Mijn inschatting is dat de indeling zelf bruikbaar blijft, omdat de meeste fouten ontstaan in het ontwerp van het systeem en niet in het model.

A2A en MCP: wat de protocollen regelen

Er zijn twee protocollen die je moet kennen, en ze doen iets anders.

MCP (Model Context Protocol) regelt hoe een agent tools en data gebruikt: een database, een API, een map met bestanden. Anthropic introduceerde het in november 2024. Sinds 9 december 2025 valt het onder de Agentic AI Foundation van de Linux Foundation, samen met goose van Block en AGENTS.md van OpenAI; die stichting had op 13 augustus 2026 247 leden. Voor PHP is er een officiële SDK, mcp/sdk, gebouwd door het Symfony-team samen met de PHP Foundation. Hoe je MCP veilig aan je eigen systemen koppelt, lees je in mijn artikel over MCP.

A2A (Agent2Agent) regelt hoe agents elkaar vinden en werk aan elkaar geven, ook als ze bij verschillende bedrijven draaien. Google presenteerde het in april 2025 en droeg het op 23 juni 2025 over aan de Linux Foundation. IBM liet zijn eigen Agent Communication Protocol in augustus 2025 in A2A opgaan. Versie 1.0 verscheen op 12 maart 2026. Volgens de Linux Foundation steunden in april 2026 meer dan 150 organisaties het protocol en is het ingebouwd in Azure AI Foundry, Copilot Studio en Amazon Bedrock AgentCore.

Twee organisaties naast elkaar. Links jouw organisatie: een PHP-applicatie met een eigen agent die via MCP een database en een API gebruikt. Rechts een andere organisatie met een agent die via MCP zijn eigen tools gebruikt. Tussen de twee agents loopt A2A: eerst de Agent Card ophalen, dan een taak sturen en een status met resultaat terugkrijgen. Wat de agent rechts intern doet, is van links niet te zien.
MCP is de lijn van een agent naar zijn tools, A2A de lijn tussen twee agents. Over de A2A-lijn gaat alleen wat jij in het bericht zet.

De A2A-specificatie beschrijft agents als opaque: de ene agent ziet niet welk model de andere gebruikt, welke instructies of welke tools. Hij ziet een beschrijving van wat de ander kan, stuurt een bericht en krijgt een taak terug met een status. Tussen bedrijven is dat precies goed. Het betekent ook dat de ontvanger niets weet wat niet in het bericht staat, en dat is meteen de belangrijkste ontwerpregel voor alles wat volgt.

Een A2A-overdracht in PHP

A2A 1.0 kent drie transportvormen: JSON-RPC, gRPC en gewone HTTP met JSON. Voor een PHP-applicatie is HTTP met JSON het eenvoudigst; je hebt er niet meer dan curl voor nodig. Er bestaan ook PHP-bibliotheken voor A2A, maar die komen uit de community en niet van het A2A-project zelf. Voor dit voorbeeld houd ik het bij de kale aanroepen, zodat je ziet wat er over de lijn gaat.

Het voorbeeld is verzonnen, om de techniek te laten zien: een webshop in PHP laat productteksten naar het Duits vertalen door de agent van een vertaalbureau. Dat bureau publiceert een Agent Card op een vaste plek, /.well-known/agent-card.json, met naam, endpoints, authenticatie en de skills van de agent:

{
  "name": "Vertaalagent",
  "description": "Vertaalt producttekst NL-DE met de terminologie van de klant.",
  "supportedInterfaces": [
    {"url": "https://agent.vertaalbureau.example/a2a", "protocolBinding": "HTTP+JSON", "protocolVersion": "1.0"}
  ],
  "capabilities": {"streaming": false, "pushNotifications": true},
  "skills": [
    {"id": "product-nl-de", "name": "Producttekst NL-DE", "description": "Titel en beschrijving, HTML blijft intact.", "tags": ["vertaling", "e-commerce"]}
  ]
}

De webshop leest die kaart, kiest het endpoint en stuurt een bericht. Een bericht bestaat uit parts: tekst, een bestand of gestructureerde data. Hier gaat de opdracht als tekst mee en het product als JSON:

<?php
function a2aPost(string $baseUrl, string $path, array $body, string $token): array
{
    $ch = curl_init(rtrim($baseUrl, '/') . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/a2a+json',
            'A2A-Version: 1.0',
            'Authorization: Bearer ' . $token,
        ],
        CURLOPT_POSTFIELDS     => json_encode($body, JSON_THROW_ON_ERROR),
    ]);
    $raw = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    if ($raw === false || $status >= 400) {
        throw new RuntimeException("A2A-aanroep mislukt (HTTP $status)");
    }
    return json_decode($raw, true, flags: JSON_THROW_ON_ERROR);
}

// 1. De agent vinden: de Agent Card staat op een vaste plek
$card = json_decode(
    file_get_contents('https://agent.vertaalbureau.example/.well-known/agent-card.json'),
    true, flags: JSON_THROW_ON_ERROR
);
$endpoint = null;
foreach ($card['supportedInterfaces'] as $interface) {
    if ($interface['protocolBinding'] === 'HTTP+JSON' && $interface['protocolVersion'] === '1.0') {
        $endpoint = $interface['url'];
        break;
    }
}

// 2. De overdracht: opdracht als tekst, het product als data
$response = a2aPost($endpoint, '/message:send', [
    'message' => [
        'messageId' => bin2hex(random_bytes(16)),
        'role'      => 'ROLE_USER',
        'parts'     => [
            ['text' => $opdracht],
            ['data' => $product, 'mediaType' => 'application/json'],
        ],
    ],
], getenv('VERTAALBUREAU_TOKEN'));

Wat terugkomt, is een taak met een id en een status. Soms stuurt een agent direct een los bericht terug in plaats van een taak; ook dat mag volgens de specificatie. Een taak doorloopt een vaste reeks toestanden, en je code moet ze allemaal kunnen afhandelen, niet alleen de toestand waarin alles goed ging:

Levenscyclus van een A2A-taak. Van SUBMITTED naar WORKING. Vanuit WORKING kan de taak onderbroken worden in INPUT_REQUIRED (de agent heeft een vraag) of AUTH_REQUIRED (extra autorisatie nodig) en daarna met een vervolgbericht weer doorgaan. Eindtoestanden: COMPLETED, FAILED, CANCELED en REJECTED. Bij COMPLETED staat de aantekening: controleer het resultaat in je eigen code.
De toestanden van een A2A-taak volgens de specificatie 1.0. Alleen COMPLETED betekent dat er een resultaat is, en ook dat resultaat moet je nog controleren.
<?php
$task = $response['task'] ?? null;
if ($task === null) {
    // De agent antwoordde met een los bericht in plaats van een taak
    return handleDirectMessage($response['message']);
}

$result = match ($task['status']['state']) {
    'TASK_STATE_COMPLETED'      => verifyTranslation($task['artifacts'] ?? [], $product),
    'TASK_STATE_INPUT_REQUIRED' => askEditor($task),      // de agent stelt een vraag
    'TASK_STATE_AUTH_REQUIRED'  => throw new RuntimeException('Agent vraagt extra autorisatie'),
    'TASK_STATE_SUBMITTED',
    'TASK_STATE_WORKING'        => schedulePoll($task['id']), // later ophalen met GET /tasks/{id}
    default                     => logFailure($task),     // FAILED, CANCELED of REJECTED
};

INPUT_REQUIRED is de interessantste toestand. Het is de plek in het protocol waar een agent kan zeggen: dit weet ik niet, vertel het me. In het Berkeley-onderzoek ging 6,8 procent van de fouten over agents die gokten in plaats van te vragen. Het protocol maakt vragen dus mogelijk. Of de agent het ook doet, hangt af van de opdracht die je meestuurt.

De overdracht als contract

Anthropic beschrijft wat een hoofdagent aan een subagent moet meegeven: een doel, een uitvoerformaat, aanwijzingen over welke tools en bronnen hij gebruikt, en duidelijke grenzen aan de taak. Zonder die vier ging het in hun eerste versies mis: agents deden elkaars werk dubbel, lieten gaten vallen, of startten vijftig subagents voor een eenvoudige vraag. Dezelfde vier punten werken voor een overdracht tussen bedrijven:

<?php
$opdracht = <<<TXT
Doel: vertaal titel en beschrijving naar het Duits voor een Duitse webshop.
      Gebruik de du-vorm en voeg geen verkoopzinnen toe.
Uitvoer: JSON met precies de velden "title" en "description".
      Dezelfde HTML-tags als in de invoer, in dezelfde volgorde.
Bronnen: gebruik de terminologielijst uit de data. Vertaal merknamen
      en productcodes niet.
Grenzen: niets inkorten, niets toevoegen. Twijfel je over een term,
      stel dan een vraag in plaats van te gokken.
TXT;

De laatste zin koppelt de opdracht aan INPUT_REQUIRED: je geeft de agent toestemming om te vragen, en je code weet wat ze met die vraag moet doen.

Het tweede deel van het contract staat aan jouw kant: controleer wat terugkomt in gewone code, op dingen die je kunt meten. Niet met een tweede agent die zegt dat het goed is, want dan heb je het controleprobleem uit het onderzoek alleen verplaatst.

<?php
function verifyTranslation(array $artifacts, array $product): array
{
    $data = $artifacts[0]['parts'][0]['data'] ?? null;

    $keys = is_array($data) ? array_keys($data) : [];
    sort($keys);
    if ($keys !== ['description', 'title']) {
        throw new UnexpectedValueException('Vertaling heeft niet het afgesproken formaat');
    }

    // Zelfde aantal HTML-tags als het origineel
    if (substr_count($data['description'], '<') !== substr_count($product['description'], '<')) {
        throw new UnexpectedValueException('HTML-structuur wijkt af van het origineel');
    }

    // Productcodes moeten letterlijk terugkomen
    foreach ($product['codes'] as $code) {
        if (!str_contains($data['title'] . ' ' . $data['description'], $code)) {
            throw new UnexpectedValueException("Productcode $code ontbreekt in de vertaling");
        }
    }

    return $data;
}

Of de vertaling goed Duits is, stelt deze functie niet vast. Wel dat het formaat klopt, dat de opmaak heel is en dat er geen productcode is weggevallen. Dat zijn precies de fouten die een mens bij het nalezen snel mist, en die code nooit mist.

Wat A2A en MCP niet regelen

Het protocol bezorgt het bericht. Twee dingen blijven jouw verantwoordelijkheid.

Veiligheid

Op 9 september 2026 publiceerden onderzoekers van Purdue University A2ABreak, een systematische analyse van de A2A-specificatie. Ze vonden elf nieuwe kwetsbaarheden, waaronder het injecteren van context tussen verschillende klanten via onbeschermde id's, het buitmaken van inloggegevens doordat de identiteit onderweg in een keten van doorgegeven taken verloren gaat, en het weglekken van data via een kwaadwillende agent die zegt iets te kunnen wat niet gecontroleerd is.

Versie 1.0 van A2A bevat ondertekende Agent Cards, waarmee je kunt nagaan of een kaart echt van het opgegeven domein komt; de specificatie zegt dat clients dat zouden moeten doen. Mijn advies gaat een stap verder: behandel alles wat een andere agent teruggeeft zoals je gebruikersinvoer behandelt. Een artifact kan instructies bevatten die jouw eigen agent daarna uitvoert. Wat er rond zo'n agent aan beveiliging en toezicht nodig is, beschreef ik in het artikel over agent harnesses.

Wie beslist

In juni 2026 vergeleken Richard Kang en Yudho Diponegoro vijf protocollen voor samenwerkende agents, waaronder MCP, A2A en ACP, op zes aspecten van besluitvorming: lidmaatschap, overleg, stemmen, het bewaren van afwijkende meningen, doorverwijzen naar een mens en het achteraf kunnen naspelen van wat er gebeurde. Geen enkel protocol ondersteunde ze allemaal, en stemmen en het vastleggen van afwijkende meningen ontbraken overal. Hun conclusie: dat is geen ontbrekende functie in de protocollen, maar een laag die erboven nog niet bestaat.

Voor een PHP-applicatie betekent dat: wie mag goedkeuren wat een agent voorstelt, regel je in je eigen code. Log bij elke overdracht het taak-id, wat je stuurde en wat terugkwam, zodat je achteraf kunt nagaan welke agent welke beslissing nam.

Waar je begint

Begin met één agent. Splits pas op als het werk echt uiteenvalt in stukken die niet van elkaar afhangen, zoals zoeken in veel bronnen tegelijk, en reken dan met een veelvoud aan tokens. Gebruik A2A pas als de andere agent buiten je eigen systeem draait; binnen één applicatie is een functieaanroep of een job in de wachtrij eenvoudiger en beter te testen.

En behandel elke overdracht als een contract met twee kanten: een opdracht met doel, uitvoer, bronnen en grenzen, en een controle in je eigen code op wat terugkomt. Het protocol bezorgt het pakket. Wat erin zit, blijft jouw werk.

Bronnen

Deel dit artikel

Erik van de Blaak

Geschreven door

Erik van de Blaak

AI Solutions Engineer & Full-Stack Developer

Erik van de Blaak is AI Solutions Engineer en full-stack developer bij CareerValue BV. Hier schrijft hij over AI-codeertools en agents, zoals Claude Code.

Reacties (0)

Reageer op dit artikel

Wordt niet gepubliceerd

Ik lees elke reactie voordat die online komt.

Nog geen reacties op dit artikel.

Lees ook