Google ADK — intro
Google's Agent Development Kit is the Gemini-native agent framework. LlmAgent, tools, sessions, runners — plus a web UI for local dev. Here's the shape.
What you'll learn
- What Google ADK is and where it fits next to MAF and LangGraph
- The core building blocks — LlmAgent, tools, sessions, runners
- Hello-world: an LlmAgent on Gemini that answers a question
- The `adk web` local dev UI and CLI
Before you start
If you’re on Google Cloud, you’ll meet Agent Development Kit (ADK)
— the google-adk Python package Google shipped to be the
Gemini-native answer to MAF and LangGraph. ADK is opinionated where it
matters: Gemini is the default, Vertex AI is the deployment story, and
there’s a local web UI for developing agents without a CLI loop.
It also supports non-Gemini models via LiteLLM, so you’re not locked in — but the design clearly assumes Gemini-first, with everything else working via a compatibility shim.
The building blocks
ADK has four core concepts:
| Block | What it is |
|---|---|
| LlmAgent | An LLM + instructions + tools. The unit of agency. |
| Tools | Python functions exposed to the agent — same idea as MAF. |
| Sessions | Conversation state (like MAF threads). |
| Runners | The execution layer — wire an agent to a session and run it. |
The mental model maps almost 1:1 onto MAF. The differences are in ergonomics and defaults, not in fundamentals — both frameworks implement the same agent loop you saw in the tool-calling lesson.
Hello-world
The smallest ADK program: an LlmAgent, a session service, a
Runner, an async call.
# requires: pip install google-adk
# Shape only — google-adk needs a real Python process and Gemini access; read it as reference code.
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
# 1. The agent. instruction = system prompt; tools come next lesson.
agent = LlmAgent(
name="data-explainer",
model="gemini-2.5-flash",
instruction=(
"You explain data engineering concepts in two sentences. "
"Never use marketing language."
),
)
# 2. A session service. In-memory is fine for dev; production swaps in
# a persistent backend (Vertex AI Session Service, Cloud Memorystore, etc).
session_service = InMemorySessionService()
# 3. A runner ties the agent to a session.
runner = Runner(
agent=agent,
app_name="lesson-app",
session_service=session_service,
)
# 4. Create a session for a user, then call the agent.
async def main():
session = await session_service.create_session(
app_name="lesson-app",
user_id="u_1",
)
events = runner.run_async(
user_id="u_1",
session_id=session.id,
new_message="What is a window function in SQL?",
)
async for event in events:
if event.is_final_response():
print(event.content.parts[0].text)
# In real code: asyncio.run(main())
print("Shape only — needs Gemini API access to actually run.")
A few things worth flagging:
runner.run_asyncyields events, not a single result. You stream through them and pick out the final response (or intermediate tool calls, model thoughts, etc.). The event-stream API is ADK’s fundamental shape — internalize it early.- Sessions live in a session service. The agent itself is
stateless — this is deliberate: one
LlmAgentdefinition can serve thousands of users simultaneously because all per-user state lives in the session, not in the agent.(app_name, user_id, session_id)is the unique key. model="gemini-2.5-flash"— a string, not an object. ADK resolves to Gemini by default; for OpenAI/Anthropic/etc you’d wrap the model name inLiteLlm(model="openai/gpt-4.1")or similar.
Here’s a question worth holding onto. When your agent calls the wrong tool, or quietly stalls mid-loop, where do you look? Every framework emits events; few make them easy to watch. Keep that in mind — ADK’s answer is a dev tool the others mostly lack.
The web UI — adk web
ADK ships with a local dev UI: run adk web in a directory that
contains your agent module, and it serves a browser-based playground.
You can chat with the agent, inspect every event (tool calls, model
thoughts, token counts), and iterate without a CLI loop.
# Project layout:
# my_agents/
# __init__.py
# research_agent/
# __init__.py
# agent.py # defines `root_agent`
$ adk web my_agents
# → browser opens to localhost:8000
This is the single best ergonomic feature ADK has over MAF and LangGraph. You see the whole event trace inline. For development, nothing beats it.
The CLI
ADK also has a CLI for scaffolding and running agents headlessly:
adk create my_agent # scaffold an agent project
adk run my_agent # run in the terminal
adk eval my_agent ./tests # run evals against fixtures
adk deploy ... # push to a deploy target
The CLI is the recommended entry point — it sets up the
project structure ADK expects (one folder per agent, agent.py
exporting root_agent).
When ADK wins
The honest opinion:
- You’re on Google Cloud. Vertex AI integration is first-class, auth via Application Default Credentials just works, and Agent Engine is the easiest one-command deploy of any agent framework.
- You want Gemini, specifically. Gemini Flash is fast and cheap for most agent jobs; ADK uses it as the default and gives you native features (Google Search grounding, Vertex code execution) without wrappers.
- You like the event-stream model. ADK’s event API is more fine-grained than MAF’s — useful for building UIs that show “agent thinking” or per-step traces.
When not to reach for ADK:
- You need .NET parity. ADK is Python-first; there’s a Java SDK but the community center of gravity is Python.
- You’re on Azure with no Google footprint. MAF is the better fit.
- You want maximum framework neutrality. LangGraph treats every provider equally; ADK gives Gemini preferential treatment.
In one breath
- ADK is Google’s
google-adkSDK — the Gemini-native agent framework, with Vertex AI as the deployment story; non-Gemini models work through a LiteLLM shim. - Four building blocks: LlmAgent (LLM + instructions + tools), Tools (Python functions), Sessions (conversation state), Runner (ties an agent to a session and runs the loop).
- The agent is stateless; all per-user state lives in the session, keyed by
(app_name, user_id, session_id)— so one agent definition can serve thousands of users at once. runner.run_asyncyields a stream of events (tool calls, model thoughts, the final response), not one return value — internalize the event stream early.adk webis a local dev UI for inspecting every event, not a deploy target — ship to Agent Engine, Cloud Run, or GKE. Reach for ADK on Google Cloud or when you want Gemini; off-GCP, MAF or LangGraph fit better.
Quick check
Quick check
Next
The next lesson shows tools in ADK — how to define them, how multiple tools coexist, and the built-in tools (Google Search grounding, code execution) you get for free.
Practice this in an interview
All questionsAn agent is an LLM placed in a loop where it reasons, chooses and calls tools or actions, observes the results, and repeats until a goal is met, rather than producing one response and stopping. The key differences are autonomy, tool use, memory and state, and multi-step control flow driven by the model's own decisions.
Tool calling extends the LLM's output space to include structured function invocations. The model emits a JSON object naming a tool and its arguments; the runtime executes the tool and feeds the result back as a new message. An agent is a loop that repeats this cycle — observe, think, act — until the task is complete or a stopping condition is met.
Function calling lets an LLM output a structured request to invoke an external function with arguments, which the runtime executes and feeds back, enabling agents to act in the world. Good tool design uses clear names and descriptions, minimal well-typed parameters, narrow single-purpose scope, least privilege, and informative error messages so the model can choose and call them reliably.
In LlamaIndex a Node is a chunk of a source document with metadata and relationships, indexed for retrieval; a query engine wraps an index to take a natural-language query, retrieve relevant nodes, and synthesize an answer. RAG-as-a-tool wraps a query engine in a QueryEngineTool so an agent can call it like any other tool, deciding when to retrieve from that knowledge source as part of its reasoning loop.