Build coordinated multi-agent systems with handoffs
Multi-agent systems enable specialized agents to collaborate on complex tasks by transferring control to each other. The agent framework implements this through handoffs.
When an agent has handoffs configured, the framework automatically creates transfer_to_<agent_name> tools that allow agents to delegate tasks to specialists.
import { openai } from '@ai-sdk/openai';import { agent, swarm } from '@deepagents/agent';const researcher = agent({ name: 'researcher', model: openai('gpt-4o'), prompt: 'You research topics and provide detailed information.', handoffDescription: 'Handles research and fact-finding tasks',});const writer = agent({ name: 'writer', model: openai('gpt-4o'), prompt: 'You write clear, engaging content based on research.', handoffDescription: 'Handles writing and content creation',});const coordinator = agent({ name: 'coordinator', model: openai('gpt-4o'), prompt: ` You coordinate research and writing tasks. - Use transfer_to_researcher for fact-finding - Use transfer_to_writer for content creation `, handoffs: [researcher, writer],});// The coordinator can now delegate to researcher and writerconst stream = swarm(coordinator, 'Write a blog post about AI agents', {});for await (const chunk of stream) { if (chunk.type === 'text-delta') { process.stdout.write(chunk.delta); }}
The agent can call these tools to transfer control:
// Agent decides to use researcherAgent: "I need to gather information first."[Calls: transfer_to_researcher()]// Researcher takes overResearcher: "Let me research that topic..."[Performs research]// Returns to coordinatorCoordinator: "Now I'll send this to the writer."[Calls: transfer_to_writer()]
import { openai } from '@ai-sdk/openai';import { agent, instructions, swarm, generate, execute } from '@deepagents/agent';import { z } from 'zod';const WebSearchPlanSchema = z.object({ searches: z.array( z.object({ reason: z.string().describe('Why this search is important'), query: z.string().describe('The search term to use'), }) ),});const ReportDataSchema = z.object({ short_summary: z.string().describe('A short 2-3 sentence summary'), markdown_report: z.string().describe('The final report'), follow_up_questions: z.array(z.string()),});const planner = agent({ model: openai('gpt-4o'), name: 'PlannerAgent', output: WebSearchPlanSchema, prompt: instructions({ purpose: [ 'You are a research assistant. Given a query, come up with web searches to answer it.', ], routine: ['Output between 5 and 10 terms to query for.'], }),});const research = agent({ model: openai('gpt-4o'), name: 'ResearchAgent', prompt: instructions({ purpose: [ 'You are a research assistant. Search the web and produce a concise summary.', ], routine: [ 'Capture the main points. Write succinctly.', 'This will be consumed by someone synthesizing a report.', ], }), tools: { web_search: openai.tools.webSearch({ searchContextSize: 'low' }), },});const writer = agent({ name: 'WriterAgent', model: openai('gpt-4o'), output: ReportDataSchema, prompt: instructions({ purpose: [ 'You are a senior researcher writing a cohesive report.', 'You will be provided with the query and initial research.', ], routine: [ 'Come up with an outline for the report', 'Generate the report in markdown format', 'Aim for 5-10 pages, at least 1000 words', ], }),});// Workflowasync function run(query: string) { const plan = await generate(planner, `Query: ${query}`, {}); const searchResults = await Promise.all( plan.output.searches.map(async (item) => { const result = await execute(research, `Search: ${item.query}`, {}); return await result.text; }) ); const report = await generate( writer, `Original query: ${query}\nSearch results: ${JSON.stringify(searchResults)}`, {} ); return report.output;}
For complex coordination, use the supervisor pattern:
import { agent, instructions } from '@deepagents/agent';const supervisor = agent({ name: 'supervisor', model: openai('gpt-4o'), prompt: instructions.supervisor({ purpose: [ 'You are a supervisor coordinating multiple specialist agents.', 'Delegate tasks to the appropriate agent and review their work.', ], routine: [ 'Analyze the user request', 'Break it into subtasks', 'Delegate each subtask to the right specialist', 'Review and synthesize the results', ], }), handoffs: [specialist1, specialist2, specialist3],});
agent({ name: 'researcher', handoffDescription: 'Handles research tasks, fact-finding, and web searches', // ...})
Explicit Coordination Instructions
Tell the coordinator when to use each agent:
prompt: ` Use transfer_to_researcher when: user needs facts or data Use transfer_to_writer when: research is complete and content needs to be written Use transfer_to_editor when: content is drafted and needs review`
Limit Handoff Depth
Avoid deeply nested handoffs (agent → agent → agent → agent). Instead, have specialists return to a central coordinator.
Use swarm() for Handoffs
Always use swarm() instead of execute() when working with agents that have handoffs:
// ✅ Correctconst stream = swarm(coordinator, message, context);// ❌ May not handle handoffs properlyconst stream = execute(coordinator, message, context);