Google ADK
Google's Agent Development Kit: first-party agentic framework for Gemini and Vertex AI
Introduction
Google ADK (Agent Development Kit) is Google's first-party framework for building agentic AI systems natively on Gemini and Google Cloud, released in 2025. Where LangGraph is a community-built graph engine that works with any LLM provider, ADK is Google's opinionated, Gemini-native orchestration layer withWorkflow, Context-based state management, event streaming, and a direct path to Vertex AI Agent Engine deployment built in.
The core model is straightforward: Agent objects wrap a Gemini model, a system instruction, and an output_key that names where their output lands in shared state. Workflow objects compose agents with Edge definitions, enabling linear sequences and conditional retry loops. A Runner ties everything together with a session service and streams events asynchronously.
1. When to Use
GCP, Vertex AI, Gemini-native requirements
2. LangGraph vs ADK
Side-by-side comparison across 8 dimensions
3. Project Setup
Multi-Agent Blogger project walkthrough
4. Agent Architecture
Agent, Workflow, routing functions, Runner
5. Running the Project
ADK dev UI and programmatic runner
When to Use Google ADK
Deep GCP / Vertex AI Integration
If your infrastructure runs on Google Cloud (Vertex AI, Cloud Run, Cloud Storage, BigQuery), ADK plugs in natively. Deployment to Vertex AI Agent Engine requires zero extra wiring, and IAM, logging, and monitoring all use your existing GCP setup.
Native Gemini Features
ADK is built around Gemini. Multimodal inputs, grounding with Google Search, and native function calling are first-class features, not adapter layers bolted on after the fact. If you need Gemini-specific capabilities, ADK is the intended path.
Dynamic Agentic Task Automation
ADK's Workflow class supports retry loops, conditional routing via plain Python functions wrapped with node(), and Edge back-edges out of the box. Modeling multi-step tasks with self-correction is the primary use case.
Enterprise Google Cloud Environments
Teams already using Workspace, Cloud Identity, and GCP billing will find ADK integrates with their existing security, observability, and cost management tooling without additional connectors or configuration.
Avoid ADK when...
- Your stack runs on AWS or Azure with no plans to adopt Vertex AI
- You need to call non-Gemini models - ADK is designed for Gemini; other providers require custom adapters
- You need the broad LangChain integration ecosystem: 100+ LLM providers, vector stores, and community tools
- Your team is already productive with LangGraph and there is no concrete GCP migration on the roadmap
LangGraph SDK vs Google ADK
Both frameworks orchestrate multi-step, stateful agentic workflows, but from different philosophies. LangGraph is a general-purpose graph engine from the open-source community; ADK is a vertically integrated, first-party Google product optimized for Gemini and GCP.
| Dimension | LangGraph | Google ADK |
|---|---|---|
| Provider | Open-source (LangChain Inc) | First-party Google Cloud |
| Graph Model | Directed graph with explicit nodes and conditional edges | Workflow with Edge definitions and node() routing |
| State Management | Explicit TypedDict schema passed between nodes | ctx.state dict on the Context object |
| Control Flow | Conditional edges via Python functions returning node names | Edge(from_node=..., route="...") matched against routing function return values |
| Tool Integration | @tool decorator and bind_tools() on the model | Native Gemini function calling inside Agent |
| Model Flexibility | Any LLM: Anthropic, OpenAI, Gemini, Ollama, and more | Optimized for Gemini; other providers require custom adapters |
| Debugging | LangSmith tracing, in-memory state inspection | ADK event streaming via runner.run_async(), Vertex AI logs |
| Use Case | Any LLM provider, complex graph topologies, open ecosystem | GCP-native teams, Gemini-first workflows, Vertex AI deployment |
They Are Not Mutually Exclusive
If your team is already productive with LangGraph, ADK does not replace it. Choose ADK when Vertex AI deployment, native Gemini features, or enterprise GCP integration are hard requirements, not simply because you are building agentic systems. The two can even coexist in the same organization, with different teams choosing based on their infrastructure context.
Project Setup: Multi-Agent Blogger
The example project is a Multi-Agent Blogger: a pipeline that takes a topic, plans an outline with retry logic, writes the full article with retry logic, then generates alternative titles and a social media hook. It demonstrates ADK's core patterns: Agent, Workflow, routing functions wrapped with node(), and the Runner + session model.
Project Structure
agents-google-adk/
├── .env # GOOGLE_API_KEY=your_key_here
├── requirements.txt
└── blogger/
├── __init__.py
├── agent.py # All agents, routing functions, root_agent (Workflow)
└── main.py # Runner, session service, async entry pointrequirements.txt
google-adk==2.2.0 python-dotenv>=1.0.0
Installation
pip install -r requirements.txtAPI Key
Set GOOGLE_API_KEY=your_key_here in your .env file. Get a free key at Google AI Studio. Gemini Flash is free-tier eligible with generous rate limits for development and testing.
Agent Architecture
The Blogger pipeline has three layers. Leaf Agent objects call Gemini and write results to a named output_key in shared ctx.state. Workflow objects group leaf agents into retry loops with conditional routing. The root Workflow sequences the three stages in order.
1. Leaf Agents
Agent is the fundamental unit. Each one has a model (a Gemini model string), an instruction (its system prompt), and an output_key. When an agent runs, it calls Gemini and writes the response text to ctx.state[output_key]. Downstream agents see that value because Gemini receives the full state as context when building the next prompt.
from google.adk.agents import Agent, Context
from google.adk.workflow import Edge, START, Workflow, node
MODEL = "gemini-flash-latest"
blog_planner = Agent(
name="BlogPlanner",
description="Creates a practical, skimmable outline in Markdown",
model=MODEL,
output_key="blog_outline",
instruction="""
As a technical content strategist, produce a clear Markdown outline with:
- Title
- Short intro
- 2 main sections.
- Conclusion
If `codebase_context` exists in state, weave in specific sections/snippets.
Return only the outline in Markdown.
""",
)
outline_validator = Agent(
name="OutlineValidator",
description="Validates the outline.",
model=MODEL,
instruction="""
Check the outline (`blog_outline`) in state. If it has a title, intro,
2 sections and a conclusion, respond "OK", otherwise return "RETRY" and
list missing pieces.""",
output_key="validation_result",
)2. Routing Functions
Routing functions are plain Python functions that receive a Context, readctx.state, and return a string. That string is matched againstroute= values in Edge definitions to decide the next node. Wrap the function with node() to make it composable inside a Workflow. The tries >= 3 guard is essential: it ensures the loop exits even if the validator never returns "OK".
def _route_outline(ctx: Context) -> str:
result = ctx.state.get("validation_result", "")
tries = ctx.state.get("planner_tries", 0) + 1
ctx.state["planner_tries"] = tries
return "OK" if result.strip().upper().startswith("OK") or tries >= 3 else "RETRY"
route_outline = node(_route_outline, name="RouteOutline")3. Workflow with Retry Loop
Workflow is ADK's orchestrator. A tuple (START, a, b, c) means a linear sequence. Edge(from_node=route_outline, to_node=blog_planner, route="RETRY") adds a conditional back-edge: if route_outline returns "RETRY", execution loops back to blog_planner for another attempt.
resilient_planner = Workflow(
name="ResilientPlanner",
description="Generates and validates a blog outline, retrying up to 3 times",
edges=[
(START, blog_planner, outline_validator, route_outline),
Edge(from_node=route_outline, to_node=blog_planner, route="RETRY"),
],
)4. Root Workflow
The root Workflow chains the three stages. resilient_planner runs first and writes blog_outline to state. resilient_writer runs second, readsblog_outline (via Gemini's context), and writes blog_post.final_agent runs last to generate the titles and tweet hook.
root_agent = Workflow(
name="Blogger",
description="Plans and writes a complete blog post end-to-end.",
edges=[
(START, resilient_planner, resilient_writer, final_agent),
],
)Architecture Diagram
Multi-Agent Blogger Architecture
Three-stage pipeline: plan with retry, write with retry, then finalize. Dashed arrows are conditional back-edges.
How Agents Share Data via output_key
BlogPlanner writes its output to ctx.state["blog_outline"] viaoutput_key="blog_outline". OutlineValidator does not receive blog_outline as an argument: it sees it because ADK passes the fullctx.state as context to Gemini when building the next prompt. Downstream agents reference state keys in their instruction text (e.g. "check the outline (blog_outline) in state"), and Gemini resolves them. This is the key ADK data-passing pattern, no explicit argument threading required.
Running the Project
ADK Dev Web UI
The fastest way to try the project is the ADK development interface. From the project root:
adk web blogger/Opens the ADK dev interface at http://localhost:8000. Send a topic and watch each agent step execute in real time.
Programmatic Runner
For scripted or automated use, run via the module entry point:
python -m blogger.main "The future of agentic AI systems"from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
from .agent import root_agent
async def run(topic: str) -> None:
session_service = InMemorySessionService()
await session_service.create_session(
app_name="blogger", user_id="local", session_id="run-1"
)
runner = Runner(
node=root_agent,
app_name="blogger",
session_service=session_service,
)
async for event in runner.run_async(
user_id="local",
session_id="run-1",
new_message=types.Content(
role="user",
parts=[types.Part(text=topic)],
),
):
if event.content and event.content.parts:
for part in event.content.parts:
if part.text:
print(part.text, end="", flush=True)Streaming Events
runner.run_async() is an async generator that yields an ADK event for every agent step. The loop filters for text parts and prints them incrementally, so you see the article being written as each agent completes rather than waiting for the full pipeline to finish.
Key Takeaways
Agentis the leaf unit -model,instruction, andoutput_keyare the three required pieces; agents communicate via named state keys, not explicit argument passingWorkflowis the orchestrator -(START, a, b, c)defines a linear sequence;Edge(from_node=x, to_node=y, route="R")adds a conditional back-edge for retry loops- Routing functions are plain Python - wrap with
node(), receiveContext, readctx.state, return a route string matched againstEdge.routevalues output_keyis how agents hand data forward - downstream agents see prior output because Gemini receives the full state as context when building each promptRunner+InMemorySessionServiceform the runtime - one session per run, events streamed asynchronously viarunner.run_async()- Choose ADK for Gemini-native GCP workflows - choose LangGraph for multi-provider flexibility, complex graph topologies, and the open-source ecosystem
- Always guard retry loops - a
tries >= Ncondition in every routing function prevents infinite loops when a validator never returns"OK"