Post

Google Agent Development Kit (ADK)

An open-source, production-ready Python framework for building multi-agent systems with hierarchical orchestration, composable tools, and deployment flexibility from local development to Vertex AI.

Google Agent Development Kit (ADK)

An open-source, production-ready Python framework for building multi-agent systems with hierarchical orchestration, composable tools, and deployment flexibility from local development to Vertex AI.


What Is ADK?

The Agent Development Kit (ADK) is Google’s opinionated, code-first Python framework for building sophisticated multi-agent systems. It applies software engineering best practices (modularity, testability, composability) to agent development.

Key Philosophy:

  • Agents as Software Components: Agents are testable, versioned, and composable — not black boxes
  • Code-First Design: Define agents in Python, not YAML or UI; version-control your agent logic
  • Hierarchical Orchestration: Agents can be wrapped as tools for other agents, enabling complex multi-agent systems
  • Model Agnostic: Works with Gemini, Claude, GPT-4, or local open-source models via MCP
  • Deployment Flexibility: Same code runs locally for testing, on Cloud Run for scalable inference, or on Vertex AI for enterprise

Status (April 2025):

  • v1.0 stable, production-ready
  • Active maintenance, community extensions growing
  • Free and open-source (Apache 2.0)

Core Concepts

Agent Types

1. LLM Agents

Intelligent, language-based task execution. The model decides what tools to use and in what order.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from google.adk.agent import Agent
from google.adk.tools import Tool

class ResearchAgent(Agent):
    """Autonomously research a topic using web search and document analysis."""

    def __init__(self, model="gemini-2.5-pro"):
        super().__init__(model=model)
        self.add_tool(GoogleSearchTool())
        self.add_tool(WebFetchTool())
        self.add_tool(DocumentAnalysisTool())

    def execute(self, query: str) -> str:
        """Research the given query and return findings."""
        return self.run(f"Research: {query}")

# Usage
agent = ResearchAgent()
findings = agent.execute("Latest advances in quantum error correction")
print(findings)  # Model decides: search → fetch papers → analyze → summarize

Strengths:

  • Flexible, can adapt to new tasks without code changes
  • Good for open-ended exploration
  • Can chain multiple tools creatively

Limitations:

  • Non-deterministic (model might take unexpected paths)
  • Harder to test and debug
  • May require more tokens (exploring dead ends)

2. Workflow Agents

Deterministic state machines for predictable, sequential processes. You define the flow; the agent executes steps within it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from google.adk.agent import WorkflowAgent
from google.adk.workflows import Sequential, Parallel, Loop

class DataProcessingWorkflow(WorkflowAgent):
    """Process data through a fixed pipeline: validate → transform → analyze → report."""

    def __init__(self):
        super().__init__()

    def build_workflow(self):
        return Sequential([
            self.validate_data(),
            self.transform_data(),
            Parallel([
                self.run_statistical_analysis(),
                self.generate_visualizations()
            ]),
            self.create_report()
        ])

    def validate_data(self):
        return self.tool("DataValidationTool")

    def transform_data(self):
        return self.tool("DataTransformationTool")

    def run_statistical_analysis(self):
        return self.tool("StatisticalAnalysisTool")

    def generate_visualizations(self):
        return self.tool("ChartGenerationTool")

    def create_report(self):
        return self.tool("ReportGenerationTool")

# Usage
workflow = DataProcessingWorkflow()
report = workflow.execute(data=raw_data)

Strengths:

  • Fully deterministic, predictable behavior
  • Easy to test (each step is testable)
  • Efficient (no wasted exploration)
  • Good for production workflows

Limitations:

  • Less flexible (must code new workflows for new processes)
  • Requires upfront understanding of the full process

3. Custom Agents

Specialized agents with custom rules, decision logic, and integrations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from google.adk.agent import Agent

class RiskAssessmentAgent(Agent):
    """Custom agent with domain-specific rules for financial risk assessment."""

    def __init__(self):
        super().__init__(model="gemini-2.5-pro")
        self.add_tool(PortfolioAnalysisTool())
        self.add_tool(MarketDataTool())
        self.add_tool(RegulatoryCheckTool())

        # Custom rules (not LLM-generated)
        self.rules = {
            "leverage_max": 5.0,
            "concentration_limit": 0.15,
            "volatility_threshold": 0.3
        }

    def assess_risk(self, portfolio):
        # Mix of LLM reasoning + custom rules
        market_conditions = self.get_market_data()
        regulatory_status = self.check_regulations()

        # Custom rule checks
        leverage = self.calculate_leverage(portfolio)
        if leverage > self.rules["leverage_max"]:
            return f"CRITICAL: Leverage {leverage:.1f}x exceeds max {self.rules['leverage_max']}"

        # Use LLM for nuanced analysis
        llm_assessment = self.run(
            f"Assess risk given: {portfolio}, leverage={leverage}, regs={regulatory_status}"
        )
        return llm_assessment

The Key Innovation: Agents as Tools

ADK’s most powerful feature is composability through hierarchical orchestration.

Pattern: An agent can be wrapped as a tool for a parent agent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Level 1: Specialized agents
class CodeReviewAgent(Agent):
    """Reviews code for quality issues."""
    def execute(self, code: str) -> str:
        return self.run(f"Review: {code}")

class ArchitectureReviewAgent(Agent):
    """Reviews system design."""
    def execute(self, design: str) -> str:
        return self.run(f"Assess architecture: {design}")

class DocumentationAgent(Agent):
    """Generates documentation."""
    def execute(self, code: str) -> str:
        return self.run(f"Create docs for: {code}")

# Level 2: Orchestrator agent that uses specialized agents as tools
class ComprehensiveReviewAgent(Agent):
    """Orchestrates a full PR review using multiple specialized agents."""

    def __init__(self):
        super().__init__(model="gemini-2.5-pro")

        # Wrap specialized agents as tools
        self.code_reviewer = CodeReviewAgent()
        self.arch_reviewer = ArchitectureReviewAgent()
        self.doc_agent = DocumentationAgent()

        # Register as tools
        self.add_tool(Tool(
            name="code_review",
            func=self.code_reviewer.execute,
            description="Review code for quality issues"
        ))
        self.add_tool(Tool(
            name="architecture_review",
            func=self.arch_reviewer.execute,
            description="Review system architecture"
        ))
        self.add_tool(Tool(
            name="generate_docs",
            func=self.doc_agent.execute,
            description="Generate documentation"
        ))

    def execute(self, pr_changes: str) -> dict:
        """Comprehensive PR review."""
        return self.run(f"""
        Perform comprehensive review of PR changes:
        {pr_changes}

        Use all available tools:
        1. code_review: Check for bugs, style, performance
        2. architecture_review: Assess if design is sound
        3. generate_docs: Create/update documentation

        Synthesize findings into a single report.
        """)

# Usage
orchestrator = ComprehensiveReviewAgent()
review = orchestrator.execute(pr_changes)

Why This Matters:

  • Separation of Concerns: Each agent has one job
  • Testability: Test each agent independently
  • Reusability: Agents can be composed in new ways
  • Scaling: Agents can be deployed separately with different SLAs
  • Maintainability: Changing CodeReviewAgent doesn’t break DocumentationAgent

Tool Composition

Pre-Built Tools

ADK comes with common tools ready to use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from google.adk.tools import (
    GoogleSearchTool,
    CodeExecutionTool,
    WebFetchTool,
    FileSystemTool,
    DatabaseQueryTool,
    GoogleSheetsIntegration
)

class DataAnalysisAgent(Agent):
    def __init__(self):
        super().__init__()
        self.add_tool(GoogleSearchTool())  # Real-time web search
        self.add_tool(CodeExecutionTool())  # Execute Python in sandbox
        self.add_tool(DatabaseQueryTool(connection_string="..."))  # Query databases
        self.add_tool(GoogleSheetsIntegration(spreadsheet_id="..."))  # Read/write sheets

Custom Tools

Define your own tools easily:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from google.adk.tools import Tool

class CustomDatabaseTool(Tool):
    """Execute queries against your internal database."""

    def __init__(self, db_connection):
        super().__init__(
            name="execute_query",
            description="Execute SQL queries against production database"
        )
        self.db = db_connection

    def execute(self, query: str) -> str:
        """Execute SQL and return results as markdown table."""
        try:
            results = self.db.query(query)
            return self._format_results(results)
        except Exception as e:
            return f"Error: {e}"

    def _format_results(self, results):
        # Convert to markdown table
        ...

# Register it
agent = MyAgent()
agent.add_tool(CustomDatabaseTool(db_connection))

Third-Party Integrations (LangChain, LlamaIndex)

ADK integrates with existing ecosystems:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from google.adk.agent import Agent
from langchain.tools import Tool as LangChainTool
from llama_index.query_engine import QueryEngine

class HybridAgent(Agent):
    def __init__(self):
        super().__init__()

        # Use LangChain tools
        self.add_tool(LangChainTool.from_function(
            func=my_function,
            name="langchain_tool"
        ))

        # Use LlamaIndex query engine
        query_engine = QueryEngine(index=my_index)
        self.add_tool(Tool(
            name="rag_query",
            func=lambda q: query_engine.query(q),
            description="Query document index with RAG"
        ))

Sessions & Memory

Sessions API

Persistent conversation state across multiple agent turns.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from google.adk.sessions import Session

# Create a persistent session
session = Session(
    agent=research_agent,
    session_id="research_session_001",
    persistence_backend="firestore"  # Vertex AI Memory Bank
)

# Turn 1
session.add_message("Find information about quantum computing")
response1 = session.run()

# Turn 2 (session remembers turn 1)
session.add_message("Now summarize the key breakthroughs")
response2 = session.run()  # Can reference previous findings

# Turn 3
session.add_message("Which companies are leading in this space?")
response3 = session.run()  # Maintains full conversation context

Memory Bank (Vertex AI)

Long-term memory for agents across different sessions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from google.adk.memory import MemoryBank

class PersonalizedRecommendationAgent(Agent):
    def __init__(self, user_id):
        super().__init__()
        self.memory = MemoryBank(user_id=user_id, backend="vertex_ai")

        # Load user's previous preferences
        self.user_preferences = self.memory.get("preferences") or {}

    def execute(self, query):
        # Consider user's history in reasoning
        context = f"User preferences: {self.user_preferences}"
        response = self.run(f"{context}\nQuery: {query}")

        # Update memory with new information
        self.memory.set("last_query", query)
        self.memory.set("last_response", response)

        return response

# Usage across different sessions
user_agent = PersonalizedRecommendationAgent(user_id="user123")

# Session 1
response1 = user_agent.execute("Recommend ML papers")

# Later, different session
user_agent2 = PersonalizedRecommendationAgent(user_id="user123")
response2 = user_agent2.execute("What else should I read?")
# Agent remembers previous recommendations from memory

Deployment Options

Option 1: Local Development

1
2
3
4
pip install google-adk

# Run agent locally
python my_agent.py

Ideal for: Testing, iteration, development


Option 2: Cloud Run (Serverless)

Deploy agent as REST API with auto-scaling.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask, request
from google.cloud import run as cloud_run

app = Flask(__name__)
agent = MyAgent()

@app.route("/api/execute", methods=["POST"])
def execute():
    query = request.json.get("query")
    response = agent.execute(query)
    return {"response": response}

if __name__ == "__main__":
    # Runs on Cloud Run with automatic scaling
    app.run(host="0.0.0.0", port=8080)

Deploy:

1
2
3
4
5
gcloud run deploy my-agent \
  --source . \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_API_KEY=$GOOGLE_API_KEY

Cost: $0.15 per 1M requests (after free tier)


Option 3: Vertex AI Agent Engine (Fully Managed)

Google’s production-grade agent runtime with auto-scaling, monitoring, and compliance.

1
2
3
4
5
6
# Deploy agent to Vertex AI
gcloud adk deploy \
  --name "comprehensive-review-agent" \
  --source . \
  --region us-central1 \
  --model gemini-2.5-pro

Features:

  • Auto-scaling: Handles 1000s of concurrent agents
  • Sessions API: Persistent conversation state managed by Google
  • Memory Bank: Long-term agent memory on Vertex AI
  • Code Execution Sandbox: Safe Python/JavaScript execution within agent workflows
  • Monitoring: Built-in logging, tracing, error handling
  • Compliance: SOC 2, HIPAA, FedRAMP, GDPR certified
  • SLAs: 99.95% uptime, <500ms latency

Real-World Architecture Example

Use Case: Enterprise document analysis system for financial compliance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Tier 1: Specialist agents (testable, deployable independently)

class DocumentIngestAgent(Agent):
    """Extract text and metadata from PDFs, Word docs, etc."""
    def __init__(self):
        super().__init__(model="gemini-2.5-flash")
        self.add_tool(DocumentParsingTool())
        self.add_tool(OCRTool())

class ComplianceCheckAgent(Agent):
    """Check document against regulatory requirements."""
    def __init__(self):
        super().__init__(model="gemini-2.5-pro")
        self.add_tool(RegulatoryDatabaseTool())
        self.add_tool(PolicyMatchingTool())

class RiskAssessmentAgent(Agent):
    """Identify financial and operational risks in documents."""
    def __init__(self):
        super().__init__(model="gemini-2.5-pro")
        self.add_tool(FinancialMetricsTool())
        self.add_tool(MarketDataTool())

class ReportGenerationAgent(Agent):
    """Create formatted compliance report."""
    def __init__(self):
        super().__init__(model="gemini-2.5-flash")
        self.add_tool(ReportTemplateTool())
        self.add_tool(ChartGenerationTool())

# Tier 2: Orchestrator (composes specialists)

class ComplianceReviewOrchestrator(Agent):
    """Main orchestrator that coordinates the full review process."""

    def __init__(self):
        super().__init__(model="gemini-2.5-pro")

        # Initialize specialists
        self.ingestion = DocumentIngestAgent()
        self.compliance = ComplianceCheckAgent()
        self.risk = RiskAssessmentAgent()
        self.reporting = ReportGenerationAgent()

        # Register as tools
        self.add_tool(Tool(
            name="ingest_document",
            func=self.ingestion.execute,
            description="Extract text from financial document"
        ))
        self.add_tool(Tool(
            name="check_compliance",
            func=self.compliance.execute,
            description="Verify against regulatory requirements"
        ))
        self.add_tool(Tool(
            name="assess_risk",
            func=self.risk.execute,
            description="Identify financial and operational risks"
        ))
        self.add_tool(Tool(
            name="generate_report",
            func=self.reporting.execute,
            description="Create compliance report"
        ))

    def execute(self, document_path: str) -> str:
        """Full compliance review workflow."""
        return self.run(f"""
        Perform comprehensive compliance review:
        Document: {document_path}

        Steps:
        1. Use ingest_document to extract content
        2. Use check_compliance to identify issues
        3. Use assess_risk to evaluate financial impact
        4. Use generate_report to create final report

        Format findings clearly with recommendations.
        """)

# Tier 3: API layer

from flask import Flask

app = Flask(__name__)
orchestrator = ComplianceReviewOrchestrator()

@app.route("/api/review", methods=["POST"])
def review_document():
    document_path = request.json.get("document_path")
    report = orchestrator.execute(document_path)
    return {"report": report}

# Deploy to Vertex AI Agent Engine
# gcloud adk deploy --name compliance-orchestrator ...

Deployment Architecture:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌─────────────────────────────────────────┐
│ Cloud Run / Vertex AI Agent Engine       │
│                                         │
│  ┌───────────────────────────────────┐ │
│  │ ComplianceReviewOrchestrator       │ │
│  │                                   │ │
│  │  ├─ ingest_document ──────────┐   │ │
│  │  ├─ check_compliance ─────────┼─┐ │ │
│  │  ├─ assess_risk ──────────────┼─┼─┤ │
│  │  └─ generate_report ──────────┼─┼─┤ │
│  │                           │   │ │ │ │
│  └──────────────────────────────┼─┼─┼─┘ │
│                             │   │ │ │   │
│  ┌──────────────────────────┴───┼─┼─┘   │
│  │ Vertex AI Memory Bank    │ │       │
│  │ (persistent sessions)    │ │       │
│  └──────────────────────────┴─┘       │
└─────────────────────────────────────────┘
        ↓
    Gemini 2.5 API

Scaling Characteristics:

  • Each specialist agent can be deployed separately
  • Orchestrator routes requests to specialists via tool calls
  • Vertex AI Auto-scaling handles 1000s+ concurrent reviews
  • Memory Bank persists session state (enables resumable reviews)

ADK vs Alternatives

Comparison: ADK vs LangChain vs LlamaIndex vs Anthropic Agent SDK

Feature ADK LangChain LlamaIndex Anthropic SDK
Language Python Python, JS Python Python
Primary Use Multi-agent orchestration LLM chains + memory RAG + document indexing Claude API integration
Hierarchical Agents Yes (agents as tools) Partial (tools only) No Partial (tools only)
Model Support Multi-model (via MCP) 50+ LLM integrations 20+ LLM integrations Claude only
Memory/Sessions Built-in, Vertex AI native Multiple backends Basic Optional
Deployment Cloud Run, Vertex AI DIY, any Python runtime DIY, any Python runtime API-only
Testing Framework Integrated Manual Manual Manual
Learning Curve Low (opinionated) Steep (modular = complex) Steep (RAG-focused) Very low (claude-specific)
Community Size Growing Largest Large Growing (Anthropic-backed)
Best For Enterprise multi-agent Rapid prototyping Document-heavy workflows Claude-exclusive projects
Hosting Support Vertex AI native Any runtime Any runtime Any runtime

Verdict:

  • Choose ADK if: Building production multi-agent systems on Google Cloud, need hierarchical orchestration, want managed hosting
  • Choose LangChain if: Building rapid prototypes, need flexibility, don’t mind managing infrastructure
  • Choose LlamaIndex if: Building RAG systems, need document indexing, document-heavy workflows
  • Choose Anthropic SDK if: Standardized on Claude, want minimal abstraction

Performance Characteristics

Token Usage per Operation

Operation Tokens Cost (Flash)
Simple agent execution 500–2K $0.00015–0.0006
Multi-turn conversation 5–20K $0.0015–0.006
Complex orchestration (3+ agents) 20–100K $0.006–0.03
Full document analysis workflow 50–200K $0.015–0.06

Example: Daily compliance reviews

1
100 documents/day × 50K avg tokens × $0.30/M (Flash) = $1.50/day = $45/month

Latency

Operation Latency
Single agent execution 1–3s
Multi-agent orchestration 3–10s
With web search 5–15s
Vertex AI Agent Engine (managed) <500ms p50, <2s p95

Testing Agents

ADK includes testing utilities:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from google.adk.testing import AgentTest

class TestResearchAgent(AgentTest):
    def setUp(self):
        self.agent = ResearchAgent()

    def test_research_accuracy(self):
        """Test that agent returns factually correct information."""
        result = self.agent.execute("Who won the 2024 Nobel Prize in Physics?")
        self.assertIn("Aspect", result)  # Known winner

    def test_error_handling(self):
        """Test graceful error handling."""
        result = self.agent.execute("Query with invalid syntax: @#$%")
        self.assertNotIn("Error:", result)  # Should recover gracefully

    def test_tool_usage(self):
        """Test that agent uses tools correctly."""
        calls = self.agent.trace_tool_calls()
        self.assertIn("GoogleSearchTool", [t.name for t in calls])

# Run tests
pytest test_agents.py

Summary for Engineering Leaders

ADK is Google’s answer to the multi-agent problem — how do you build complex systems where multiple specialized agents coordinate?

Key Advantages:

  1. Composability: Agents as tools enables clean, testable hierarchies
  2. Production Ready: Vertex AI integration gives you enterprise-grade hosting from day one
  3. Cost Efficient: Multi-agent approach (specialists + orchestrator) reduces token waste vs single large agent
  4. Scalable: Auto-scaling from local dev to 1000s of concurrent agents
  5. Model Agnostic: Works with Gemini, Claude, GPT-4, or local open-source via MCP

When to Adopt:

  • Building enterprise workflows requiring multiple specialized agents
  • Need persistent session/memory across conversations
  • Already using Google Cloud infrastructure
  • Want production-grade agent hosting without DIY infrastructure
  • Need deterministic workflows (Workflow Agents)

When to Skip:

  • Simple single-agent chatbots (use Gemini API directly)
  • Heavily invested in AWS/Azure (LangChain is more portable)
  • Document-heavy RAG workflows (LlamaIndex is better)
  • Exclusively Claude-based (Anthropic SDK is simpler)

References

Official Documentation:

Related Resources:

Community:

This post is licensed under CC BY 4.0 by the author.