Agent skill
building-with-google-adk
Use when building AI agents with Google's Agent Development Kit (ADK). Triggers include creating ADK agents, Gemini-powered agents, multi-agent workflows, MCP integration with ADK, agent evaluation, workflow agents (Sequential/Parallel/Loop), Vertex AI deployment, or comparing OpenAI SDK with ADK. NOT when using other frameworks (OpenAI SDK, LangChain, CrewAI) or general LLM API calls.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/building-with-google-adk-panaversity-agentfactory-2
SKILL.md
Building with Google ADK
Build production-grade AI agents using Google's Agent Development Kit.
Quick Start
bash
# Install ADK
pip install google-adk
# Or with uv (recommended)
uv add google-adk
# Create new agent project
adk create my_agent
# Run locally
adk run my_agent
# Web UI for debugging
adk web
Environment Configuration
Option A: Google AI Studio (Gemini API Key)
bash
# .env
GOOGLE_API_KEY=your_gemini_api_key
Option B: Vertex AI (Production)
bash
# .env
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_PROJECT=your_project_id
GOOGLE_CLOUD_LOCATION=us-central1
bash
# Authenticate with gcloud
gcloud auth application-default login
gcloud services enable aiplatform.googleapis.com
Core Architecture
┌─────────────────────────────────────────────────────────────────┐
│ ADK Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ LlmAgent │ │WorkflowAgent │ │ BaseAgent │ │
│ │ (AI-driven) │ │(Deterministic)│ │ (Custom) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └──────────┬────────┴───────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Runner │ │
│ │ Orchestrates agent execution, handles events, state │ │
│ └────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴────────────────────────────────┐ │
│ │ SessionService │ │
│ │ InMemory (dev) | Firestore | VertexAI (production) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Tools │ │
│ │ FunctionTool | google_search | McpToolset | AgentTool │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Agent Types
1. LlmAgent (AI-Driven Routing)
python
from google.adk.agents import Agent
from google.adk.tools import google_search
root_agent = Agent(
name="assistant",
model="gemini-2.5-flash",
instruction="You are a helpful assistant. Answer user questions.",
description="Main assistant for general queries.",
tools=[google_search]
)
2. SequentialAgent (Pipeline)
python
from google.adk.agents import LlmAgent, SequentialAgent
researcher = LlmAgent(
name="researcher",
model="gemini-2.5-flash",
instruction="Research the topic thoroughly.",
tools=[google_search]
)
writer = LlmAgent(
name="writer",
model="gemini-2.5-flash",
instruction="Write an article based on the research."
)
pipeline = SequentialAgent(
name="content_pipeline",
description="Research, then write.",
sub_agents=[researcher, writer]
)
3. ParallelAgent (Concurrent Execution)
python
from google.adk.agents import LlmAgent, ParallelAgent
fact_checker = LlmAgent(name="fact_checker", ...)
sentiment_analyzer = LlmAgent(name="sentiment", ...)
parallel_analysis = ParallelAgent(
name="analysis",
description="Run fact-checking and sentiment analysis in parallel.",
sub_agents=[fact_checker, sentiment_analyzer]
)
4. LoopAgent (Iterative Refinement)
python
from google.adk.agents import LlmAgent, LoopAgent
from google.adk.tools import exit_loop
solver = LlmAgent(
name="solver",
model="gemini-2.5-flash",
instruction="Solve the problem. Call exit_loop when complete.",
tools=[exit_loop]
)
iterative_solver = LoopAgent(
name="iterative_solver",
description="Iterate until solution found.",
sub_agents=[solver],
max_iterations=5
)
Tools
Function Tools (Custom Python Functions)
python
from google.adk.tools import FunctionTool
def get_weather(city: str) -> dict:
"""Get weather for a city.
Args:
city: The city name to get weather for.
Returns:
Weather data including temperature and conditions.
"""
# Implementation
return {"city": city, "temp": "22°C", "condition": "Sunny"}
agent = Agent(
name="weather_agent",
model="gemini-2.5-flash",
instruction="Provide weather information.",
tools=[get_weather] # ADK auto-wraps as FunctionTool
)
Built-in Tools
python
from google.adk.tools import google_search
from google.adk.code_executors import BuiltInCodeExecutor
agent = Agent(
name="research_agent",
model="gemini-2.0-flash",
tools=[google_search],
code_executor=BuiltInCodeExecutor() # Enables code execution
)
AgentTool (Agent as Tool)
python
from google.adk.tools.agent_tool import AgentTool
search_agent = Agent(
name="search_agent",
model="gemini-2.0-flash",
tools=[google_search],
instruction="You specialize in Google searches."
)
code_agent = Agent(
name="code_agent",
model="gemini-2.0-flash",
code_executor=BuiltInCodeExecutor(),
instruction="You specialize in code execution."
)
# Coordinator uses other agents as tools
root_agent = Agent(
name="coordinator",
model="gemini-2.0-flash",
instruction="Delegate search tasks to search_agent, code to code_agent.",
tools=[AgentTool(agent=search_agent), AgentTool(agent=code_agent)]
)
MCP Integration
python
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
root_agent = LlmAgent(
model='gemini-2.0-flash',
name='filesystem_agent',
instruction='Help users manage their files.',
tools=[
McpToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command='npx',
args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
)
)
)
]
)
Running Agents
Development: adk run
bash
adk run my_agent # Terminal chat
adk web # Web UI with debugging
Programmatic Execution
python
from google.adk import Agent, Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
agent = Agent(
name="assistant",
model="gemini-2.5-flash",
instruction="You are helpful."
)
runner = Runner(
app_name="my_app",
agent=agent,
session_service=InMemorySessionService()
)
async def run():
session = await runner.session_service.create_session(
app_name="my_app",
user_id="user123"
)
message = types.Content(
role='user',
parts=[types.Part(text="Hello!")]
)
async for event in runner.run_async(
user_id=session.user_id,
session_id=session.id,
new_message=message
):
if event.content and event.content.parts:
for part in event.content.parts:
if part.text:
print(part.text)
Simplified Debugging
python
from google.adk.runners import InMemoryRunner
runner = InMemoryRunner(agent=agent)
await runner.run_debug("Hello!") # Quick test
Session & State Management
State in Session
python
# Access state in tool functions
from google.adk.tools.tool_context import ToolContext
def get_preference(tool_context: ToolContext) -> str:
"""Get user preference from session state."""
return tool_context.state.get("preference", "default")
def set_preference(preference: str, tool_context: ToolContext) -> dict:
"""Set user preference in session state."""
tool_context.state["preference"] = preference
return {"status": "saved"}
Production Session Services
python
# Firestore for persistence
from google.adk.sessions import FirestoreSessionService
session_service = FirestoreSessionService(
project="your-project",
database="(default)"
)
# Vertex AI for managed deployment
from google.adk.sessions import VertexAiSessionService
session_service = VertexAiSessionService(
project="your-project",
location="us-central1"
)
Guardrails & Callbacks
Before Model Callback (Input Guardrail)
python
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_request import LlmRequest
from google.adk.models.llm_response import LlmResponse
from google.genai import types
from typing import Optional
def block_keyword_guardrail(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
"""Block requests containing BLOCK keyword."""
last_message = ""
if llm_request.contents:
for content in reversed(llm_request.contents):
if content.role == 'user' and content.parts:
last_message = content.parts[0].text or ""
break
if "BLOCK" in last_message.upper():
return LlmResponse(
content=types.Content(
role="model",
parts=[types.Part(text="Request blocked by guardrail.")]
)
)
return None # Allow request to proceed
agent = Agent(
name="guarded_agent",
model="gemini-2.5-flash",
instruction="You are helpful.",
before_model_callback=block_keyword_guardrail
)
Before Tool Callback (Tool Guardrail)
python
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.tool_context import ToolContext
from typing import Optional, Dict, Any
def block_sensitive_city(
tool: BaseTool,
args: Dict[str, Any],
tool_context: ToolContext
) -> Optional[Dict]:
"""Block weather requests for Paris."""
if tool.name == "get_weather":
city = args.get("city", "").lower()
if city == "paris":
return {
"status": "error",
"message": "Weather for Paris is restricted."
}
return None # Allow tool execution
agent = Agent(
name="weather_agent",
model="gemini-2.5-flash",
tools=[get_weather],
before_tool_callback=block_sensitive_city
)
Evaluation
Create Test File (JSON)
json
{
"eval_set_id": "weather_agent_tests",
"eval_cases": [
{
"eval_id": "basic_weather_request",
"conversation": [
{
"user_content": {
"parts": [{"text": "What's the weather in London?"}],
"role": "user"
},
"final_response": {
"parts": [{"text": "The weather in London is..."}],
"role": "model"
},
"intermediate_data": {
"tool_uses": [
{"name": "get_weather", "args": {"city": "London"}}
]
}
}
],
"session_input": {
"app_name": "weather_agent",
"user_id": "test_user"
}
}
]
}
Run Evaluation
bash
# CLI
adk eval ./agent.py ./tests/eval_set.test.json --print_detailed_results
# Pytest integration
pytest tests/integration/
python
from google.adk.evaluation.agent_evaluator import AgentEvaluator
@pytest.mark.asyncio
async def test_weather_agent():
await AgentEvaluator.evaluate(
agent_module="weather_agent",
eval_dataset_file_path_or_dir="tests/weather_tests.test.json"
)
Deployment
Vertex AI Agent Engine
bash
uv run adk deploy agent_engine \
--project=your-project-id \
--region=us-central1 \
--staging_bucket="gs://your-bucket" \
--display_name="My Agent" \
./my_agent
Cloud Run
bash
uv run adk deploy cloud_run \
--project=your-project-id \
--region=us-central1 \
--service_name=my-agent-service \
./my_agent
Python SDK Deployment
python
from vertexai.preview import reasoning_engines
from vertexai import agent_engines
import vertexai
vertexai.init(
project="your-project",
location="us-central1",
staging_bucket="gs://your-bucket"
)
adk_app = reasoning_engines.AdkApp(
agent=root_agent,
enable_tracing=True
)
remote_app = agent_engines.create(
agent_engine=adk_app,
extra_packages=["./my_agent"],
requirements=["google-cloud-aiplatform[adk,agent_engines]"]
)
Decision Logic
| Scenario | Pattern | Why |
|---|---|---|
| Simple Q&A | Single Agent |
Minimal overhead |
| Research → Write → Edit | SequentialAgent |
Clear pipeline |
| Parallel analysis | ParallelAgent |
Faster execution |
| Iterative refinement | LoopAgent |
Convergence-based |
| Specialized routing | Agent with sub_agents |
LLM-driven delegation |
| Explicit tool routing | Multiple AgentTool |
Coordinator pattern |
| MCP server connection | McpToolset |
Standard protocol |
| Production persistence | VertexAiSessionService |
Managed, scalable |
TaskManager Example
python
from google.adk.agents import Agent
from google.adk.tools import FunctionTool
from typing import List, Optional
# In-memory task storage
tasks: List[dict] = []
def add_task(title: str, description: Optional[str] = None) -> dict:
"""Add a new task."""
task = {
"id": len(tasks) + 1,
"title": title,
"description": description,
"completed": False
}
tasks.append(task)
return {"status": "created", "task": task}
def list_tasks() -> dict:
"""List all tasks."""
return {"tasks": tasks}
def complete_task(task_id: int) -> dict:
"""Mark a task as completed."""
for task in tasks:
if task["id"] == task_id:
task["completed"] = True
return {"status": "completed", "task": task}
return {"status": "error", "message": f"Task {task_id} not found"}
def delete_task(task_id: int) -> dict:
"""Delete a task."""
global tasks
tasks = [t for t in tasks if t["id"] != task_id]
return {"status": "deleted", "task_id": task_id}
root_agent = Agent(
name="task_manager",
model="gemini-2.5-flash",
instruction="""You are a TaskManager assistant.
Help users manage their tasks:
- Add new tasks with add_task
- List all tasks with list_tasks
- Complete tasks with complete_task
- Delete tasks with delete_task
Always confirm actions and show current task list after changes.""",
tools=[add_task, list_tasks, complete_task, delete_task]
)
Common Pitfalls
| Issue | Symptom | Fix |
|---|---|---|
| Auth not working | 403 errors | Check GOOGLE_API_KEY or Vertex AI setup |
| Tools not called | Agent ignores tools | Improve instruction clarity |
| State not persisting | Data lost between runs | Use FirestoreSessionService |
| MCP server not connecting | Tool discovery fails | Verify absolute paths, check npx |
| Slow first request | 5+ second delay | Pre-warm session service |
| Sub-agents not used | Delegation fails | Add clear description to sub-agents |
Verification
Run: python3 scripts/verify.py
Expected: ✓ building-with-google-adk valid
If Verification Fails
- Check:
.envhas validGOOGLE_API_KEYor Vertex AI config - Check: Agent has required fields (
name,model,instruction) - Stop and report if still failing
References
- references/api-patterns.md - API signatures and patterns
- references/deployment-patterns.md - Production deployment
- Official ADK Docs
Didn't find tool you were looking for?