What You’ll Learn
By the end of this post, you’ll:
- Understand what Google ADK is
- Build a working AI agent from scratch
- Understand ADK’s core architecture (App, Agent, Tools)
Prerequisites: Python 3.10+, basic Python knowledge, an API key for an LLM provider (Google, OpenAI, or Anthropic)
What is Google ADK?
Google ADK (Agent Development Kit) is an open-source, code-first toolkit for building AI agents. It’s Google’s answer to the growing complexity of agent development, designed to make building production-grade agents as straightforward as building a web API.
What Makes ADK Stand Out
ADK is built around a few core principles:
1. Model Agnostic Use any LLM provider (Google, OpenAI, Anthropic, local models) through LiteLLM integration. Switch providers with a single config change.
2. Production-Ready Features Built-In
- Multi-agent orchestration: Sequential, Parallel, and Loop agents for complex workflows
- Human-in-the-loop: First-class support for approval workflows
- Safety guardrails: Before/after callbacks for policy enforcement
- Observability: Native OpenTelemetry integration for tracing and monitoring
3. Flexible Deployment (Deployment Agnostic) Deploy anywhere - Cloud Run, Vertex AI, GKE, or your own infrastructure. ADK doesn’t lock you into a specific platform.
4. Simple Just three concepts to learn to get started: App, Agent, and Tools. Everything else builds on these fundamentals.
Core Architecture
ADK has three main concepts:

App: The container that holds everything. Handles configuration, plugins, and exposes the API.
Agent: The brain. Combines an LLM with instructions and tools to accomplish tasks.
Tools: Functions the agent can call to interact with the world (APIs, databases, files, etc.).
Setting Up Your Environment
Let’s build your first agent. First, set up your project:
# Create a new parent directory. All ADK agents will be created in this directory
mkdir agents
cd agents
# Create a virtual environment (recommended)
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install ADK
pip install google-adk
# Create the first agent
mkdir my_first_adk_agent
cd my_first_adk_agent
Configure Your API Key
If you don’t already have a Gemini API key, create a key in Google AI Studio on the API Keys page.
Create a .env file:
GOOGLE_API_KEY=your-google-api-key
Building Your First Agent
Create a file called agent.py:
"""
My First ADK Agent
A simple agent that can answer questions and do basic math.
"""
from google.adk.agents import LlmAgent
from google.adk.apps.app import App
# Step 1: Define your tools
def add_numbers(a: float, b: float) -> float:
"""Add two numbers together.
Args:
a: First number
b: Second number
Returns:
The sum of a and b
"""
return a + b
def multiply_numbers(a: float, b: float) -> float:
"""Multiply two numbers together.
Args:
a: First number
b: Second number
Returns:
The product of a and b
"""
return a * b
def get_current_time() -> str:
"""Get the current date and time.
Returns:
Current date and time as a string
"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Step 3: Create your agent
assistant = LlmAgent(
name="assistant",
model='gemini-3-flash-preview',
instruction="""You are a helpful assistant that can:
- Answer general questions
- Perform basic math calculations using the add_numbers and multiply_numbers tools
- Tell the user what time it is using the get_current_time tool
Always be friendly and helpful. When asked to do math, use the appropriate tool
rather than calculating in your head.
""",
tools=[add_numbers, multiply_numbers, get_current_time]
)
# Step 4: Create your app
app = App(
name="my_first_adk_agent",
root_agent=assistant
)
That’s it! You’ve built an AI agent in about 50 lines of code.
Running Your Agent
ADK provides multiple ways to run your agent:
Note
Run these commands from the parent directory that contains your
my-first-adk-agent/folder. For example, if your agent is insideagents/my-first-adk-agent/, runadk web,adk runfrom the agents/ directory.
Option 1: Command Line
adk run my_first_adk_agent

Option 2: Interactive Playground (Recommended for Development)
adk web
This opens a web UI where you can chat with your agent, see tool calls, and debug.

Option 3: API Server
adk api_server
This starts a FastAPI server and exposes agent’s API interface. The server would be started at http://localhost:8000. You should be able to use /list-apps, /run, etc. A few example invocations are given below.
List apps
curl -X GET "http://localhost:8000/list-apps" \
-H "Content-Type: application/json"
Create a new session
curl -X POST "http://localhost:8000/apps/my_first_adk_agent/users/u_123/sessions/s_123"
Chat with the agent
curl -X POST "http://localhost:8000/run" \
-H "Content-Type: application/json" \
-d '{
"appName": "my_first_adk_agent",
"userId": "u_123",
"sessionId": "s_123",
"newMessage": {
"role": "user",
"parts": [
{
"text": "What is the current time"
}
]
}
}'

Option 4: Programmatic
Create a file called test_agent.py:
"""
Test your agent programmatically
"""
import asyncio
from google.adk.runners import InMemoryRunner
from agent import assistant
async def main():
# Create an in-memory runner (simplest option for testing)
runner = InMemoryRunner(agent=assistant)
# Test conversations
test_messages = [
"What time is it?",
"What's 25 plus 17?",
"Can you multiply 8 by 9?",
"Hello! What can you help me with?"
]
for message in test_messages:
print(f"\n{'='*50}")
print(f"User: {message}")
print(f"{'='*50}")
# Run the agent using run_debug (requires ADK v1.18.0+)
response = await runner.run_debug(message, verbose=False)
print(f"Agent: {response}")
if __name__ == "__main__":
asyncio.run(main())
Run it:
python test_agent.py
Understanding What Just Happened
Let’s break down the key components:
1. Tools Are Just Functions
def add_numbers(a: float, b: float) -> float:
"""Add two numbers together.
Args:
a: First number
b: Second number
Returns:
The sum of a and b
"""
return a + b
ADK automatically:
- Extracts the function signature for the LLM
- Parses the docstring for parameter descriptions
- Handles calling the function when the LLM requests it
No decorators, no special classes, just Python functions.
2. The LLM Model
model = 'gemini-3-flash-preview'
We are using the Gemini 3 Flash model. ADK supports other LLM Providers via LiteLLM integration.
3. Agents Combine Everything
assistant = LlmAgent(
name="assistant", # Unique identifier
model=model, # The LLM to use
instruction="...", # System prompt
tools=[...] # Available tools
)
The LlmAgent class handles:
- Sending messages to the LLM
- Managing conversation history
- Executing tool calls
- Returning responses
4. The App is the Container
app = App(
name="my_first_agent",
root_agent=assistant
)
The App handles:
- Configuration and plugins
- Session management
- Exposing the agent via API
- Lifecycle management
Adding More Functionality
Let’s enhance our agent with a more useful tool - a weather lookup:
def get_weather(city: str) -> dict:
"""Get the current weather for a city.
Args:
city: The city name to get weather for
Returns:
Weather information including temperature and conditions
"""
# In a real app, you'd call a weather API here
# For demo purposes, we'll return mock data
import random
conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
return {
"city": city,
"temperature_f": random.randint(60, 85),
"temperature_c": random.randint(15, 30),
"conditions": random.choice(conditions),
"humidity": f"{random.randint(30, 80)}%"
}
# Add it to your agent's tools
assistant = LlmAgent(
name="assistant",
model='gemini-3-flash-preview',
instruction="""You are a helpful assistant that can:
- Answer general questions
- Perform basic math calculations
- Tell the user what time it is
- Check the weather for any city
When reporting weather, format it nicely for the user.
""",
tools=[add_numbers, multiply_numbers, get_current_time, get_weather]
)
Project Structure Best Practices
As your agent grows, organize your code like this:
my-adk-project/
├── .env # API keys (don't commit this!)
├── agent.py # Agent definition and App
├── tools/
│ ├── __init__.py
│ ├── math_tools.py # Math-related tools
│ ├── time_tools.py # Time-related tools
│ └── weather_tools.py # Weather tools
├── instructions/
│ └── assistant.txt # Agent instructions (for longer prompts)
└── tests/
└── test_agent.py # Agent tests
Example tools/math_tools.py:
"""Math tools for the assistant agent."""
def add_numbers(a: float, b: float) -> float:
"""Add two numbers together."""
return a + b
def multiply_numbers(a: float, b: float) -> float:
"""Multiply two numbers together."""
return a * b
def divide_numbers(a: float, b: float) -> float:
"""Divide the first number by the second.
Args:
a: The dividend
b: The divisor (must not be zero)
Returns:
The quotient of a divided by b
"""
if b == 0:
return {"error": "Cannot divide by zero"}
return a / b
Example instructions/assistant.txt:
You are a helpful assistant with the following capabilities:
## Core Functions
- Answer general knowledge questions
- Perform mathematical calculations using available tools
- Provide current time information
- Check weather conditions for any city
## Behavior Guidelines
1. Always use tools for calculations - don't compute in your head
2. Be friendly and conversational
3. If you don't know something, say so honestly
4. When providing weather info, format it nicely
## Response Style
- Keep responses concise but helpful
- Use bullet points for lists
- Include relevant details without overwhelming the user
Updated agent.py:
"""Main agent definition."""
from pathlib import Path
from google.adk.agents import LlmAgent
from google.adk.apps.app import App
from tools.math_tools import add_numbers, multiply_numbers, divide_numbers
from tools.time_tools import get_current_time
from tools.weather_tools import get_weather
def load_instructions(filename: str) -> str:
"""Load agent instructions from a file."""
path = Path(__file__).parent / "instructions" / filename
return path.read_text()
assistant = LlmAgent(
name="assistant",
model='gemini-3-flash-preview',
instruction=load_instructions("assistant.txt"),
tools=[
add_numbers,
multiply_numbers,
divide_numbers,
get_current_time,
get_weather
]
)
app = App(
name="my_assistant",
root_agent=assistant
)
Common Pitfalls and Solutions
1. “My tool isn’t being called”
Problem: The LLM ignores your tool.
Solution: Make sure your docstring clearly explains when to use the tool:
# Bad - vague description
def process_data(data: str) -> str:
"""Process the data."""
pass
# Good - clear use case
def format_phone_number(phone: str) -> str:
"""Format a phone number into standard (XXX) XXX-XXXX format.
Use this when the user provides a phone number that needs formatting,
or when you need to validate/standardize a phone number.
Args:
phone: A phone number in any format (e.g., "1234567890", "123-456-7890")
Returns:
Formatted phone number like "(123) 456-7890"
"""
pass
2. “Tool errors aren’t handled gracefully”
Solution: Return error information instead of raising exceptions:
def divide_numbers(a: float, b: float) -> dict:
"""Divide two numbers."""
if b == 0:
return {"error": "Cannot divide by zero", "suggestion": "Please provide a non-zero divisor"}
return {"result": a / b}
3. “My agent is slow”
Solution:
- Use a faster model for simple tasks (
gemini-3-flash-previewvsgemini-3-pro-preview) - Make tools async for I/O operations
- Use caching for repeated API calls
Complete Code
Here’s the final, complete code for your first agent:
"""
My First ADK Agent - Complete Example
"""
from datetime import datetime
from google.adk.agents import LlmAgent
from google.adk.apps.app import App
# Tools
def add_numbers(a: float, b: float) -> float:
"""Add two numbers together.
Args:
a: First number
b: Second number
Returns:
The sum of a and b
"""
return a + b
def multiply_numbers(a: float, b: float) -> float:
"""Multiply two numbers together.
Args:
a: First number
b: Second number
Returns:
The product of a and b
"""
return a * b
def get_current_time() -> str:
"""Get the current date and time.
Returns:
Current date and time as a string
"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def get_weather(city: str) -> dict:
"""Get the current weather for a city.
Args:
city: The city name to get weather for
Returns:
Weather information including temperature and conditions
"""
import random
conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]
return {
"city": city,
"temperature_f": random.randint(60, 85),
"conditions": random.choice(conditions)
}
# Agent
assistant = LlmAgent(
name="assistant",
model='gemini-3-flash-preview',
instruction="""You are a helpful assistant that can:
- Answer general questions
- Perform basic math (use add_numbers, multiply_numbers)
- Tell the current time (use get_current_time)
- Check weather for any city (use get_weather)
Always use tools for calculations. Be friendly and helpful.
""",
tools=[add_numbers, multiply_numbers, get_current_time, get_weather]
)
# App
app = App(
name="my_first_agent",
root_agent=assistant
)
Run with:
adk web
Resources
📚 Series Navigation: This is Post 1 of the Google ADK Tutorial Series.
→ Next: LiteLLM Integration: Making Your ADK Agents Model-Agnostic
