Skip to content

Multi-agent delegation

In Genkit, multi-agent systems split work between specialized agents and an orchestrator. The orchestrator decides which specialist should handle each part of the request, then synthesizes a final answer.

Use this pattern when separate capabilities benefit from separate prompts, tools, state, or evaluation. A single agent with several tools is usually simpler when one prompt can coordinate the whole task. Multiple agents are useful when specialists need different instructions, different model settings, durable specialist memory, or independently inspectable artifacts.

The middleware package provides agents() for delegation. It injects one delegation tool per sub-agent. By default, tool names use delegate_to_<agentName>.

import { agents, artifacts, retry } from '@genkit-ai/middleware';
const researcher = ai.defineAgent({
name: 'researcher',
description: 'Finds facts and produces sourced research notes.',
system: 'Research the user request and write concise findings.',
use: [artifacts(), retry()],
});
const coder = ai.defineAgent({
name: 'coder',
description: 'Writes and explains code.',
system:
'Write clear TypeScript code unless the user asks for another language.',
use: [artifacts(), retry()],
});
const coordinator = ai.defineAgent({
name: 'coordinator',
system:
'Delegate to specialists, inspect their results, then answer the user.',
use: [
agents({
agents: [
'researcher',
{
name: 'coder',
description:
'Writes, debugs, and explains code. Use for programming tasks.',
},
],
historyLength: 4,
maxDelegations: 5,
artifactStrategy: 'session',
}),
artifacts({ readonly: true }),
],
});

The middleware can discover agent descriptions from action metadata, or you can override a description in the middleware config. Keep descriptions concrete because they become tool descriptions for the orchestrator model.

  • agents accepts agent names, agent actions, or entries with a name and description override.
  • toolPrefix controls generated tool names. It defaults to delegate_to; set it to an empty string to use bare agent names.
  • historyLength sets how many recent conversation messages are forwarded to sub-agents.
  • maxDelegations limits delegation calls in one orchestrator turn.
  • artifactStrategy controls whether sub-agent artifacts are merged into the parent session.

When history is forwarded to client-managed sub-agents, the middleware includes recent messages in the sub-agent state. For server-managed sub-agents, history is not forwarded as client state because those agents own their server-side session.

Delegation appears as normal tool activity in the orchestrator stream.

const turn = coordinator
.chat()
.sendStream('Research sorting algorithms and write quicksort.');
for await (const chunk of turn.stream) {
for (const request of chunk.toolRequests) {
const name = request.toolRequest.name;
if (name.startsWith('delegate_to_')) {
showDelegation(name);
}
}
if (chunk.text) {
appendText(chunk.text);
}
}

Sub-agent interrupts and failures are returned to the orchestrator as tool output. They do not automatically become top-level interrupts for the original client. Write orchestrator instructions that tell it how to handle delegated failures, such as retrying, choosing another specialist, or asking the user for clarification.

With artifactStrategy: 'session', sub-agent artifacts are merged into the parent session and namespaced by invocation. Pair this with artifacts({ readonly: true }) so the orchestrator can inspect delegated work through the read_artifact tool.

Use session artifacts when delegated work should be visible to the final user or to later turns. Keep artifacts isolated when the specialist output is only an implementation detail for the orchestrator’s current answer.

The older Building multi-agent systems page describes a prompts-as-tools pattern. Prefer the Agents API middleware for new work because it integrates with sessions, streaming, persistence, background execution, and HTTP clients.