ADK Multi-Agent

Original Notion page had multiple screenshots illustrating delegation, AgentTool vs sub-agent, and root-agent diagrams. See migrated_from URL.

Delegation

The root agent is responsible for delegating to specialized agents.

  • Pass in the user query → root agent looks through all sub-agent descriptions → finds the right sub-agent.
  • In ADK, this is pure delegation — there are no multi-iteration handoffs.

Built-in tools constraint

Built-in tools (like Google Search) cannot be used inside a sub-agent.

Workaround: wrap that agent in AgentTool — this treats an agent like a tool call rather than a sub-agent.

So:

  • Sub-agent doesn’t work if it uses a built-in tool.
  • AgentTool wrapping the same agent → works.

Difference between AgentTool and Sub-agent

Sub-agentAgentTool
PatternPure delegation; root hands off controlRoot calls it like a function tool, gets back a result
Built-in tools insideNot allowedAllowed
Use caseSpecialist takes over the conversationCompose specialist’s output into your own response

Root agent example

root_agent = Agent(
    name="manager",
    model="gemini-2.0-flash",
    description="Manager agent",
    instruction="""
    You are a manager agent that is responsible for overseeing the work of the other agents.
 
    Always delegate the task to the appropriate agent. Use your best judgement
    to determine which agent to delegate to.
 
    You are responsible for delegating tasks to the following agent:
    - stock_analyst
    - funny_nerd
 
    You also have access to the following tools:
    - news_analyst
    - get_current_time
    """,
    sub_agents=[stock_analyst, funny_nerd],   # import agents from sub-agent folder
    tools=[
        AgentTool(news_analyst),              # uses google_search → can't be a sub-agent
        get_current_time,
    ],
)

Sub-agent example (funny_nerd)

def get_nerd_joke(topic: str, tool_context: ToolContext) -> dict:
    """Get a nerdy joke about a specific topic."""
    print(f"--- Tool: get_nerd_joke called for topic: {topic} ---")
 
    jokes = {
        "python": "Why don't Python programmers like to use inheritance? Because they don't like to inherit anything!",
        "javascript": "Why did the JavaScript developer go broke? Because he used up all his cache!",
        "java": "Why do Java developers wear glasses? Because they can't C#!",
        "programming": "Why do programmers prefer dark mode? Because light attracts bugs!",
        "math": "Why was the equal sign so humble? Because he knew he wasn't less than or greater than anyone else!",
        "physics": "Why did the photon check a hotel? Because it was travelling light!",
        "chemistry": "Why did the acid go to the gym? To become a buffer solution!",
        "biology": "Why did the cell go to therapy? Because it had too many issues!",
        "default": "Why did the computer go to the doctor? Because it had a virus!",
    }
 
    joke = jokes.get(topic.lower(), jokes["default"])
 
    # Update state with the last joke topic
    tool_context.state["last_joke_topic"] = topic
 
    return {"status": "success", "joke": joke, "topic": topic}
 
 
# Create the funny nerd agent
funny_nerd = Agent(
    name="funny_nerd",
    model="gemini-2.0-flash",
    description="An agent that tells nerdy jokes about various topics.",
    # super important for the root agent to do delegation
    instruction="""
    You are a funny nerd agent that tells nerdy jokes about various topics.
 
    When asked to tell a joke:
    1. Use the get_nerd_joke tool to fetch a joke about the requested topic
    2. If no specific topic is mentioned, ask the user what kind of nerdy joke they'd like to hear
    3. Format the response to include both the joke and a brief explanation if needed
 
    Available topics include:
    - python
    - javascript
    - java
    - programming
    - math
    - physics
    - chemistry
    - biology
 
    Example response format:
    "Here's a nerdy joke about <TOPIC>:
    <JOKE>
 
    Explanation: {brief explanation if needed}"
 
    If the user asks about anything else,
    you should delegate the task to the manager agent.
    """,
    tools=[get_nerd_joke],
)
from google.adk.agents import Agent
from google.adk.tools import google_search
 
news_analyst = Agent(
    name="news_analyst",
    model="gemini-2.0-flash",
    description="News analyst agent",
    instruction="""
    You are a helpful assistant that can analyze news articles and provide a summary of the news.
 
    When asked about news, you should use the google_search tool to search for the news.
 
    If the user asks for news using a relative time, you should use the get_current_time tool to get the current time to use in the search query.
    """,
    tools=[google_search],
)

Tip — escape from a “stuck” sub-agent

If the agent gets stuck inside a sub-agent, ask it to delegate back explicitly in the instructions (see the funny_nerd example above).

See next