skip to content

Google ADK

You will learn Google's Agent Development Kit: composing agents into workflows, tools and toolsets, the runner with sessions and memory, and the dev tooling for evaluation and deployment. Interviewers ask because ADK pulls evaluation and deployment into the framework itself, which invites the question of how you actually test an agent before shipping it.

part ofAI agent & RAG frameworksoverview, primer and where to startread it →
on this pageshow

questions

24

In Google ADK, what is the difference between an agent's instruction and description?

level: juniorimportance: must knowfreq 64%

answer

  1. one faces inward, one faces outward
  2. who reads the field, and when
  3. routing metadata vs system prompt
  4. siblings compete on description text
  5. root-only field covers the whole tree

basics

~20 s

instruction is the agent's own prompt — it tells that agent how to behave. description is a one-line summary other agents read when deciding whether to hand work over, so it drives delegation rather than behaviour.

solid answer

~40 s

On an ADK `LlmAgent`, `instruction` and `description` face in opposite directions. `instruction` faces inward: it is folded into that agent's system prompt and shapes what it says, which tools it reaches for, and what format it produces. `description` faces outward: it is what a *parent or sibling* agent sees when the LLM is choosing whether to transfer control, so it is effectively routing metadata. That is why a leaf agent with no siblings can get away with a thin description, while an agent that sits inside a `sub_agents` list must have a sharp, distinctive one — vague or overlapping descriptions are the usual root cause of "the coordinator keeps picking the wrong specialist". There is also `global_instruction`, which only takes effect on the root agent and applies across the whole agent tree.

code

python · 23 lines
python
from google.adk.agents import LlmAgent

refunds = LlmAgent(
    name="refund_specialist",
    model="gemini-2.0-flash",
    description="Handles refunds and returns; does not change shipping addresses.",
    instruction="Confirm the order id, check eligibility, then state the refund amount and timeline.",
)

shipping = LlmAgent(
    name="shipping_specialist",
    model="gemini-2.0-flash",
    description="Handles delivery status and address changes; does not issue refunds.",
    instruction="Look up the shipment, report its status, and offer an address change if allowed.",
)

coordinator = LlmAgent(
    name="support_coordinator",
    model="gemini-2.0-flash",
    global_instruction="Always answer in the customer's language and never invent order details.",
    instruction="Route the customer to the right specialist. Do not answer domain questions yourself.",
    sub_agents=[refunds, shipping],
)

go deeper

for a junior

Know that instruction is the agent's own prompt and description is what other agents read when deciding to hand over. Saying that one sentence clearly is most of the answer at this level.

for a middle

Explain the consequence: descriptions are routing metadata that siblings compete on, so misrouting is a description bug while bad output is an instruction bug. Mention instruction templating with {key} placeholders.

for a senior

Show that you debug with the split — read the trace to see which agent received the turn, then fix the corresponding field — and that you write sibling descriptions as a mutually exclusive set rather than one at a time.

for a principal

Own it as a convention: cross-cutting policy lives in the root's global_instruction, routing vocabulary is standardised across teams, and description quality is treated as an interface contract because it determines routing accuracy as the tree grows.

## Two fields, two audiences An ADK `LlmAgent` is constructed with, among other things, `name`, `model`, `instruction`, `description`, `tools` and `sub_agents`. Beginners often treat `instruction` and `description` as a long and short version of the same thing. They are not: they are read by different parties at different times. **`instruction` is read by this agent's own model.** ADK assembles the agent's request and folds `instruction` in as system guidance. Everything about how the agent behaves lives here: its persona, the steps it should follow, the tools it should prefer, the output format, the refusals. If the agent misbehaves, `instruction` is what you edit. **`description` is read by *other* agents' models.** When an `LlmAgent` has `sub_agents`, ADK exposes a transfer capability to the model, and the choice of target is made from the candidate agents' `name` and `description`. So `description` is a routing label — a short, discriminative statement of what this agent is *for*, written for a reader who has only that line to go on. ## Why the split exists Keeping them separate is what makes multi-agent trees composable. An agent's internal prompt can be long, opinionated and full of formatting rules without bloating every routing decision made above it. And the routing label can be tuned independently: you can rewrite a description to fix a misrouting problem without touching the agent's behaviour at all. It also means the two fail differently, which is the practical part of the answer: - A bad `instruction` produces an agent that does the wrong thing once it is invoked. - A bad `description` produces an agent that is invoked at the wrong time, or never invoked, while its own behaviour is perfect. Diagnosing agent misbehaviour starts with deciding which of those two you are looking at. If the trace shows the wrong agent received the turn, the bug is in descriptions. If the right agent received it and then produced nonsense, the bug is in its instruction. ## Writing a good description Because descriptions compete with each other, they should be written as a set, not one at a time. Useful properties: - **Discriminative** — it should say what this agent handles that its siblings do not. Two siblings described as "answers customer questions" and "helps customers with queries" give the router nothing to choose on. - **Scoped** — naming the domain and the boundary ("handles refunds and returns; does not change shipping addresses") lets the router rule the agent out as well as in. - **Short** — every sibling's description sits in the routing context on every turn, so long descriptions are a recurring token cost across the whole tree. `name` matters for the same reason: it is the identifier the model produces when it transfers, and it appears alongside the description, so a name like `refund_specialist` is doing routing work that `agent_2` is not. ## Instruction templating `instruction` is not a static string. ADK substitutes session-state values into it using `{key}` placeholders, so an agent can be written once and re-used across steps that differ only in the data they operate on. A placeholder written as `{key?}` is treated as optional, so a missing value does not blow up the run. This is the mechanism that lets a downstream agent in a `SequentialAgent` read what an upstream agent produced. ## global_instruction There is a third field, `global_instruction`, that applies across an entire agent tree rather than to one agent. Only the root agent's `global_instruction` takes effect; setting it on a nested agent does nothing. Use it for cross-cutting rules every agent must respect — brand voice, a language requirement, a blanket prohibition — and keep per-agent behaviour in each agent's own `instruction`. Repeating the same three safety rules inside eight agents' instructions is a maintenance trap; that content belongs in `global_instruction` on the root. ## The one-line summary to give an interviewer "`instruction` is how this agent behaves; `description` is how other agents decide to call it; `global_instruction` on the root is what every agent in the tree obeys." If you can then name the failure mode each one causes when written badly, you have answered the question at the level it is actually being asked.

  • What does global_instruction do that instruction does not?
    `global_instruction` applies to every agent in the tree, but only the root agent's value takes effect — setting it on a nested agent has no effect. It is the right home for cross-cutting rules such as tone, language or blanket prohibitions, so you do not copy the same paragraph into eight agents' `instruction` fields and then have them drift apart.
  • A coordinator keeps routing billing questions to the support agent. Which field do you edit first?
    The descriptions, not the instructions. Misrouting means the transfer decision was wrong before the target agent ever ran, and that decision is made from sibling `name` and `description`. Rewrite both siblings' descriptions together so each states what it owns and what it does not, then re-test; only if the correct agent now receives the turn and still answers badly do you touch its `instruction`.
  • Does an agent with no siblings still need a description?
    It matters much less. `description` is consumed when some other agent's model is choosing a transfer target, so a single root agent or a leaf inside a `SequentialAgent` — where ordering is fixed by code — is not being selected on its description. It is still worth writing as documentation, and it becomes load-bearing the moment that agent is added to a `sub_agents` list.
  • Can instruction contain values produced earlier in the run?
    Yes — ADK substitutes session-state values into `instruction` via `{key}` placeholders, with `{key?}` marking one as optional so a missing value does not fail the run. That is how a downstream agent in a `SequentialAgent` consumes what an upstream agent wrote, without you having to build the prompt string yourself.

saying these in an interview costs you the question

  • Calling description a shorter version of instruction
  • Putting behaviour rules in description and hoping the agent follows them
  • Leaving sibling descriptions vague, then blaming the model for misrouting
  • Setting global_instruction on a nested agent and expecting it to apply
  • Thinking instruction is read by the parent agent when routing

context

open as a page

In Google ADK, what do adk web, adk run, and adk api_server each give you?

level: juniorimportance: must knowfreq 68%

basics

~20 s

adk web starts a local dev UI over your agent folder, with chat plus Events, Trace and Eval tabs. adk run drives the same agent from the terminal. adk api_server serves it as a local HTTP API.

open as a page

In Google ADK, what survives a restart with InMemorySessionService vs DatabaseSessionService?

level: juniorimportance: must knowfreq 72%

basics

~10 s

Nothing survives with InMemorySessionService — sessions, event history and state live in the process and vanish on restart. DatabaseSessionService writes them to a SQL database given by db_url, so the same session_id resumes afterwards.

open as a page

In Google ADK, how does a plain Python function become a callable tool?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Google ADK wraps any callable placed in an agent's tools list into a FunctionTool. The function name, its type-hinted parameters and its docstring become the declaration the model sees, so the docstring is functional code rather than a comment.

open as a page

In Google ADK, when do you use a workflow agent instead of an LlmAgent?

level: middleimportance: must knowfreq 72%

basics

~20 s

Use LlmAgent when the model must decide what happens next. Use ADK's SequentialAgent, ParallelAgent or LoopAgent when the order is already known: they run their sub_agents on fixed control flow and call no LLM of their own.

open as a page

In a Google ADK SequentialAgent, how does one agent's output reach the next agent?

level: middleimportance: must knowfreq 58%

basics

~20 s

Through session state, not through a return value. Set output_key on the producing LlmAgent and ADK stores its final response under that key; the next agent reads it with a {key} placeholder in its instruction, or a tool reads it from state.

open as a page

In Google ADK, what does returning a value from before_model_callback or before_tool_callback do?

level: middleimportance: must knowfreq 56%

basics

~20 s

Returning a non-None value short-circuits the step. A before_model_callback that returns an LlmResponse skips the model call and uses that response; a before_tool_callback that returns a dict skips the tool and uses that dict as its result. Returning None lets the step proceed.

open as a page

In ADK's adk eval, what do tool_trajectory_avg_score and response_match_score measure?

level: middleimportance: must knowfreq 62%

basics

~20 s

tool_trajectory_avg_score compares the tool calls the agent actually made — names and arguments, in order — against the ones recorded in the eval case, averaged over invocations. response_match_score compares the final response text to the expected text using ROUGE-1 similarity.

open as a page

In Google ADK session state, what do the app:, user: and temp: prefixes do?

level: middleimportance: must knowfreq 58%

basics

~20 s

They set scope. An unprefixed key belongs to one session; app: is shared by every user of that app_name; user: follows one user_id across all their sessions; temp: exists only for the current invocation and is never persisted.

open as a page

What does Google ADK's Runner.run_async yield, and how do you spot the final reply?

level: middleimportance: must knowfreq 66%

basics

~20 s

Runner.run_async is an async generator of Event objects — one per model chunk, tool call, tool response and agent message. Check event.is_final_response() to find the turn's answer; event.partial marks streaming fragments you should not treat as final.

open as a page

In Google ADK, how does a tool get a ToolContext and what can it do with it?

level: middleimportance: must knowfreq 68%

basics

~20 s

Declare a parameter annotated with ADK's ToolContext type and the framework injects it, hiding it from the model's schema. Through it a tool reads and writes session state, sets actions such as skipping summarization or transferring control, and reaches artifacts, memory and auth.

open as a page

In Google ADK, how does an .evalset.json file differ from a .test.json file?

level: middleimportance: should knowfreq 52%

basics

~20 s

A test file captures one simple session and is meant to run cheaply and often, like a unit test. An eval set file holds many named eval cases, each a full multi-turn session with its own starting state, and is the integration-tier artifact you record from the dev UI.

open as a page

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

level: middleimportance: should knowfreq 54%

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.

open as a page

How does a Google ADK LoopAgent decide to stop iterating?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Two ways only: it reaches max_iterations, or a sub-agent escalates — by setting escalate on the tool context's actions, or emitting an event with escalate set. With neither configured, the loop keeps re-running its sub_agents indefinitely.

open as a page

What does Google ADK's ParallelAgent isolate between branches, and what do they share?

level: seniorimportance: should knowfreq 46%

basics

~20 s

ParallelAgent gives each sub-agent its own branch of the conversation history, so branches do not see each other's messages. They still run against one shared session state, so two branches writing the same key race and the loser's work vanishes silently.

open as a page

What breaks when an ADK agent that worked under adk web is deployed to Cloud Run?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Conversations vanish and tool calls start getting denied. In-memory session, artifact and memory services are per-process, and Cloud Run runs many replaceable instances; local user credentials are replaced by the service account, and the dev UI and tracing are opt-in flags at deploy time.

open as a page

Why doesn't mutating session.state directly persist in Google ADK, and what does?

level: seniorimportance: should knowfreq 44%

basics

~20 s

The Session you hold is a snapshot; the session service only writes state when an Event is appended. Changes must travel as EventActions.state_delta on that event, so an in-place edit to the returned dict is lost on the next load.

open as a page

In Google ADK, how does MemoryService recall differ from the session's event history?

level: seniorimportance: should knowfreq 48%

basics

~20 s

Session history is this thread's events, reloaded in full every turn. A MemoryService is a separate searchable store of past sessions: you ingest finished ones with add_session_to_memory, and the agent queries them on demand through the load_memory tool.

open as a page

In Google ADK, how does LongRunningFunctionTool handle a pending human approval?

level: seniorimportance: should knowfreq 42%

basics

~20 s

The wrapped function returns an interim result immediately, such as a pending status with a ticket id, and ADK marks that call as long-running on the event it emits. The turn ends without blocking; the real outcome is delivered later as a function response carrying the same call id.

open as a page

How do you decide the shape of a large Google ADK agent tree as it grows?

level: principalimportance: should knowfreq 36%

basics

~20 s

Decide per node whether the next step is a judgment or a known fact. Known steps become workflow agents; genuine judgment becomes a small set of sub_agents with sharply distinct descriptions. Every extra transfer hop is another model call, another failure point, and another thing to evaluate.

open as a page

How do you choose between Vertex AI Agent Engine and Cloud Run for an ADK agent?

level: principalimportance: should knowfreq 38%

basics

~20 s

Choose Agent Engine when you want the platform to own sessions, memory and tracing and you accept Vertex coupling. Choose Cloud Run when you need control of the container, dependencies and networking, or the agent must live inside an existing service. Both are one adk deploy command.

open as a page

Your ADK agent runs on several replicas — which session, memory and artifact services do you pick?

level: principalimportance: should knowfreq 34%

basics

~20 s

Every in-memory service must go: they are per-process, so a request landing on another replica sees no session. Pick a shared backend for each — a database or Vertex session service, a durable memory service, and GcsArtifactService for blobs — and decide retention per store.

open as a page

In Google ADK, how do you decide which OpenAPIToolset operations an agent gets?

level: principalimportance: should knowfreq 34%

basics

~20 s

OpenAPIToolset generates one callable REST tool per operation in the spec, so a large API becomes hundreds of tools. Curate deliberately: filter the toolset down to the operations an agent actually needs, and split the rest across separate agents rather than loading one agent with everything.

open as a page