skip to content

In Google ADK, what happens when the model calls an AgentTool-wrapped agent?

level: middleimportance: should knowfreq 54%

answer

  1. Another agent, exposed as a function
  2. Round trip, not a handover
  3. Runs its own nested invocation
  4. Caller sees the final answer only
  5. One flag suppresses the extra rewrite

basics

~20 s

AgentTool exposes another agent as a callable function. When the model calls it, ADK runs that agent to completion as a nested invocation and returns its final response as the function result, so control comes straight back to the caller instead of being handed over.

solid answer

~50 s

`AgentTool(agent=some_agent)` turns an agent into a tool the calling model can invoke. ADK generates a function declaration from it — a single request-style string argument unless the wrapped agent declares its own input schema — and when the model calls it, the wrapped agent runs as its own nested invocation with its own instruction and its own tools. Its final response comes back as the function response, and the caller continues its turn. That is the crucial contrast with putting the agent in `sub_agents`: a transfer hands the conversation over, while an AgentTool call is a round trip that returns. Set `skip_summarization=True` when you want the wrapped agent's output used as-is rather than re-summarized by the caller. The cost is real: a nested agent run means a second set of model calls, added latency, and a caller that sees only the final text, not the intermediate steps.

code

python · 16 lines
python
from google.adk.agents import Agent
from google.adk.tools.agent_tool import AgentTool

summarizer = Agent(
    name="summarizer",
    model="gemini-2.0-flash",
    description="Condenses supplied text into three bullet points.",
    instruction="Summarize the text you are given in exactly three bullets.",
)

root_agent = Agent(
    name="root",
    model="gemini-2.0-flash",
    instruction="Call the summarizer tool when the user asks for a summary.",
    tools=[AgentTool(agent=summarizer, skip_summarization=True)],
)

go deeper

for a junior

Know that an agent can be handed to another agent as a tool, and that the call returns the wrapped agent's answer rather than handing the conversation over.

for a middle

Explain the nested invocation: its own instruction and tools, a request-style argument, the final response returned as the tool result, and what the summarization flag changes.

for a senior

Weigh the cost — stacked latency, multiplied tokens, layered debugging — and show how you diagnose a bad answer by reading the request string the caller composed before blaming the sub-agent.

for a principal

Own the composition policy: how deep nesting may go, when a specialist should be a callable tool versus a transfer target, and how descriptions are curated so callers route correctly at scale.

## The construct `AgentTool` lives in ADK's tools package and takes an agent: `AgentTool(agent=summarizer)`. You place it in another agent's `tools` list exactly like a function tool. From the calling model's point of view there is no difference between this and any other tool — it sees a name, a description (drawn from the wrapped agent's description), and a parameter to fill in. That parameter is normally a single free-text request string: the caller writes, in natural language, what it wants the sub-agent to do. If the wrapped agent declares a structured input schema, the declaration reflects that instead, and the caller must produce a matching object. ## What execution looks like When the call fires, ADK does not simply append a message to the current conversation. It runs the wrapped agent as its own invocation: the sub-agent's instruction applies, its own tools are available to it, it may loop through several model calls of its own, and it produces a final response. That final response is what lands in the function response the caller sees. Two properties follow, and both are frequently probed: - **The sub-agent does not inherit the caller's transcript.** It gets the request it was handed and the session's state, not the caller's full message history. That is a feature — it is why an AgentTool is a context-isolation device — but it means anything the sub-agent needs must be in the request or in state. - **The caller sees only the outcome.** Intermediate reasoning and the sub-agent's own tool calls do not enter the caller's context. They are still visible as events for debugging, but they don't consume the caller's window. ## Call versus transfer This is the comparison interviewers actually want. ADK gives you two ways to involve another agent: | | AgentTool | agent placed in sub_agents | |---|---|---| | control | returns to the caller with a result | handed over to the other agent | | shape | a function call inside one turn | a transfer, after which that agent drives | | use it when | you need a *result* to keep working with | you need a *specialist to take over* the conversation | If the parent has to combine the sub-agent's answer with something else — merge two research results, validate an answer before showing it, use a summary as an input to a draft — you want a call, because a transfer never comes back for that turn. If the user's request is simply the other agent's job from here on, a transfer is cleaner and cheaper. ## skip_summarization By default the caller's model receives the sub-agent's output as a tool result and decides what to say next, which usually means paraphrasing it. `AgentTool(agent=..., skip_summarization=True)` suppresses that extra pass so the wrapped agent's output is used as it stands. Reach for it when the sub-agent already produced exactly the artifact you want — a formatted report, structured JSON, an exact quotation — and paraphrasing would cost a model round trip while risking distortion. Leave it off when the sub-agent returns raw material the caller genuinely needs to weave into a larger answer. ## What it costs An AgentTool call is a full agent run nested inside another agent's turn. That means: - **Latency stacks.** The caller waits for the sub-agent's entire loop, which may itself be several model calls plus tool I/O. - **Tokens multiply.** Each level pays for its own instruction and context. A three-deep nest is three prompts per user turn, minimum. - **Debugging is layered.** A bad final answer might be the caller's prompt, the request string it composed, the sub-agent's instruction, or one of the sub-agent's tools. ADK's event stream and dev UI are how you tell them apart — read the request string the caller actually sent before blaming the sub-agent. - **Failures need a story.** If the sub-agent errors or returns something useless, the caller receives that as a tool result and must decide what to do. An instruction that never anticipates a bad sub-answer produces confident nonsense. ## A second, very practical use Beyond composition, AgentTool is the standard workaround for ADK's constraints on built-in, model-executed tools: put the restricted tool on its own dedicated agent and expose that agent as an AgentTool alongside your own function tools. The wrapping buys you a compliant boundary as well as a reusable component. ## Design guidance Keep the nesting shallow — one level of AgentTool solves most problems, two is already hard to reason about. Give each wrapped agent a sharp `description`, because that description is what the caller's model reads when deciding whether to call it; a vague one produces both over-calling and never-calling. And prefer a plain function tool when there is no genuine need for a model in the loop: wrapping deterministic work in an agent just to make it callable is paying model money for an if-statement.

  • How do you decide between an AgentTool call and a transfer to a sub-agent?
    Ask whether the parent still has work to do afterwards. If it must combine, validate, or build on the specialist's output, call it as a tool so control returns with a result. If the specialist simply owns the rest of the request, transfer — a call would only add a wasted round trip and leave the parent narrating something it did not do.
  • What does the wrapped agent actually see when it is called?
    The request the caller composed for it, plus the session state, under its own instruction and with its own tools. It does not inherit the caller's message history. That isolation is the main benefit — the sub-agent's context stays small and focused — but it means anything it needs must be in the request string or in state, so a caller that writes a lazy request gets a lazy answer.
  • When is skip_summarization the wrong choice?
    When the sub-agent returns raw material rather than a finished answer — search hits, a JSON record, a numeric result — and the caller needs to fold it into a wider response. Suppressing summarization then leaks machine-shaped output straight to the user. Use it only when the wrapped agent's output is already exactly what should be shown.

Calling a colleague and waiting for their answer, versus forwarding the ticket to them and walking away. AgentTool is the phone call; a transfer is the forward.

saying these in an interview costs you the question

  • Says AgentTool hands the conversation over permanently
  • Thinks the sub-agent sees the caller's full chat history
  • Assumes the caller's context absorbs the sub-agent's intermediate steps
  • Treats a nested agent run as free compared to a function call
  • Wraps deterministic logic in an agent instead of a plain function tool

context