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.

DimensionLangGraphGoogle ADK
ProviderOpen-source (LangChain Inc)First-party Google Cloud
Graph ModelDirected graph with explicit nodes and conditional edgesWorkflow with Edge definitions and node() routing
State ManagementExplicit TypedDict schema passed between nodesctx.state dict on the Context object
Control FlowConditional edges via Python functions returning node namesEdge(from_node=..., route="...") matched against routing function return values
Tool Integration@tool decorator and bind_tools() on the modelNative Gemini function calling inside Agent
Model FlexibilityAny LLM: Anthropic, OpenAI, Gemini, Ollama, and moreOptimized for Gemini; other providers require custom adapters
DebuggingLangSmith tracing, in-memory state inspectionADK event streaming via runner.run_async(), Vertex AI logs
Use CaseAny LLM provider, complex graph topologies, open ecosystemGCP-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 point
requirements.txt
google-adk==2.2.0
python-dotenv>=1.0.0
Installation
$ pip install -r requirements.txt
API 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

BloggerRoot WorkflowResilientPlannerWorkflowResilientWriterWorkflowFinalAgentAgentBlogPlanneroutput_key: blog_outlineOutlineValidatoroutput_key: validation_resultRouteOutlineOK / RETRYBlogWriteroutput_key: blog_postBlogPostValidatoroutput_key: validation_resultRoutePostOK / RETRYRETRYRETRY

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

  • Agent is the leaf unit - model, instruction, and output_key are the three required pieces; agents communicate via named state keys, not explicit argument passing
  • Workflow is 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, read ctx.state, return a route string matched against Edge.route values
  • output_key is how agents hand data forward - downstream agents see prior output because Gemini receives the full state as context when building each prompt
  • Runner + InMemorySessionService form the runtime - one session per run, events streamed asynchronously via runner.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 >= N condition in every routing function prevents infinite loops when a validator never returns "OK"