Complete Tutorial: Google Agent Development Kit (ADK) for Building AI Agents with Python
Google Agent Development Kit (ADK) is an open-source framework from Google for building, managing, and orchestrating AI agents. The framework is designed to let developers create modular, composable, and production-ready agents. ADK integrates directly with the Google Cloud ecosystem and supports various LLM models including Gemini, Claude, and GPT.
In this tutorial, we will learn how to use Google ADK from basics to advanced features, complete with code examples you can run immediately.
Why Google ADK?
Before jumping into implementation, it is important to understand ADK's advantages over other agent frameworks:
- Multi-Agent Architecture: ADK natively supports multi-agent orchestration, enabling you to build complex agent systems with ease
- Google Cloud Integration: Directly integrates with Vertex AI, Gemini API, and other Google Cloud services
- Model Agnostic: While optimized for Gemini, ADK can be used with any LLM model through LiteLLM
- Built-in Tools: Provides ready-to-use tools for Google Search, code execution, and more
- Session Management: Integrated session and memory management system
- Streaming Support: Supports streaming responses for a better user experience
Installation and Setup
System Requirements
Make sure you have Python 3.9 or later installed on your system.
python --version # Minimum Python 3.9
Installing ADK
Install Google ADK using pip:
pip install google-adk
For additional features like evaluation and deployment:
pip install google-adk[eval]
pip install google-adk[a2a]
Configuring the API Key
ADK requires an API key to access LLM models. You can use a Gemini API key or Google Cloud credentials.
Using Gemini API Key:export GOOGLEAPIKEY="your-gemini-api-key"
Using Google Cloud:
export GOOGLECLOUDPROJECT="your-project-id"
export GOOGLECLOUDLOCATION="us-central1"
gcloud auth application-default login
Project Structure
ADK uses a specific folder structure convention. Create the following project structure:
myagentproject/
├── myagent/
│ ├── init.py
│ └── agent.py
└── requirements.txt
The init.py file must export an agent variable:
from .agent import agent
Creating Your First Agent
Simple Agent
Let's start by creating a simple agent that can answer questions:
# myagent/agent.py
from google.adk.agents import Agent
agent = Agent(
model="gemini-2.0-flash",
name="assistant",
description="An AI assistant agent that helps answer questions",
instruction="""You are a friendly and helpful AI assistant.
Answer user questions clearly and concisely.
Provide accurate and well-structured responses.""",
)
Running the Agent
There are several ways to run an agent:
Using CLI:adk run myagent
Using Web UI:
adk web myagent
Programmatically:
import asyncio
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
async def main():
sessionservice = InMemorySessionService()
runner = Runner(
agent=agent,
appname="myapp",
sessionservice=sessionservice,
)
session = await sessionservice.createsession(
appname="myapp",
userid="user1",
)
from google.genai.types import Content, Part
response = runner.run(
userid="user1",
sessionid=session.id,
newmessage=Content(
role="user",
parts=[Part(text="What is machine learning?")]
),
)
async for event in response:
if event.content and event.content.parts:
for part in event.content.parts:
if part.text:
print(part.text)
asyncio.run(main())
Adding Tools to Your Agent
Tools are functions that an agent can call to perform specific actions. ADK supports several types of tools.
Function Tools
The simplest way to add tools is by defining regular Python functions:
from google.adk.agents import Agent
def calculatebmi(weightkg: float, heightcm: float) -> dict:
"""Calculate Body Mass Index (BMI).
Args:
weightkg: Body weight in kilograms.
heightcm: Height in centimeters.
Returns:
Dictionary containing the BMI value and its category.
"""
heightm = heightcm / 100
bmi = weightkg / (heightm * 2)
if bmi < 18.5:
category = "Underweight"
elif bmi < 25:
category = "Normal"
elif bmi < 30:
category = "Overweight"
else:
category = "Obese"
return {
"bmi": round(bmi, 1),
"category": category,
}
def converttemperature(value: float, fromunit: str, tounit: str) -> dict:
"""Convert temperature between units.
Args:
value: Temperature value to convert.
fromunit: Source unit (celsius, fahrenheit, kelvin).
tounit: Target unit (celsius, fahrenheit, kelvin).
Returns:
Dictionary containing the conversion result.
"""
if fromunit == "celsius":
celsius = value
elif fromunit == "fahrenheit":
celsius = (value - 32) 5 / 9
elif fromunit == "kelvin":
celsius = value - 273.15
else:
return {"error": f"Unknown unit '{fromunit}'"}
if tounit == "celsius":
result = celsius
elif tounit == "fahrenheit":
result = celsius 9 / 5 + 32
elif tounit == "kelvin":
result = celsius + 273.15
else:
return {"error": f"Unknown unit '{tounit}'"}
return {"result": round(result, 2), "unit": tounit}
agent = Agent(
model="gemini-2.0-flash",
name="calculatoragent",
description="A calculator agent with various computation functions",
instruction="You are a calculator assistant. Use the available tools to help with calculations.",
tools=[calculatebmi, converttemperature],
)
Built-in Tools
ADK provides several built-in tools that can be used directly:
from google.adk.agents import Agent
from google.adk.tools import googlesearch, codeexecution
agent = Agent(
model="gemini-2.0-flash",
name="researchagent",
description="A research agent that can search the internet for information",
instruction="""You are an AI researcher. Use Google Search to find the latest
information and code execution for data analysis.""",
tools=[googlesearch, codeexecution],
)
Agent as Tool
One of ADK's powerful features is the ability to use other agents as tools:
from google.adk.agents import Agent
translator = Agent(
model="gemini-2.0-flash",
name="translator",
description="Translates text to the requested language",
instruction="You are a translator. Translate the given text to the requested language.",
)
summarizer = Agent(
model="gemini-2.0-flash",
name="summarizer",
description="Summarizes long text into key points",
instruction="You are a summarizer. Create a concise summary of the given text.",
)
agent = Agent(
model="gemini-2.0-flash",
name="contentprocessor",
description="Main agent that processes content",
instruction="""You are a content processor. Use the translator to translate
and the summarizer to summarize text based on user requests.""",
tools=[translator, summarizer],
)
Multi-Agent Systems
ADK provides several orchestration patterns for more complex multi-agent systems.
Sequential Agent
Sequential agent runs sub-agents in order, passing output from one agent to the next:
from google.adk.agents import SequentialAgent, Agent
collectoragent = Agent(
model="gemini-2.0-flash",
name="datacollector",
description="Collects data from given sources",
instruction="Collect and organize data from the given input.",
)
analystagent = Agent(
model="gemini-2.0-flash",
name="dataanalyst",
description="Analyzes collected data",
instruction="Analyze the given data and generate insights.",
)
writeragent = Agent(
model="gemini-2.0-flash",
name="reportwriter",
description="Writes reports based on analysis",
instruction="Write a comprehensive report based on the given analysis.",
)
agent = SequentialAgent(
name="datapipeline",
description="Automated data analysis pipeline",
subagents=[collectoragent, analystagent, writeragent],
)
Parallel Agent
Parallel agent runs multiple sub-agents simultaneously:
from google.adk.agents import ParallelAgent, Agent
sentimentagent = Agent(
model="gemini-2.0-flash",
name="sentimentanalyzer",
description="Analyzes text sentiment",
instruction="Analyze the text sentiment: positive, negative, or neutral.",
)
topicagent = Agent(
model="gemini-2.0-flash",
name="topicextractor",
description="Extracts main topics from text",
instruction="Identify the main topics from the given text.",
)
entityagent = Agent(
model="gemini-2.0-flash",
name="entityextractor",
description="Extracts entities from text",
instruction="Identify people names, organizations, and locations from the text.",
)
agent = ParallelAgent(
name="textanalyzer",
description="Parallel text analysis",
subagents=[sentimentagent, topicagent, entityagent],
)
Loop Agent
Loop agent runs sub-agents repeatedly until a certain condition is met:
from google.adk.agents import LoopAgent, Agent
writeragent = Agent(
model="gemini-2.0-flash",
name="writer",
description="Writes and improves text",
instruction="""Write or improve text based on feedback.
If the text is already good, respond with 'DONE'.""",
)
revieweragent = Agent(
model="gemini-2.0-flash",
name="reviewer",
description="Reviews and provides feedback on text",
instruction="""Review the text and provide improvement feedback.
If the text is already excellent, respond with 'APPROVED'.""",
)
agent = LoopAgent(
name="writingloop",
description="Writing loop with iterative review",
subagents=[writeragent, revieweragent],
maxiterations=3,
)
Session and Memory Management
InMemory Session
For development and testing, use InMemorySessionService:
from google.adk.sessions import InMemorySessionService
sessionservice = InMemorySessionService()
session = await sessionservice.createsession(
appname="myapp",
userid="user1",
)
print(f"Session ID: {session.id}")
Session State
You can store and access state within a session:
from google.adk.agents import Agent
def savepreference(key: str, value: str, toolcontext) -> str:
"""Save a user preference.
Args:
key: Preference name.
value: Preference value.
toolcontext: Tool context (automatically provided by ADK).
Returns:
Confirmation message.
"""
toolcontext.state[key] = value
return f"Preference '{key}' saved with value '{value}'"
def getpreference(key: str, toolcontext) -> str:
"""Retrieve a user preference.
Args:
key: Name of the preference to retrieve.
toolcontext: Tool context (automatically provided by ADK).
Returns:
Preference value or error message.
"""
value = toolcontext.state.get(key)
if value:
return f"Preference '{key}': {value}"
return f"Preference '{key}' not found"
agent = Agent(
model="gemini-2.0-flash",
name="preferenceagent",
description="An agent that remembers user preferences",
instruction="Help users save and retrieve their preferences.",
tools=[savepreference, getpreference],
)
Database Session
For production, use DatabaseSessionService with support for various databases:
from google.adk.sessions import DatabaseSessionService
sessionservice = DatabaseSessionService(
dburl="postgresql://user:pass@localhost:5432/mydb"
)
Callbacks and Guardrails
Before Model Callback
Use callbacks to modify or validate input before sending it to the model:
from google.adk.agents import Agent
from google.genai.types import Content, Part
def contentfilter(callbackcontext, llmrequest):
"""Filter sensitive content before sending to the model."""
usermessage = llmrequest.contents[-1]
if usermessage and usermessage.parts:
text = usermessage.parts[0].text.lower()
blockedwords = ["hack", "exploit", "bypass"]
for word in blockedwords:
if word in text:
return Content(
role="model",
parts=[Part(text="Sorry, I cannot help with that request.")]
)
return None
agent = Agent(
model="gemini-2.0-flash",
name="safeagent",
description="An agent with content filtering",
instruction="Answer user questions safely.",
beforemodelcallback=contentfilter,
)
After Model Callback
Use the after callback to process or validate model output:
def formatresponse(callbackcontext, llmresponse):
"""Format model response before sending to the user."""
if llm
response.content and llmresponse.content.parts:
for part in llm
response.content.parts:
if part.text:
part.text = part.text.strip()
if not part.text.endswith((".", "!", "?")):
part.text += "."
return llmresponse
agent = Agent(
model="gemini-2.0-flash",
name="formattedagent",
description="An agent with response formatting",
instruction="Answer user questions.",
aftermodelcallback=formatresponse,
)
Using Models Other Than Gemini
ADK supports other LLM models through LiteLLM integration:
from google.adk.agents import Agent
from google.adk.models.litellm import LiteLlm
claudeagent = Agent(
model=LiteLlm(model="anthropic/claude-sonnet-4-20250514"),
name="claudeagent",
description="An agent using Claude",
instruction="You are an assistant powered by Claude.",
)
gptagent = Agent(
model=LiteLlm(model="openai/gpt-4o"),
name="gptagent",
description="An agent using GPT-4",
instruction="You are an assistant powered by GPT-4.",
)
Make sure the corresponding API keys are configured:
export ANTHROPICAPIKEY="your-anthropic-key"
export OPENAIAPIKEY="your-openai-key"
Example Project: Customer Support Agent
Here is a complete example of a customer support agent using multi-agent patterns:
# customersupport/agent.py
from google.adk.agents import Agent
def find
order(ordernumber: str) -> dict:
"""Find order information by order number.
Args:
order
number: Customer order number (format: ORD-XXXX).
Returns:
Dictionary containing order details.
"""
orders = {
"ORD-1001": {
"status": "Shipped",
"carrier": "FedEx",
"tracking": "FX1234567890",
"estimate": "2-3 business days",
},
"ORD-1002": {
"status": "Processing",
"estimate": "Will ship within 24 hours",
},
}
order = orders.get(ordernumber)
if order:
return {"found": True, *order}
return {"found": False, "message": "Order not found"}
def searchproducts(query: str) -> dict:
"""Search products by keyword.
Args:
query: Product search keyword.
Returns:
Dictionary containing matching products.
"""
products = [
{"name": "Laptop Pro X", "price": 1299.99, "stock": 5},
{"name": "Wireless Mouse Z", "price": 29.99, "stock": 50},
{"name": "Mechanical Keyboard K", "price": 89.99, "stock": 20},
]
results = [p for p in products if query.lower() in p["name"].lower()]
return {"products": results, "total": len(results)}
def createticket(subject: str, description: str, priority: str) -> dict:
"""Create a new support ticket.
Args:
subject: Ticket subject.
description: Problem description.
priority: Priority level (low, medium, high).
Returns:
Dictionary containing the created ticket information.
"""
return {
"ticketid": "TKT-2001",
"subject": subject,
"priority": priority,
"status": "Created",
"message": "Ticket created successfully. Our team will contact you within 24 hours.",
}
orderagent = Agent(
model="gemini-2.0-flash",
name="orderagent",
description="Handles questions about orders and shipping",
instruction="""You handle order-related questions.
Use the findorder tool to check order status.
Provide clear and concise information.""",
tools=[findorder],
)
productagent = Agent(
model="gemini-2.0-flash",
name="productagent",
description="Handles questions about products and catalog",
instruction="""You handle product-related questions.
Use the searchproducts tool to find products.
Provide recommendations that match customer needs.""",
tools=[searchproducts],
)
supportagent = Agent(
model="gemini-2.0-flash",
name="supportagent",
description="Handles complaints and creates support tickets",
instruction="""You handle customer complaints.
Use the createticket tool to create support tickets.
Show empathy and provide solutions.""",
tools=[createticket],
)
agent = Agent(
model="gemini-2.0-flash",
name="customersupport",
description="Main customer support agent",
instruction="""You are the main customer support agent.
Route questions to the appropriate sub-agent:
- Order and shipping questions -> orderagent
- Product and catalog questions -> productagent
- Complaints and issues -> supportagent
Greet customers warmly and professionally.""",
tools=[orderagent, productagent, supportagent],
)
Deployment with Vertex AI
To deploy an agent to production using Vertex AI:
from google.adk.cli import deploy
deploy.deploytovertexai(
agentmodule="customersupport",
projectid="your-project-id",
location="us-central1",
displayname="Customer Support Agent",
)
Or using the CLI:
adk deploy cloudrun \
--project=your-project-id \
--region=us-central1 \
--app
name=customer-support \
customersupport
Best Practices
1. Clear and Specific Instructions
Write detailed and specific instructions for each agent. The clearer the instructions, the better the agent performance.
# Less effective
instruction = "Answer questions."
More effective
instruction = """You are a senior data analyst.
When receiving data-related questions:
Identify the relevant metrics
Explain visible trends
Provide actionable recommendations
Format your answers in easily readable bullet points."""
2. Document Tools with Docstrings
ADK uses function docstrings to explain tools to the model. Make sure docstrings are complete with parameter descriptions and return values.
3. Error Handling in Tools
Always handle errors inside tool functions and return informative error messages:
def fetchdata(url: str) -> dict:
"""Fetch data from a URL.
Args:
url: Data source URL.
Returns:
Dictionary containing data or error message.
"""
try:
import requests
response = requests.get(url, timeout=10)
response.raiseforstatus()
return {"success": True, "data": response.json()}
except requests.RequestException as e:
return {"success": False, "error": str(e)}
4. Use Session State for Context
Leverage session state to store conversation context and user preferences, so the agent can provide more personalized responses.
5. Limit Agent Scope
Each agent should have specific responsibilities. Use multi-agent patterns to divide complex tasks into smaller, manageable parts.
6. Testing with ADK Eval
Use ADK's built-in evaluation framework to test agent performance:
from google.adk.evaluation import evaluate
results = evaluate(
agent=agent,
testcases=[
{
"input": "What is my BMI? Weight 70 kg, height 175 cm",
"expectedtoolcalls": ["calculatebmi"],
"expectedoutputcontains": ["Normal"],
},
],
)
print(f"Pass rate: {results.pass_rate}%")
Conclusion
Google Agent Development Kit (ADK) provides a robust foundation for building AI agents in Python. With support for multi-agent orchestration, tool management, session handling, and Google Cloud integration, ADK is suitable for building AI applications from prototype to production.
Key takeaways:
- Start with a simple agent and add complexity gradually
- Leverage multi-agent patterns for complex tasks
- Write clear instructions and docstrings
- Use session state to maintain context
- Always test your agents before deploying to production
For more information, visit the official Google ADK documentation and example projects in its GitHub repository. Happy building!