Skip to content

adwibha/exploring-adk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ADK Explorations: Comprehensive Hands-On Learning

MIT License Python 3.9+ Status: Complete ADK Ollama Local

Master the Agent Development Kit (ADK) through 10 structured, progressive modules. Learn to build agents, compose tools, orchestrate multi-agent systems, and implement advanced patterns using local Ollama inference.

Project Status: Complete. All 10 modules tested and documented. Estimated learning time: 2-3 hours per module. Total commitment: 20-30 hours for comprehensive mastery.


Agent Anatomy

Every ADK agent consists of three fundamental components:

%%{init: {theme: 'base', themeVariables: {primaryColor: '#2196F3', primaryBorderColor: '#1976D2', primaryTextColor: '#fff', fontSize: '16px'}}}%%
graph LR
    A["Model<br/>(LLM Engine)"] -->|Reasoning| B["Orchestration<br/>(ADK Framework)"]
    C["Tools<br/>(Functions)"] -->|Invokes| B
    B -->|Generates| D["Action/Response"]
    
    style A fill:#2196F3,stroke:#1565C0,color:#fff
    style B fill:#FF9800,stroke:#E65100,color:#fff
    style C fill:#9C27B0,stroke:#6A1B9A,color:#fff
    style D fill:#4CAF50,stroke:#2E7D32,color:#fff
Loading

Agent Types in ADK

Every agent in ADK is built on the BaseAgent foundation. ADK provides three distinct categories to build sophisticated applications, each serving different needs:

1. LLM Agents (LlmAgent, Agent)

LLM agents use Large Language Models as their core reasoning engine. They understand natural language, reason about problems, plan solutions, generate responses, and dynamically decide which tools to use. Ideal for flexible, language-centric tasks where the agent needs to make intelligent decisions.

Characteristics:

  • Non-deterministic (decisions vary based on input and reasoning)
  • Dynamic tool selection (LLM chooses when/which tool to call)
  • Best for: Q&A, content generation, intelligent assistants

Example:

root_agent = LlmAgent(
    model=LiteLlm(model="ollama_chat/qwen2.5:3b"),
    instruction="You are a helpful assistant. Use available tools intelligently.",
    tools=[search, calculate, summarize]
)

2. Workflow Agents (SequentialAgent, ParallelAgent, LoopAgent)

Workflow agents control the execution flow of other agents in predefined, deterministic patterns. They don't use an LLM for flow control—instead, they enforce structured orchestration without dynamic decision-making.

Workflow Patterns:

  • Sequential: Tool A → Tool B → Tool C (linear pipeline)
  • Parallel: Tool A, B, C run simultaneously (gather results)
  • Loop: Tool A → evaluate → retry if needed (iterative refinement)

Characteristics:

  • Deterministic (execution order is guaranteed)
  • Explicit control flow (you define the pattern)
  • Best for: Multi-step pipelines, data processing, orchestration

Example:

pipeline = SequentialAgent(
    name="DataPipeline",
    sub_agents=[
        fetch_agent,    # Step 1
        process_agent,  # Step 2
        save_agent      # Step 3
    ]
)

3. Custom Agents (Extending BaseAgent)

Custom agents allow you to implement unique operational logic, specific control flows, or specialized integrations not covered by standard agent types. Built by extending BaseAgent directly.

Characteristics:

  • Can be either deterministic or non-deterministic
  • Custom implementation of perception-thinking-action loop
  • Best for: Specialized integrations, domain-specific workflows, novel patterns

Example:

from google.adk.agents import BaseAgent

class DatabaseAgent(BaseAgent):
    def __init__(self, db_connection):
        self.db = db_connection
    
    def run(self, query: str):
        # Custom logic: parse query, validate, execute
        return self.db.execute(query)

Agent Type Comparison

Feature LLM Agent Workflow Agent Custom Agent
Primary Function Reasoning, Generation, Tool Use Controlling Agent Execution Flow Implementing Unique Logic/Integrations
Core Engine Large Language Model (LLM) Predefined Logic (Sequence, Parallel, Loop) Custom Code
Determinism Non-deterministic (Flexible) Deterministic (Predictable) Can be either, based on implementation
Primary Use Language tasks, Dynamic decisions Structured processes, Orchestration Tailored requirements, Specific workflows
Tool Selection LLM chooses dynamically Enforced by workflow structure Custom implementation
When to Use Questions, creative tasks, intelligent routing Guaranteed execution order, pipelines Novel patterns, domain-specific logic

BaseAgent Hierarchy

All agent types in ADK extend from BaseAgent, providing a unified interface:

BaseAgent (Foundation)
├── LlmAgent (Language-based reasoning)
│   ├── Sub-agents for multi-agent systems
│   └── Can delegate to other agents
├── SequentialAgent (Sequential orchestration)
├── ParallelAgent (Parallel orchestration)
├── LoopAgent (Iterative orchestration)
└── Custom Agents (Your implementation)

BaseAgent Hierarchy

Multi-Agent Systems

The true power of ADK comes from combining agent types. Complex applications frequently employ multi-agent architectures where:

  • LLM Agents handle intelligent, language-based task execution and decision-making
  • Workflow Agents manage the overall process flow using deterministic patterns
  • Custom Agents provide specialized capabilities or rules for unique integrations

This allows you to build sophisticated, hierarchical systems where specialized agents collaborate toward shared goals. See Module 09 for a detailed multi-agent example.


What is an Agent?

An agent is an autonomous system that perceives its environment, reasons about its state, and takes actions to achieve goals. In ADK, agents are composed of three fundamental components:

  • Model: The reasoning engine (Large Language Model)
  • Tools: Functions and capabilities the agent can invoke
  • Orchestration: The framework managing the perception-thinking-action loop

This curriculum teaches you to build, test, and deploy agents that effectively combine these components.

For foundational concepts, see ADK LLM Agents documentation.


Quick Start (5 Minutes)

System Requirements

  • Python 3.9 or higher (python3 --version)
  • Ollama running locally (download from ollama.ai)
  • Basic terminal command familiarity
  • Approximately 4GB available RAM for local LLM inference

Refer to ADK Python Getting Started for complete setup instructions.

Installation and Launch

# 1. Install dependencies
cd adk-project
.venv/bin/pip install litellm google-adk

# 2. Pull a fast, tool-capable model
ollama pull qwen2.5:3b

# 3. Start the exploration environment
cd explorations
export OLLAMA_API_BASE="http://localhost:11434"
.venv/bin/adk web

Open http://localhost:8000 in your browser. ADK auto-discovers all root_agent definitions across modules and displays them as interactive tabs.


Learning Curriculum

Module Concept Duration Reference
01 — Hello Agent Agent anatomy: model, name, description, instruction 15 min LLM Agents
02 — Single Tool Python function as agent capability 15 min Multi-Tool Agent
03 — Multi Tool Tool selection and sequencing 20 min Multi-Tool Agent
04 — Input Schema Pydantic-based input validation 15 min LLM Agents
05 — Output Schema Deterministic structured JSON responses 20 min LLM Agents
06 — Session State Application state management 20 min Sessions
07 — Callbacks Hooks for tool execution lifecycle 15 min Callbacks
08 — Workflow Agents Sequential, parallel, loop orchestration 25 min Workflow Agents
09 — Multi-Agent Systems Hierarchical agent composition 25 min LLM Agents
10 — Advanced Tools External system integration 20 min Custom Tools

Total Commitment: 3+ hours of hands-on exploration and experimentation.


Recommended Learning Path

Day 1: Foundations (1 hour)

Learn agent anatomy and how tools work.

  • 01 — Hello Agent → Understand agent parameters and configuration
  • 02 — Single Tool → Write your first tool function
  • 03 — Multi Tool → Watch agent select between multiple tools

Key Concept: A tool is simply a Python function with a docstring. The docstring tells the LLM what the tool does and when to use it.

Day 2: Structure (1 hour)

Learn to control inputs, outputs, and application state.

  • 04 — Input Schema → Validate user input with Pydantic
  • 05 — Output Schema → Force structured JSON responses
  • 06 — Session State → Track user state across conversation turns

Key Concept: Schemas enforce type safety. Input schemas validate before processing. Output schemas guarantee deterministic, parseable responses.

Day 3: Advanced (1+ hours)

Build complex, production-ready systems.

  • 07 — Callbacks → Debug agent reasoning with execution hooks
  • 08 — Workflow Agents → Orchestrate multi-step flows deterministically
  • 09 — Multi-Agent Systems → Delegate to specialized sub-agents
  • 10 — Advanced Tools → Integrate with external systems securely

Key Concept: Complex agents are built by composing simpler patterns. Workflows guarantee execution order. Multi-agent systems scale by specialization.


Module Highlights

01 — Hello Agent (Introductory)

Concept: An LLM agent is defined by four parameters: model, name, description, and instruction.

from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm

root_agent = LlmAgent(
    model=LiteLlm(model="ollama_chat/qwen2.5:3b"),
    name="hello_agent",
    description="A helpful pirate assistant",
    instruction="You are a pirate. Answer all questions like a pirate."
)

Why it Matters: Your instruction parameter shapes agent personality. The same model with different instructions produces different behavior.

Learn More: ADK LLM Agents


01 Example: Basic Agent Interaction

Hello Agent


02 — Single Tool (Introductory)

Concept: A Python function with a docstring becomes an agent tool. The docstring is critical—it's what the LLM reads to understand the tool's purpose.

def roll_die(sides: int) -> int:
    """Roll a die with N sides and return the result (1 to N)."""
    return random.randint(1, sides)

root_agent = LlmAgent(
    model=...,
    tools=[roll_die]
)

Why it Matters: Tool docstrings are the interface between your code and the LLM's reasoning. Clear, specific docstrings lead to correct tool usage.

Learn More: Multi-Tool Agent Tutorial

02 Example: Tool Execution in Action

Single Tool


03 — Multi Tool (Intermediate)

Concept: When an agent has multiple tools, it must reason about which tool to use and when. Tool chaining occurs when one tool's output becomes input to another.

# Agent has three tools available
tools=[add, multiply, is_prime]

# Instruction guides tool selection
instruction="""
When asked to calculate:
1. Perform the math operation (use add/multiply)
2. If the result seems interesting, check if it's prime
"""

Why it Matters: Multi-tool agents solve complex problems through reasoning and sequencing.

Try This: Ask "Multiply 3 by 4, then check if it's prime" and watch the agent call multiply first, then is_prime.

Learn More: Multi-Tool Agent Tutorial


04 — Input Schema (Intermediate)

Concept: Pydantic models validate structured input before the agent processes it.

from pydantic import BaseModel
from typing import Optional

class MealOrder(BaseModel):
    dish: str
    quantity: int
    spice_level: Optional[str] = None

root_agent = LlmAgent(
    model=...,
    input_schema=MealOrder
)

Why it Matters: Type safety. Your agent code receives validated data, not raw strings.


05 — Output Schema (Critical)

Concept: Force agent responses to be valid JSON matching a schema. Responses are always deterministic and parseable.

from pydantic import BaseModel

class ProductInfo(BaseModel):
    name: str
    price: float
    quantity: int
    in_stock: bool

root_agent = LlmAgent(
    model=...,
    output_schema=ProductInfo
)

Why it Matters: Parse responses as Python objects without string matching. No guessing about response format.

result = agent.run("iPhone 15 Pro for $999, 5 in stock")
print(result.price)  # 999.0 (typed float, not string)
print(result.in_stock)  # True (typed bool)

Learn More: LLM Agents Documentation


06 — Session State (Intermediate)

Concept: Your code controls a Python dictionary separate from the LLM's conversation history. Use session state for business logic decisions.

session_state = {
    "user_name": None,
    "total_requests": 0,
    "subscription_tier": "free"
}

# Your code extracts facts and updates state
import re
def process_message(message: str):
    session_state["total_requests"] += 1
    
    match = re.search(r"my name is\s+([a-zA-Z\s]+?)(?:\.|,|$)", message, re.IGNORECASE)
    if match:
        session_state["user_name"] = match.group(1).strip()
    
    # Business logic: upgrade tier after 5 requests
    if session_state["total_requests"] > 5:
        session_state["subscription_tier"] = "premium"

Why it Matters: Session state lets you make programmatic decisions based on accumulated facts, separate from the agent's own conversation memory.

Learn More: ADK Sessions


07 — Callbacks (Advanced)

Concept: Hooks that execute before/after tool calls, for logging, validation, or modification.

def log_tool_call(tool_name, args):
    """Log before each tool call."""
    print(f"Calling {tool_name} with args: {args}")

def validate_tool_call(tool_name, args):
    """Reject certain tools."""
    if tool_name == "delete_file":
        return False  # Agent cannot use this tool
    return True

root_agent = LlmAgent(
    model=...,
    callbacks={
        "before_tool_call": log_tool_call,
        "validate_tool_call": validate_tool_call
    }
)

Why it Matters: Gain visibility into agent reasoning. Intercept and modify tool behavior for security and monitoring.

Learn More: ADK Callbacks


08 — Workflow Agents (Advanced)

Concept: Guarantee execution order using specialized orchestration agents. Unlike multi-tool (agent chooses), workflows enforce deterministic sequencing.

Sequential Workflow: Execute tools one after another. Each step receives the output of the previous step.

from google.adk.agents import SequentialAgent, LlmAgent

step1 = LlmAgent(name="Fetch", instruction="Fetch data")
step2 = LlmAgent(name="Process", instruction="Process the fetched data")
step3 = LlmAgent(name="Save", instruction="Save results")

pipeline = SequentialAgent(
    name="DataPipeline",
    sub_agents=[step1, step2, step3]
)

Parallel Workflow: Execute multiple agents simultaneously, then combine results.

Loop Workflow: Execute an agent, evaluate, and retry if needed.

Why it Matters: Workflows are predictable. Multi-tool agents let the LLM choose order (sometimes unreliably). Workflows enforce control flow.

Learn More: ADK Workflow Agents

08 Example: Multi-Step Pipeline Execution

Workflow Agent


09 — Multi-Agent Systems (Advanced)

Concept: Hierarchical agent composition. A coordinator agent delegates requests to specialized sub-agents based on their descriptions and capabilities.

# Define specialist agents
math_agent = LlmAgent(
    name="math_agent",
    description="Solves math problems and calculations",
    instruction="You are a math expert. Solve step by step."
)

story_agent = LlmAgent(
    name="story_agent",
    description="Writes creative fiction and stories",
    instruction="You are a creative writer."
)

# Create coordinator
coordinator = LlmAgent(
    name="coordinator",
    description="Routes user requests to the best specialist",
    instruction="""
You are a coordinator. When a user asks a question:
1. Identify which specialist is best suited
2. Transfer the request using transfer_to_agent(agent_name='specialist_name')
3. Let the specialist handle and return the answer
    """,
    sub_agents=[math_agent, story_agent]
)

Agent Hierarchy:

  • The coordinator is the parent agent
  • math_agent and story_agent are sub-agents (children)
  • ADK automatically sets parent_agent on each sub-agent
  • An agent can only have one parent (single parent rule)

Why it Matters:

  • Modularity: Each agent specializes in a domain
  • Scalability: Add more specialists without coordinator complexity
  • Maintainability: Sub-agents can be tested independently
  • Efficiency: Reduces token consumption (smaller specialized models)

Delegation Mechanism: The coordinator uses transfer_to_agent() to invoke specialists. ADK's AutoFlow framework handles the delegation automatically.

Use Cases:

  • Customer support: Route to billing_agent, technical_support_agent, sales_agent
  • Content creation: Route to blog_writer_agent, social_media_agent, email_agent
  • Research: Route to literature_search_agent, data_analysis_agent, synthesis_agent

Module 09 Architecture Diagram

%%{init: {theme: 'base', themeVariables: {primaryColor: '#FF9800', primaryBorderColor: '#E65100', primaryTextColor: '#fff', fontSize: '16px'}}}%%
graph TD
    User["User Query"] --> Coordinator["Coordinator Agent<br/>(Router)"]
    
    Coordinator -->|transfer_to_agent| Math["Math Agent<br/>(Specialist)"]
    Coordinator -->|transfer_to_agent| Story["Story Agent<br/>(Specialist)"]
    Coordinator -->|transfer_to_agent| Trivia["Trivia Agent<br/>(Specialist)"]
    
    Math --> Result1["Calculation<br/>Result"]
    Story --> Result2["Creative<br/>Response"]
    Trivia --> Result3["Knowledge<br/>Response"]
    
    Result1 --> Final["Final Answer"]
    Result2 --> Final
    Result3 --> Final
    
    style Coordinator fill:#FF9800,stroke:#E65100,color:#fff,stroke-width:3px
    style Math fill:#2196F3,stroke:#1565C0,color:#fff
    style Story fill:#9C27B0,stroke:#6A1B9A,color:#fff
    style Trivia fill:#4CAF50,stroke:#2E7D32,color:#fff
    style Final fill:#FFC107,stroke:#FFA000,color:#000,stroke-width:2px
    style User fill:#757575,stroke:#424242,color:#fff
Loading

10 — Advanced Tools (Advanced)

Concept: Integration with external systems. Secure file I/O, code execution, and system integration.

from pathlib import Path

SAFE_DIR = Path.cwd()

def _validate_path(file_path: str) -> Path:
    """Prevent directory traversal attacks."""
    path = (SAFE_DIR / file_path).resolve()
    if not str(path).startswith(str(SAFE_DIR.resolve())):
        raise ValueError(f"Path {file_path} outside allowed directory")
    return path

def read_file(file_path: str) -> str:
    """Read and return file contents safely."""
    try:
        path = _validate_path(file_path)
        with open(path, 'r') as f:
            return f.read()
    except ValueError as e:
        return f"Access denied: {e}"

root_agent = LlmAgent(
    model=...,
    tools=[read_file, write_file, list_files]
)

Why it Matters:

  • Real system integration (files, databases, APIs)
  • Security: Always validate paths to prevent traversal attacks
  • Error handling: Return descriptive errors for agent visibility

Learn More: ADK Custom Tools


Environment Configuration

Model Selection

ADK supports multiple model providers. For local exploration with Ollama:

Fast Model (Recommended for Learning):

ollama pull qwen2.5:3b
# Export: OLLAMA_API_BASE="http://localhost:11434"
# Use: model=LiteLlm(model="ollama_chat/qwen2.5:3b")

Powerful Model (For Complex Tasks):

ollama pull gemma4:latest
# Use: model=LiteLlm(model="ollama_chat/gemma4:latest")

Learn more:

Environment Variable Setup

# Required for Ollama-based models
export OLLAMA_API_BASE="http://localhost:11434"

# Make permanent (add to ~/.zshrc or ~/.bashrc)
echo 'export OLLAMA_API_BASE="http://localhost:11434"' >> ~/.zshrc
source ~/.zshrc

# Verify it's set
echo $OLLAMA_API_BASE

Detailed Setup Instructions

1. Verify Prerequisites

python3 --version           # Must be 3.9 or higher
ollama --version            # Ollama installed
ollama ps                   # Ollama daemon running
curl http://localhost:11434/api/tags  # API is responding

2. Install Python Dependencies

cd adk-project
source .venv/bin/activate   # Activate virtual environment
.venv/bin/pip install --upgrade pip setuptools wheel
.venv/bin/pip install google-adk litellm

3. Select and Pull Models

# Pull fast model
ollama pull qwen2.5:3b

# Pull powerful model (optional)
ollama pull gemma4:latest

# Verify models are installed
ollama list

4. Configure Environment

export OLLAMA_API_BASE="http://localhost:11434"

# Persist across sessions
echo 'export OLLAMA_API_BASE="http://localhost:11434"' >> ~/.zshrc

5. Start ADK Web Interface

cd explorations
.venv/bin/adk web

Navigate to http://localhost:8000. All 10 modules appear as interactive tabs.


Troubleshooting

"Connection refused: localhost:11434"

Ollama daemon is not running.

ollama serve
# Verify: curl http://localhost:11434/api/tags

"Model not found: ollama_chat/qwen2.5:3b"

Model has not been pulled.

ollama pull qwen2.5:3b
ollama list  # Verify installation

Slow Agent Responses

You're using a high-capability model (gemma4, ~10 seconds). Switch to qwen2.5:3b (~2 seconds) in agent.py:

model=LiteLlm(model="ollama_chat/qwen2.5:3b")

Agent Not Using Tools

Tool docstring is missing or vague. Make it specific:

def calculate_tax(amount: float, rate: float) -> float:
    """Calculate tax on an amount. Use when asked for tax calculation."""
    return amount * rate

"ModuleNotFoundError: No module named 'google.adk'"

ADK not installed or virtual environment not activated.

source .venv/bin/activate
.venv/bin/pip install google-adk litellm

OLLAMA_API_BASE not set

Export the environment variable:

export OLLAMA_API_BASE="http://localhost:11434"
echo $OLLAMA_API_BASE  # Verify

After Exploration: Next Steps

Pattern Combinations

  • Multi-Agent + Output Schema: Specialists return deterministic JSON
  • Session State + Callbacks: Comprehensive user journey tracking
  • Workflow + Advanced Tools: Complex multi-step file processing pipelines

Building Production Applications

  1. Combine learned patterns for real use cases
  2. Deploy as REST API: adk api_server
  3. Implement error handling and monitoring
  4. Add long-term memory with vector embeddings

Advanced Topics

  • Custom agents inheriting from BaseAgent
  • MCP server integration
  • Vector databases for retrieval-augmented generation
  • Multi-language support (Java, Go, TypeScript)

Module Architecture

Each module is completely independent:

explorations/
├── 01_hello_agent/
│   ├── agent.py       # Agent configuration: model, name, description, instruction
│   └── README.md      # Module-specific concept guide
├── 02_single_tool/
│   ├── agent.py       # Single tool: function with docstring
│   └── README.md
├── 03_multi_tool/
│   ├── agent.py       # Multiple tools: agent reasoning and selection
│   └── README.md
├── 04_input_schema/
│   ├── agent.py       # Input validation with Pydantic
│   └── README.md
├── 05_output_schema/
│   ├── agent.py       # Structured JSON output enforcement
│   └── README.md
├── 06_session_state/
│   ├── agent.py       # Application state management
│   └── README.md
├── 07_callbacks/
│   ├── agent.py       # Tool execution hooks and monitoring
│   └── README.md
├── 08_workflow_agents/
│   ├── agent.py       # Deterministic execution orchestration
│   └── README.md
├── 09_multi_agent/
│   ├── agent.py       # Hierarchical agent delegation
│   └── README.md
├── 10_advanced_tools/
│   ├── agent.py       # External system integration and security
│   └── README.md
└── __init__.py        # Package initialization

ADK's auto-discovery loads all root_agent definitions at startup. Each module appears as an interactive tab in the web interface. Modify and test modules independently.


Learning Best Practices

  1. Read the Module README First

    • Explains concepts before code
    • Identifies common mistakes
    • Provides experimentation suggestions
  2. Modify and Experiment

    • Change instruction parameters
    • Add or remove tools
    • Test edge cases
  3. Restart Web Interface

    • ADK loads agents at startup
    • Changes require restart: adk web
  4. Choose Appropriate Models

    • qwen2.5:3b: Fast iteration (2 seconds)
    • gemma4:latest: Complex reasoning (10+ seconds, more capable)
  5. Test Independently

    • Each module tab operates independently
    • Cross-module dependencies are minimal

Official Documentation

Getting Started:

Agents & Core Concepts:

Tools & Integration:

Advanced Features:

Model Configuration:


Project Metadata

  • Framework: Google Agent Development Kit (ADK)
  • Language: Python 3.9+
  • Local LLM: Ollama
  • Model Provider: LiteLLM (supports 100+ LLM providers)
  • Estimated Learning Time: 20-30 hours total
  • Status: Complete and tested

About

Comprehensive hands-on learning curriculum for Google's Agent Development Kit (ADK). Master AI agents through 10 progressive modules: agent configuration, tool orchestration, multi-agent systems, and advanced patterns. Complete working examples with Ollama local inference.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages