Google ADK Tutorial
A comprehensive guide to building Multi-Agent AI Systems from Scratch
1. Introduction to Google ADK
Welcome to the Google Agent Development Kit (ADK) user guide. Traditional AI chatbots are often linear and reactive—you ask a question, and they respond without reasoning across complex real-world actions. Multi-Agent systems solve this by breaking tasks down among specialized agents.
In this guide, you will learn how to go from a simple conversational agent to a fully orchestrated team of AI agents capable of planning an elaborate trip to Tokyo!
Installation
pip install google-adk
pip install python-dotenv
2. Creating Your First Agent
Every ADK agent requires three core components: name, model, and instruction.
Basic Flight Agent Code
import asyncio
from google.adk.agents import Agent
from google.adk.runners import InMemoryRunner
from dotenv import load_dotenv
# Load API keys (e.g., GOOGLE_API_KEY) from .env
load_dotenv()
flight_agent = Agent(
name="flight_agent",
model="gemini-2.5-flash",
description="Tell me the optimal route between flights.",
instruction="You are a helpful travel assistant. Help the user analyze flight setups."
)
async def main():
runner = InMemoryRunner()
await runner.run_debug(
agent=flight_agent,
prompt="How many layovers are there between New York and Tokyo?"
)
if __name__ == "__main__":
asyncio.run(main())
3. Adding Memory and Context
Without memory, an agent starts from zero with every input. By adding sessions and state, the agent can remember user preferences (like your favorite travel destinations).
LLMAgent with Session Service
from google.adk.agents import LlmAgent
from google.adk.services import InMemorySessionService
from google.adk.tools import preload_memory
from google.adk.runners import InMemoryRunner
# We upgrade to LlmAgent to better leverage state
context_flight_agent = LlmAgent(
name="flight_agent",
model="gemini-2.5-flash",
description="A flight agent with memory bridging.",
instruction="You are a travel assistant. Remember the users departure city.",
tools=[preload_memory]
)
# Start a tracked session with memory
session_service = InMemorySessionService()
runner = InMemoryRunner(session_service=session_service, app_name="TravelApp")
# Agent conversations are appended and recalled seamlessly
4. Empowering Agents with Tools
Tools are like appliances for an AI "chef". They allow the LLM to access live web data, calculate formulas, or interact with external APIs.
A. Built-In Tools (Search & Code Execution)
from google.adk.tools import google_search
from google.adk.code_executors import BuiltInCodeExecutor
# Agent with Google Search access
search_agent = Agent(
name="sightseeing_expert",
model="gemini-2.5-flash",
instruction="Use Google Search to find up-to-date sightseeing spots.",
tools=[google_search]
)
# Agent with Code Execution for budgeting
budget_agent = Agent(
name="finance_expert",
model="gemini-2.5-flash",
instruction="Calculate precise budget expenses.",
code_executor=BuiltInCodeExecutor()
)
B. Custom Python Tools
You can wrap any standard Python function with ADK so your agent can dynamically invoke it using the docstrings as a guide.
from google.adk.tools import FunctionTool
import requests
def get_weather(latitude: float, longitude: float) -> str:
"""Fetch the exact current weather mapping for specific coordinates."""
# (Mocked API call)
return "The current weather is 17.9°C"
get_weather_tool = FunctionTool(get_weather)
weather_flight_agent = Agent(
name="flight_agent",
model="gemini-2.5-flash",
description="Use get_weather to fetch conditions.",
instruction="If user asks about weather via lat/longitude, call get_weather tool.",
tools=[get_weather_tool]
)
5. Multi-Agent Orchestration
A monolith agent trying to handle hotels, flights, and activities simultaneously becomes fragile. Instead, ADK uses Coordinators resolving sub-agents.
Parallel vs Sequential Agents
Running agents in parallel speeds up queries that don't depend on each other. Sequential agents wait for prior dependencies.
from google.adk.agents import Agent, ParallelAgent, SequentialAgent
from google.adk.tools import google_search
# 1. Define distinct Specialists
flight_specialist = Agent(name="flight_specialist", model="gemini-2.5-flash", instruction="Find routes.")
hotel_expert = Agent(name="hotel_expert", model="gemini-2.5-flash", tools=[google_search], instruction="Suggest hotels.")
activity_curator = Agent(name="activity_curator", model="gemini-2.5-flash", tools=[google_search], instruction="Plan tourism activities.")
# 2. Parallel Coordination (run simultaneously)
parallel_coordinator = ParallelAgent(
name="parallel_coordinator",
description="Fetch flights, sightseeing, and hotel info in parallel.",
sub_agents=[flight_specialist, hotel_expert, activity_curator]
)
# 3. Sequential Coordination (Master Trip Planner)
travel_planner_root = SequentialAgent(
name="travel_planner",
description="Orchestrate the trip plan by running parallel checks then summarizing findings.",
sub_agents=[parallel_coordinator]
)
6. Production Safety & Deployment
Moving from a demo to production requires serious safety considerations inside your pipeline.
A. Implementing Filters
Input Filters defend against prompt injection (e.g. "ignore previous instructions"). Output Filters sanitize AI hallucinations before the user sees them.
def input_filter(user_input: str) -> bool:
"""Return False to block a prompt before it reaches the LLM."""
if "ignore previous instructions" in user_input.lower():
return False
return True
def output_filter(response: str) -> str:
"""Sanitize the LLM response replacing harmful chunks."""
if "forbidden phrase" in response.lower():
return "Sorry, I cannot answer that."
return response
B. Rate Limiting and Audit Logging
import json
from datetime import datetime, timedelta
# Audit logging
def log_event(log_entry):
timestamp = datetime.now().isoformat()
entry = {"timestamp": timestamp, "log": log_entry}
with open("audit.log", "a") as f:
f.write(json.dumps(entry) + "\n")
# Rate limiting snippet logic using session counting
# If session request limit > max_requests in time_delta -> Block action
7. Complete Functional Example
Here is a fully integrated, runnable Python script that combines Memory, Custom Tools, Sequential & Parallel Orchestration, and Safety Filters into one cohesive Multi-Agent System.
import asyncio
import json
from datetime import datetime
from google.adk.agents import Agent, ParallelAgent, SequentialAgent
from google.adk.services import InMemorySessionService
from google.adk.tools import google_search, FunctionTool
from google.adk.runners import InMemoryRunner
from dotenv import load_dotenv
# 1. Setup & Safety Environment
load_dotenv()
def input_filter(user_input: str) -> bool:
"""Security block against prompt injections."""
if "ignore previous instructions" in user_input.lower():
print("[SECURITY] Blocked malicious input.")
return False
return True
def log_event(event_type: str, details: str):
"""Audit logging for compliance."""
entry = {"timestamp": datetime.now().isoformat(), "type": event_type, "details": details}
with open("travel_audit.log", "a") as f:
f.write(json.dumps(entry) + "\n")
# 2. Custom Tools Definition
def get_weather(location: str) -> str:
"""Fetch current weather for a specific location."""
# Mocking real API for the example
return f"The current weather in {location} is sunny and 22°C."
weather_tool = FunctionTool(get_weather)
# 3. Define Specialist Agents
flight_agent = Agent(
name="flight_specialist",
model="gemini-2.5-flash",
instruction="Find the best flight routes. Extract the arrival city for other agents."
)
hotel_agent = Agent(
name="hotel_expert",
model="gemini-2.5-flash",
tools=[google_search],
instruction="Suggest top-rated hotels in the arrival city."
)
activity_agent = Agent(
name="activity_curator",
model="gemini-2.5-flash",
tools=[weather_tool],
instruction="Plan activities based on the weather tool output."
)
# 4. Multi-Agent Orchestration
# Run Hotel and Activity searches in parallel after Flight is found
destination_experts = ParallelAgent(
name="destination_experts",
description="Find hotels and activities simultaneously.",
sub_agents=[hotel_agent, activity_agent]
)
# Master orchestrator ensuring sequential logic
travel_master = SequentialAgent(
name="travel_master",
description="Coordinate the full trip.",
sub_agents=[flight_agent, destination_experts],
instruction="First find flights, then let destination experts find hotels and activities."
)
# 5. Main Execution Runner
async def main():
user_prompt = "Plan a 3-day trip to Tokyo from New York."
# Run Safety Check
if not input_filter(user_prompt):
return
log_event("REQUEST", user_prompt)
print("Starting ADK Multi-Agent System...")
# Initialize Session Memory & Runner
session_service = InMemorySessionService()
runner = InMemoryRunner(session_service=session_service, app_name="TravelApp")
# Execute Master Agent
response = await runner.run(
agent=travel_master,
prompt=user_prompt
)
log_event("RESPONSE", response)
print(f"\n--- Final Itinerary ---\n{response}")
if __name__ == "__main__":
# Execute the async loop
asyncio.run(main())