| name | google-adk-multi-agent |
| description | Build ADK multi-agent systems with sub_agents, transfer_to_agent, and agent hierarchies. Use when creating coordinator/worker patterns, triage agents, or any system with multiple collaborating agents. |
Google ADK — Multi-Agent Systems
Core Concept
Multi-agent systems use a parent agent with sub_agents that the model can delegate to. The LLM decides which sub-agent to invoke based on description fields.
Import
from google.adk.agents import Agent
from google.adk.tools import transfer_to_agent
Basic Multi-Agent (LLM-Routed)
greeter = Agent(
name="greeter",
model="gemini-2.5-flash",
description="Handles greetings and introductions.",
instruction="Greet the user warmly and help them get started.",
)
researcher = Agent(
name="researcher",
model="gemini-2.5-flash",
description="Researches topics and answers factual questions.",
instruction="Research the topic thoroughly and provide accurate answers.",
tools=[google_search],
)
coordinator = Agent(
name="coordinator",
model="gemini-2.5-flash",
description="Routes user requests to the appropriate specialist.",
instruction="""You coordinate between specialist agents.
Route greetings to greeter, factual questions to researcher.""",
sub_agents=[greeter, researcher],
)
root_agent = coordinator
How Delegation Works
- Parent agent receives user message
- LLM decides based on sub-agent
description fields
- Model generates a
transfer_to_agent function call
- Control passes to the chosen sub-agent
- Sub-agent handles the request and responds
- Control returns to parent (or stays with sub-agent depending on config)
Explicit Transfer Tool
For manual control over transfers:
from google.adk.tools import transfer_to_agent
def escalate_to_human(reason: str) -> str:
"""Escalate the conversation to a human agent."""
return f"Escalating: {reason}"
support_agent = Agent(
name="support",
model="gemini-2.5-flash",
instruction="Handle support requests. Use transfer_to_agent to route to specialists.",
tools=[transfer_to_agent],
sub_agents=[billing_agent, technical_agent],
)
Triage Pattern (Dynamic Routing)
from google.adk.tools.tool_context import ToolContext
def update_execution_plan(agents: list[str], tool_context: ToolContext) -> str:
"""Updates which agents should execute."""
tool_context.state["execution_agents"] = agents
return "Plan updated."
triage_agent = Agent(
name="triage",
model="gemini-2.5-flash",
instruction="""Analyze the request and decide which worker agents are needed.
Available workers: code_agent, math_agent, writing_agent.
Call update_execution_plan with the relevant agents, then transfer to executor.""",
tools=[update_execution_plan, transfer_to_agent],
sub_agents=[executor_agent],
)
Hierarchical Multi-Agent
code_reviewer = Agent(name="code_reviewer", model="gemini-2.5-flash", ...)
test_writer = Agent(name="test_writer", model="gemini-2.5-flash", ...)
engineering_lead = Agent(
name="engineering_lead",
model="gemini-2.5-flash",
description="Handles code review and testing tasks.",
instruction="Delegate code review to code_reviewer, testing to test_writer.",
sub_agents=[code_reviewer, test_writer],
)
product_lead = Agent(
name="product_lead",
model="gemini-2.5-flash",
description="Handles product and design decisions.",
instruction="...",
)
root_agent = Agent(
name="coordinator",
model="gemini-2.5-pro",
description="Main coordinator for all tasks.",
instruction="Route engineering tasks to engineering_lead, product tasks to product_lead.",
sub_agents=[engineering_lead, product_lead],
)
Sharing State Between Agents
from google.adk.agents.readonly_context import ReadonlyContext
agent_a = Agent(
name="agent_a",
model="gemini-2.5-flash",
instruction="Research and store findings.",
output_key="agent_a_findings",
)
def agent_b_instruction(ctx: ReadonlyContext) -> str:
findings = ctx.state.get("agent_a_findings", "No findings yet.")
return f"Based on these findings, write a summary:\n{findings}"
agent_b = Agent(
name="agent_b",
model="gemini-2.5-flash",
instruction=agent_b_instruction,
include_contents="none",
)
Conditional Agent Execution (Callbacks)
from google.adk.agents.callback_context import CallbackContext
from google.genai import types
from typing import Optional
def skip_if_not_needed(callback_context: CallbackContext) -> Optional[types.Content]:
if "skip_agent" in callback_context.state:
return types.Content(parts=[types.Part(text="Skipped.")])
return None
conditional_agent = Agent(
name="conditional",
model="gemini-2.5-flash",
instruction="...",
before_agent_callback=skip_if_not_needed,
)
Key Rules
description is critical — it's how the parent LLM decides which sub-agent to call
- Sub-agents inherit the session and state from their parent
output_key lets agents write results that siblings/parents can read
transfer_to_agent can be explicit (tool) or implicit (model decides from sub_agents)
- Avoid circular transfers — design clear hierarchies
Related Skills
google-adk-llm-agent — Single agent configuration
google-adk-workflow-agents — Deterministic orchestration (Sequential, Parallel, Loop)
google-adk-a2a — Remote agent-to-agent communication