Skip to content

Enable Multi-Agent Collaboration

Learn how to enable multiple AI agents to collaborate, with one agent delegating tasks to specialist agents for complex workflows.

By the end of this guide, you will:

  • Understand multi-agent collaboration patterns
  • Configure agents to delegate to other agents
  • Set up specialist agents for specific domains
  • Handle inter-agent communication
  • Monitor and debug multi-agent workflows
  • A running Pika installation
  • Multiple agents defined
  • Understanding of agent configuration
  • Familiarity with your use case requirements

Multi-agent collaboration enables complex workflows by distributing tasks across specialized agents:

  • Orchestrator Agent: Receives user requests and delegates to specialists
  • Specialist Agents: Handle specific domains or tasks
  • Tool Integration: Each agent can use domain-specific tools
  • Customer Service: Triage agent routes to billing, technical, or sales specialists
  • Research Assistant: Main agent delegates to web search, data analysis, and document review agents
  • Development Helper: Coordinator agent assigns tasks to code review, testing, and documentation agents

Plan your multi-agent system architecture.

Hub and Spoke:

User → Orchestrator Agent → Specialist Agent 1
→ Specialist Agent 2
→ Specialist Agent 3

Sequential Pipeline:

User → Agent 1 (Data Collection)
→ Agent 2 (Analysis)
→ Agent 3 (Reporting)

Collaborative Team:

User → Project Manager Agent
→ Developer Agent + QA Agent + Documentation Agent
(Agents coordinate with each other)

Define focused agents for specific domains.

const techSupportAgent: AgentDataRequest = {
userId: `cloudformation/${this.stackName}`,
agent: {
agentId: 'tech-support-specialist',
basePrompt: `You are a technical support specialist.
Your role:
- Diagnose technical issues
- Guide users through troubleshooting steps
- Escalate unresolved issues
You have access to:
- Knowledge base search tool
- System status checker
- Diagnostic tools
Be methodical, patient, and thorough in your troubleshooting.`,
modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0'
},
tools: [
knowledgeBaseSearchTool,
systemStatusTool,
diagnosticTool
]
};
const billingAgent: AgentDataRequest = {
userId: `cloudformation/${this.stackName}`,
agent: {
agentId: 'billing-specialist',
basePrompt: `You are a billing specialist.
Your role:
- Answer billing questions
- Process refund requests
- Explain charges and invoices
You have access to:
- Billing lookup tool
- Invoice generator
- Payment processor
Always verify customer identity before discussing sensitive billing information.`,
modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0'
},
tools: [
billingLookupTool,
invoiceTool,
paymentTool
]
};

Build the main agent that routes to specialists.

const orchestratorAgent: AgentDataRequest = {
userId: `cloudformation/${this.stackName}`,
agent: {
agentId: 'customer-service-orchestrator',
basePrompt: `You are a customer service coordinator.
Your role is to:
1. Understand the customer's needs
2. Determine which specialist can best help
3. Delegate to the appropriate specialist agent
4. Synthesize responses from multiple specialists if needed
Available specialist agents:
- tech-support-specialist: Technical issues, troubleshooting, system problems
- billing-specialist: Billing questions, refunds, invoices, payments
- sales-specialist: Product information, upgrades, new purchases
When you determine which specialist is needed, use the delegate_to_agent tool to transfer the conversation.
If a request spans multiple domains, you can consult multiple specialists and provide a comprehensive response.`,
modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0'
},
tools: [
delegateToAgentTool
]
};

Collaborators (inline specialist agents) do not receive promptSessionAttributes from Bedrock. Without configuration, they cannot see user or session data (e.g. userId, currentDate, timezone, names, account info).

If your collaborators need to know who the user is, the current date, timezone, or other session/user fields, you must explicitly pass those into their instructions. The runtime supports this via collaboratorContextFields on the supervisor agent.

Set collaboratorContextFields on the supervisor agent to an array of keys (e.g. ['userId', 'currentDate', 'timezone', 'firstName', 'lastName', 'accountId', 'accountType']). Those keys are read from the same attribute map used for the main agent's promptSessionAttributes and injected into each collaborator's instruction as a <session-context> XML block.

Instructions for agent authors:

  1. Choose which keys collaborators need (e.g. userId, currentDate, timezone, firstName, lastName, accountId, accountType).
  2. Ensure those keys are present in session attributes or user custom data (or use standard ones like userId, currentDate that the runtime always adds).
  3. Add the same keys to collaboratorContextFields in the supervisor's agent definition.
  4. Optional: In collaborator base prompts, mention that they can use the information in <session-context> when relevant.

Supervisor agent definition (excerpt):

agent: {
agentId: 'customer-service-orchestrator',
basePrompt: '...',
collaboratorContextFields: ['userId', 'currentDate', 'timezone', 'firstName', 'lastName', 'accountId', 'accountType'],
collaborators: [
{ agentId: 'tech-support-specialist', instruction: '...', historyRelay: 'TO_COLLABORATOR' },
{ agentId: 'billing-specialist', instruction: '...', historyRelay: 'TO_COLLABORATOR' }
]
}

What a collaborator sees in its instruction (conceptually):

<session-context>
<userId>user-123</userId>
<currentDate>2025-02-18T12:00:00.000Z</currentDate>
<timezone>America/New_York</timezone>
<firstName>Jane</firstName>
<lastName>Doe</lastName>
<accountId>acct-456</accountId>
<accountType>retailer</accountType>
</session-context>

Only keys that exist in the runtime attribute map are included; values are XML-escaped.

Create a tool that allows one agent to invoke another.

src/tools/delegate-to-agent.ts
import { ToolExecutionParams, ToolResponse } from 'pika-shared/types/chatbot/chatbot-types';
import { invokeConverseFunction } from 'pika-shared/util/aws-utils';
interface DelegateInput {
agentId: string;
task: string;
context?: Record<string, any>;
}
export async function handler(event: ToolExecutionParams): Promise<ToolResponse> {
try {
const input = event.toolInput as DelegateInput;
const { agentId, task, context } = input;
console.log(`Delegating to agent ${agentId}: ${task}`);
// Invoke the target agent
const response = await invokeConverseFunction({
agentId: agentId,
message: task,
userId: event.userId,
sessionId: event.sessionId,
// Pass along context from orchestrator
additionalContext: context
});
return {
toolExecutionSucceeded: true,
responseFromTool: JSON.stringify({
agentId: agentId,
response: response.content,
delegationSuccessful: true
})
};
} catch (error) {
console.error('Delegation error:', error);
return {
toolExecutionSucceeded: false,
responseFromTool: JSON.stringify({
error: `Failed to delegate to agent: ${error.message}`
})
};
}
}
const delegateToAgentTool = {
toolId: 'delegate-to-agent',
name: 'delegate_to_agent',
displayName: 'Delegate to Specialist Agent',
description: 'Delegate a task to a specialist agent for expert handling',
executionType: 'lambda',
lambdaArn: 'WILL_BE_REPLACED_BY_CUSTOM_RESOURCE',
functionSchema: {
name: 'delegate_to_agent',
description: 'Transfer the conversation to a specialist agent',
inputSchema: {
type: 'object',
properties: {
agentId: {
type: 'string',
description: 'The ID of the specialist agent to delegate to',
enum: [
'tech-support-specialist',
'billing-specialist',
'sales-specialist'
]
},
task: {
type: 'string',
description: 'Clear description of what the specialist should help with'
},
context: {
type: 'object',
description: 'Additional context or information for the specialist'
}
},
required: ['agentId', 'task']
}
}
};

Process and combine responses from multiple agents.

const researchAgent: AgentDataRequest = {
userId: `cloudformation/${this.stackName}`,
agent: {
agentId: 'research-coordinator',
basePrompt: `You are a research coordinator.
When given a research question:
1. Delegate to web-search-agent to find current information
2. Delegate to data-analysis-agent to analyze any data
3. Delegate to fact-check-agent to verify claims
4. Synthesize all findings into a comprehensive report
Use the delegate_to_agent tool to consult each specialist in sequence.
Present a well-organized final report combining all insights.`,
modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0'
},
tools: [delegateToAgentTool]
};
// Tool that allows parallel agent invocation
async function consultMultipleAgents(
agentIds: string[],
task: string,
userId: string,
sessionId: string
): Promise<AgentResponse[]> {
const promises = agentIds.map(agentId =>
invokeConverseFunction({
agentId,
message: task,
userId,
sessionId
})
);
return Promise.all(promises);
}

Configure all agents in your deployment.

// Deploy all specialist agents
const techAgent = new cdk.CustomResource(this, 'TechSupportAgent', {
serviceToken: agentCustomResourceArn,
properties: {
AgentData: gzipAndBase64EncodeString(JSON.stringify(techSupportAgent))
}
});
const billingAgent = new cdk.CustomResource(this, 'BillingAgent', {
serviceToken: agentCustomResourceArn,
properties: {
AgentData: gzipAndBase64EncodeString(JSON.stringify(billingAgentData))
}
});
// Deploy orchestrator (depends on specialists)
const orchestrator = new cdk.CustomResource(this, 'OrchestratorAgent', {
serviceToken: agentCustomResourceArn,
properties: {
AgentData: gzipAndBase64EncodeString(JSON.stringify(orchestratorAgent))
}
});
orchestrator.node.addDependency(techAgent);
orchestrator.node.addDependency(billingAgent);
// Create chat app using orchestrator
const chatApp = new cdk.CustomResource(this, 'CustomerServiceApp', {
serviceToken: chatAppCustomResourceArn,
properties: {
ChatAppData: gzipAndBase64EncodeString(JSON.stringify({
userId: `cloudformation/${this.stackName}`,
chatApp: {
chatAppId: 'customer-service',
title: 'Customer Service',
agentId: 'customer-service-orchestrator'
}
}))
}
});
  • Clear Specialization: Each agent has a well-defined domain
  • Minimal Overlap: Reduce ambiguity in routing decisions
  • Explicit Capabilities: Document what each agent can do
  • Graceful Handoffs: Smooth transitions between agents
  • Smart Routing: Orchestrator understands when to delegate
  • Context Preservation: Pass relevant information to specialists
  • Response Synthesis: Combine specialist outputs coherently
  • Fallback Handling: What to do if specialist unavailable
  • Parallel When Possible: Consult multiple specialists concurrently
  • Cache Results: Avoid redundant specialist calls
  • Monitor Latency: Track end-to-end response times
  • Optimize Prompts: Keep agent instructions efficient
  • Review orchestrator prompt for clarity
  • Check specialist descriptions are distinct
  • Add examples of routing decisions
  • Log routing decisions for analysis
  • Verify context passed in delegation
  • Check session continuity
  • Review conversation history handling
  • Ensure relevant data persists
  • Identify bottleneck agents
  • Consider parallel invocation
  • Optimize specialist prompts
  • Cache common specialist responses