google-adk
Building agents with Google ADK (Agent Development Kit): project scaffolding and `root_agent` conventions, LlmAgent parameters, workflow agents (Sequential/Parallel/Loop) and custom BaseAgent orchestr
SKILL.mdplugins/ai/skills/google-adk/SKILL.md
GitHubGoogle ADK (Agent Development Kit)
ADK is Google's open-source framework for building, debugging, and deploying agents — described by the vendor as building "reliable AI agents at enterprise scale." This skill covers building with it: agent types, tools, multi-agent composition, sessions and state, callbacks, evaluation, and the Google Cloud deployment paths.
Docs domain: the canonical https://google.github.io/adk-docs/ now 301-redirects to https://adk.dev/ (confirmed 2026-08-05). Send users to adk.dev; a stale bookmark still works but the URL in their browser will change.
Corpus fetched 2026-08-05. Where this skill says a detail is unverified, it is genuinely absent from the fetched docs — say so rather than guessing.
Answering rules
Always establish which language and which major line before answering. ADK ships in five languages (Python, TypeScript, Go, Java, Kotlin) but only Python 2.0 (GA 2026-05-19) and Go 2.0 (GA 2026-06-30) have reached the 2.0 graph-based line; Java, Kotlin, and TypeScript are still 1.x. A 2.0 answer given to a Java user is wrong.
Always confirm the app defines a module-level root_agent before debugging "my agent doesn't load". adk create, adk run, and adk eval all resolve the agent through that symbol.
Never propose adk web as a production surface. The docs state plainly: "ADK Web is not meant for use in production deployments." Production goes to Agent Runtime, Cloud Run, GKE, or a custom container.
Never leave a LoopAgent without a termination mechanism. The docs are explicit that LoopAgent does not inherently decide when to stop — set max_iterations and give a sub-agent an escalation path (tool_context.actions.escalate = True).
Never assume ParallelAgent branches share state. Each sub-agent runs as an independent branch with no automatic state sharing and non-deterministic completion order — use distinct output_keys plus a downstream synthesis agent (the gather pattern).
Never ship InMemorySessionService or InMemoryArtifactService to production. Both are documented as development/testing only and lose everything on restart.
Never write a broad try...except around agent logic on ADK 2.0 — it masks failures from the framework's automatic retry mechanism. Let exceptions propagate.
Always send a user to the local loop first — adk run for a terminal conversation, adk web for the dev UI and its interactive eval threshold sliders. That beats reasoning about the agent's behavior from source.
Install and scaffold
Python:
python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1
pip install google-adk
pip show google-adk # verify
adk create my_agent
adk create generates agent.py, .env, and __init__.py. The .env holds GOOGLE_API_KEY="YOUR_API_KEY" for the API-key path.
Java — two artifacts: com.google.adk:google-adk (library) and com.google.adk:google-adk-dev (a Spring Boot server for running agents), both pinned at 1.6.0 in the docs as of 2026-08-05. Gradle builds must pass -parameters to javac — ADK Java relies on parameter-name reflection.
Minimal Python agent — note the module-level root_agent:
from google.adk.agents.llm_agent import Agent
def get_current_time(city: str) -> dict:
"""Returns the current time in a specified city."""
return {"status": "success", "city": city, "time": "10:30 AM"}
root_agent = Agent(
model='gemini-flash-latest',
name='root_agent',
description="Tells the current time in a specified city.",
instruction="You are a helpful assistant...",
tools=[get_current_time],
)
Run locally: adk run my_agent (CLI chat), adk web --port 8000 (dev UI at http://localhost:8000), adk api_server (REST endpoints).
Agent types
| Type | Control flow | Decided by |
|---|---|---|
LlmAgent / Agent |
Reasoning loop over tools | The model |
SequentialAgent |
Sub-agents in fixed order | Code (deterministic) |
ParallelAgent |
Sub-agents concurrently | Code (deterministic) |
LoopAgent |
Sub-agents in order, repeated | Code + explicit termination |
Custom (BaseAgent subclass) |
Arbitrary | Your code |
LlmAgent requires name and model; the parameters that actually shape behavior are instruction, description (used by other agents to route to this one), tools, output_key (writes the final response text into session state), output_schema / input_schema, generate_content_config, include_contents, planner, and code_executor.
Instructions support template variables resolved from state: {var}, {artifact.var} for artifact text, and {var?} for an optional variable. Only the ? form is documented as "missing variable is ignored without error" — use it for anything not guaranteed to be set.
SequentialAgent passes the same InvocationContext to every sub-agent, so state (including temp:) flows step to step; that is what makes output_key → {key} chaining work. ParallelAgent does not.
Custom agents subclass BaseAgent and implement one async generator method — _run_async_impl (Python), runAsyncImpl (TypeScript/Java), Run (Go) — yielding events. Reach for one only when conditional branching on runtime results, dynamic agent selection, or external calls inside the orchestration itself rule out the built-ins. On ADK 2.0, agents subclass BaseNode and overrides of legacy _run_async_impl() are bypassed — see references/versions/2.0.md before porting a custom agent.
Read references/agents-and-workflows.md for the full LlmAgent parameter table, per-language constructor shapes for all workflow agents, worked pipeline/gather/refinement examples, and the escalation pattern.
Tools
Any Python function in an agent's tools list becomes a tool. ADK derives the schema from the function's name, docstring, type hints, and defaults — the docstring is what the model reads, so write full Args:/Returns: sections.
from google.adk.tools import ToolContext
def get_weather(city: str, unit: str, tool_context: ToolContext) -> dict:
"""
Retrieves the weather for a city in the specified unit.
Args:
city (str): The city name.
unit (str): The temperature unit, either 'Celsius' or 'Fahrenheit'.
"""
user_id = tool_context.state.get("user_id")
return {"status": "success", "report": f"Weather for {city} is sunny."}
Rules that change model behavior:
- Required vs optional is expressed by the default, not by wording — a type hint with no default is required.
- Return a
dict. Non-dict returns are auto-wrapped as{"result": value}. Include a"status"key (success/error/pending) so the model can tell success from failure. - A parameter annotated
ToolContextis auto-injected and hidden from the model — only the annotation matters, not the parameter name. Use it forstate,actions(escalate,transfer_to_agent), andsearch_memory. - Pass data between tools inside one turn through the
temp:state prefix; tools in a single agent turn share the invocation context. - Favor few parameters and primitive types; avoid generic names like
do_stuff().
MCP — McpToolset discovers an MCP server's tools, converts their schemas, and proxies calls. Both directions are supported: ADK as MCP client, and exposing ADK tools through a custom MCP server.
McpToolset(connection_params=StdioConnectionParams(server_params=StdioServerParameters(
command='npx', args=['-y', '@modelcontextprotocol/server-filesystem', '/path/to/folder'])))
McpToolset(connection_params=StreamableHTTPConnectionParams(
url="https://mapstools.googleapis.com/mcp", headers={'X-Goog-Api-Key': api_key}))
Filter with tool_filter, bound with timeout, stream progress with progress_callback. For Cloud Run and GKE, define the toolset synchronously in agent.py — an async definition is a documented deployment failure mode.
OpenAPI — OpenAPIToolset(spec_str=..., spec_str_type="json") or spec_dict=... parses an OpenAPI v3.x spec and emits one RestApiTool per operation; auth_scheme + auth_credential on the toolset apply to all of them.
Built-in tools (Google Search, code execution, RAG) are a documented gap here. The /tools-custom/ and /grounding/ pages name them and defer implementation detail to the separate /integrations/ catalog, which is not in this corpus. State the capability exists — Google Search grounding, grounding with Vertex AI Search, agentic RAG — and send the user to https://adk.dev/ integrations rather than inventing import paths.
For the MCP protocol itself (spec, transports, OAuth, writing servers) use the mcp sibling skill.
Read references/tools-and-mcp.md for the full function-tool signature rules, nullable parameters, the complete MCP connection options, and the OpenAPI toolset details.
Multi-agent composition
Two distinct mechanisms — do not conflate them:
- Sub-agent delegation (in-process). A coordinator
LlmAgentlists specialists insub_agents; ADK auto-generates a delegation tool and control returns automatically on completion. This is distinct from a manualtransfer_to_agentcall. - A2A (across the network). Expose an agent as an
A2AServer, consume a remote one withRemoteA2aAgent.
Delegation behavior is governed by the sub-agent's mode:
| Mode | User interaction | Return to parent | Notes |
|---|---|---|---|
chat (default) |
Full | Manual | Not recommended for structured workflows |
task |
Clarifications only | Automatic on finish_task |
Cannot itself have sub-agents; disabled in graph workflows on Python 2.0.0 |
single_turn |
None | Automatic on completion | Supports parallel execution of multiple sub-agents |
weather_agent = Agent(name="weather_checker", mode="single_turn",
tools=[get_weather, user_info, geocode_address])
coordinator = Agent(name="travel_planner", sub_agents=[weather_agent, flight_agent])
Task-mode and single-turn agents each run in their own session branch — parallel agents cannot observe each other's context and the parent receives aggregated results only. Design for that: anything a sibling needs must come back through the parent.
Reach for A2A when integrating standalone services owned by different teams, crossing language/framework boundaries, building microservices, or enforcing a formal contract. Avoid it for internal code organization, high-frequency low-latency calls needing shared memory, or simple helpers — those are local components. ADK's A2A implementation preserves reasoning traces, tracks long-running tools to prevent timeouts, and transfers artifacts.
A managed agent is a third thing: an agent whose reasoning, tools, and execution environment are hosted and operated by Google, consumed as a component rather than orchestrated locally.
Gap: the dedicated /agents/routing/ page (LLM-driven transfer, AgentTool, transfer_to_agent mechanics) is not in this corpus. Answer transfer questions from the mode system above and flag the rest as unverified.
Read references/agents-and-workflows.md for collaboration-mode constraints and references/deployment-and-a2a.md for the A2A surface and per-language quickstart URLs.
Sessions, state, memory, artifacts
A Session is one ongoing user↔agent interaction: id, user_id, state (mutable dict), events (chronological history). Created via a SessionService and passed into runner.run_async().
State prefixes decide lifetime — this is the single most useful thing to teach:
| Prefix | Scope |
|---|---|
temp: |
Current invocation/turn only |
user: |
Across all of one user's sessions (needs a persistent SessionService) |
app: |
Application-wide, all users |
| (none) | This session |
SessionService implementations: InMemoryService (dev/testing), DatabaseSessionService (production, database-backed), VertexAiSessionService (cloud-managed). Writes like context.state["key"] = value are auto-tracked into EventActions.state_delta and applied by the service when persisting the event — which is what preserves the audit trail and scope hierarchy. Never mutate persisted state out of band.
MemoryService searches historical context and external knowledge, reached from a tool: tool_context.search_memory("query about topic").
Artifacts are named, versioned binary data (google.genai.types.Part with inline_data + mime_type), session-scoped by plain filename or cross-session with a user: prefix:
version = await context.save_artifact(filename="report.pdf", artifact=pdf_part)
artifact = await context.load_artifact(filename="report.pdf") # latest
artifact = await context.load_artifact(filename="report.pdf", version=0) # pinned
filenames = await context.list_artifacts()
InMemoryArtifactService for dev; GcsArtifactService for production, with user-level namespacing.
Read references/sessions-state-artifacts.md for the service comparison, delta-tracking behavior, artifact versioning/namespacing rules, and use cases.
Callbacks
Six hook points, each with a documented return contract that is the whole reason to use them:
| Callback | Returning None |
Returning a value |
|---|---|---|
before_agent_callback |
Normal execution | Content → skips agent logic, becomes the final response |
after_agent_callback |
— | Content replaces the agent's output |
before_model_callback |
Proceeds with the LLM call | LlmResponse → bypasses the LLM entirely |
after_model_callback |
— | modified LlmResponse |
before_tool_callback |
Executes the tool | Dict → skips the tool, used as its result |
after_tool_callback |
— | modified tool result Dict |
Register them as LlmAgent constructor kwargs. Use them for guardrails (validate inputs/outputs, enforce safety rules), caching (before_model_callback returning a cached LlmResponse), observation/logging, and state management — the documented use cases.
Prefer a callback over prompt wording whenever the user wants a guarantee. before_tool_callback returning a dict is an enforced block; an instruction asking the model not to call the tool is not.
Read references/callbacks-and-runtime.md for exact signatures, the runtime execution surfaces, and what the runtime sub-pages do and do not cover here.
Evaluation
adk eval <AGENT_MODULE_FILE_PATH> <EVAL_SET_FILE_PATH> \
--config_file_path=test_config.json --print_detailed_results
AGENT_MODULE_FILE_PATH points at the __init__.py containing root_agent. Multiple evalset files are allowed, and file.json:eval_1,eval_2 filters to specific cases.
An evalset holds eval cases, each a distinct session: eval_id, conversation (multi-turn user content + expected final_response), session_input (app_name, user_id, state), and intermediate_data (expected tool trajectories and sub-agent responses).
Default metrics when none are specified: tool_trajectory_avg_score at 1.0 — 100% tool-trajectory match, which is strict and the usual cause of surprise failures — and response_match_score at 0.8. Override in test_config.json. LLM-judged criteria also available: final_response_match_v2, hallucinations_v1, safety_v1, with multi-turn variants.
In CI, wrap it with pytest:
from google.adk.evaluation.agent_evaluator import AgentEvaluator
@pytest.mark.asyncio
async def test_agent():
await AgentEvaluator.evaluate(agent_module="agent_name",
eval_dataset_file_path_or_dir="tests/eval_file.test.json")
For eval methodology across vendors — designing suites, judge design, regression strategy — use the evals sibling skill; this section is the ADK harness only.
Read references/evaluation.md for the full .test.json schema and threshold configuration.
Deployment
| Target | Command | When |
|---|---|---|
| Agent Runtime (Agent Platform) | adk deploy agent_engine |
Fully managed, auto-scaling; least infra to own |
| Cloud Run | adk deploy cloud_run |
Container-based managed compute |
| GKE | adk deploy gke (Python) or manual |
More control, or running open models |
| Custom container | your own image | Any container-compatible infra, disconnected systems |
"Agent Runtime on Agent Platform" is ADK's current name for what the docs previously called Agent Engine / Vertex AI Agent Engine — expect both names in the wild.
adk deploy cloud_run --project=$GOOGLE_CLOUD_PROJECT --region=$GOOGLE_CLOUD_LOCATION \
--service_name=$SERVICE_NAME --app_name=capital_agent --with_ui $AGENT_PATH
--project and --region are required; --with_ui ships the web interface; --session_service_uri (e.g. sqlite://, agentengine://) and --artifact_service_uri wire persistence. Raw gcloud flags pass through after --.
adk deploy agent_engine packages the code, builds a container, and deploys to the managed service. Language support is Python and Go v1.2.0+ only as of 2026-08-05 — and the Python package deliberately excludes the ADK API server and web UI libraries while Go includes the dedicated API server. A user expecting adk web on a Python Agent Runtime deployment will not find it.
Read references/deployment-and-a2a.md for the manual gcloud/Dockerfile/main.py path, the TypeScript/Go/Java commands, GKE cluster + Workload Identity setup, deployed-agent smoke tests, the A2A surface, and Live/bidi streaming (run_live(), LiveRequestQueue, RunConfig streaming mode).
ADK 2.0 and version gating
ADK 2.0 replaces the hierarchical agent executor with a graph-based execution engine where agents, tools, and functions are nodes. Four things break on upgrade: event schema gains node_info and output (custom DB schemas must accommodate them), agents subclass BaseNode so legacy _run_async_impl() overrides are bypassed, broad try...except masks the automatic retry mechanism, and the Go import path moves to google.golang.org/adk/v2.
The 1.x line is still maintained in parallel (v1.37.0 shipped 2026-07-30, same day as v2.6.0) — a team not ready for graph workflows can stay on 1.x rather than being forced forward.
Read references/versions/2.0.md first whenever a user reports a behavior that "used to work", names a version, or is on Java/Kotlin/TypeScript.
Reference files
references/agents-and-workflows.md—LlmAgentparameters, Sequential/Parallel/Loop semantics and per-language constructors, custom agents, collaboration modesreferences/tools-and-mcp.md— function-tool schema rules,ToolContext,McpToolsetconnections,OpenAPIToolset, grounding and the built-in-tools gapreferences/sessions-state-artifacts.md— session objects, state prefixes,SessionServiceimplementations, memory, artifact versioningreferences/callbacks-and-runtime.md— six callback signatures and return contracts, runtime execution surfacesreferences/evaluation.md—adk evalCLI, evalset/.test.jsonschema, metrics and thresholds, pytest integrationreferences/deployment-and-a2a.md— Cloud Run/Agent Runtime/GKE/custom container, A2A, Live streamingreferences/versions/2.0.md— ADK 2.0 graph engine, migration breakages, per-language GA status, recent release history
Diagnostic script
scripts/adk-preflight.py— read-only environment check: Python version, installedgoogle-adkversion,adkCLI presence, whether a target agent directory actually definesroot_agent, and which ADK-relevant environment variables are set (names only, values masked). Runpython scripts/adk-preflight.py [agent_dir]before debugging load or deploy failures.
Known gaps in this skill's sources
State these rather than filling them from memory:
- Built-in tool import paths and code samples (Google Search, code execution, Vertex AI Search) — deferred by the docs to the
/integrations/catalog, not fetched. - Exact
Runner.run_async()signature and the fullRunConfigfield list — the/runtime/sub-pages were not fetched individually. /agents/routing/— LLM-driven transfer,AgentTool, andtransfer_to_agentmechanics.- The "Agents CLI" accelerated deployment path with CI/CD and infrastructure-as-code.
- Java parity for workflow agents, callbacks, and tools beyond the install/deploy snippets — the fetched pages default to Python samples.
Sources
- https://adk.dev/
- https://adk.dev/sitemap.xml
- https://adk.dev/get-started/installation/
- https://adk.dev/get-started/python/
- https://adk.dev/agents/llm-agents/
- https://adk.dev/agents/workflow-agents/sequential-agents/
- https://adk.dev/agents/workflow-agents/parallel-agents/
- https://adk.dev/agents/workflow-agents/loop-agents/
- https://adk.dev/agents/custom-agents/
- https://adk.dev/agents/managed-agents/
- https://adk.dev/workflows/patterns/
- https://adk.dev/workflows/collaboration/
- https://adk.dev/tools-custom/
- https://adk.dev/tools-custom/function-tools/
- https://adk.dev/tools-custom/mcp-tools/
- https://adk.dev/tools-custom/openapi-tools/
- https://adk.dev/grounding/
- https://adk.dev/context/
- https://adk.dev/sessions/
- https://adk.dev/artifacts/
- https://adk.dev/callbacks/
- https://adk.dev/runtime/
- https://adk.dev/evaluate/
- https://adk.dev/deploy/
- https://adk.dev/deploy/cloud-run/
- https://adk.dev/deploy/gke/
- https://adk.dev/deploy/agent-runtime/deploy/
- https://adk.dev/a2a/intro/
- https://adk.dev/live/
- https://adk.dev/2.0/
- https://github.com/google/adk-python/releases
Fetched: 2026-08-05