Back to skills
SKILL.md
Adk Python
ASecurityGoogle Agent Development Kit (ADK) for Python — verified API patterns for building production-grade multi-agent systems. Covers Workflow graphs (ADK 2.0 Beta), LlmAgent, SequentialAgent, LoopAgent, CustomAgent (BaseAgent), MCP integration via McpToolset, FunctionTool, ToolContext state, session management, context compaction, callbacks (before/after agent/model/tool), human input via RequestInput, and the App wrapper. Use when: ADK agent, workflow graph, multi-agent, MCP toolset, HITL, contex...
- 27 stars
- 0 votes
- 0 copies
- 8 views
- Added September 12, 2026
Works with
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
npx -y skills add Fandry96/k3-agentic-skills --skill adk-python --agent claude-codeAre you the author of Adk Python?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/fandry96-adk-python)---
name: adk-python
description: "Google Agent Development Kit (ADK) for Python — verified API patterns for building production-grade multi-agent systems. Covers Workflow graphs (ADK 2.0 Beta), LlmAgent, SequentialAgent, LoopAgent, CustomAgent (BaseAgent), MCP integration via McpToolset, FunctionTool, ToolContext state, session management, context compaction, callbacks (before/after agent/model/tool), human input via RequestInput, and the App wrapper. Use when: ADK agent, workflow graph, multi-agent, MCP toolset, HITL, context compaction, session state, agent pipeline."
risk: low
source: "adk.dev official docs (verified May 2026)"
date_added: "2026-05-11"
---
# Google ADK Python — Verified API Skill
> **Source of truth:** `https://adk.dev/` (llms.txt index)
> **ADK 2.0 Beta docs:** `https://adk.dev/workflows/graph-routes/index.md`
> **Install:** `pip install "google-adk[extensions]" --pre` (for 2.0 Beta features)
## Core Imports (Verified)
```python
# Agents
from google.adk.agents import LlmAgent # Primary LLM-powered agent
from google.adk.agents import BaseAgent # For custom agents
# Alias: Agent = LlmAgent (from google.adk.agents.llm_agent import Agent)
# Workflow Agents (ADK 1.x — stable)
from google.adk.agents import SequentialAgent # Runs sub-agents in order
from google.adk.agents import LoopAgent # Repeats sub-agents until exit
from google.adk.agents import ParallelAgent # Runs sub-agents concurrently
# Graph Workflows (ADK 2.0 Beta)
from google.adk import Workflow # Graph-based workflow
from google.adk import Event # Node output events
from google.adk.events import RequestInput # Human-in-the-loop node
from google.adk.workflow import JoinNode # Fan-out/fan-in join
# Tools
from google.adk.tools.function_tool import FunctionTool
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
# Sessions & State
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
# Context Compaction
from google.adk.apps.app import App, EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
```
## Agent Types
### LlmAgent (Primary)
```python
root_agent = LlmAgent(
model='gemini-flash-latest',
name='my_agent',
instruction='Help the user with their task.',
tools=[my_function_tool, my_mcp_toolset],
# Optional:
# output_key='result', # Store output in state["result"]
# sub_agents=[child_a], # For delegation
)
```
### SequentialAgent (Stable)
Runs sub-agents one after another. No LLM needed.
```python
pipeline = SequentialAgent(
name="my_pipeline",
sub_agents=[agent_a, agent_b, agent_c]
)
```
### LoopAgent (Stable)
Repeats sub-agents until max iterations or an agent signals exit.
```python
quality_loop = LoopAgent(
name="quality_gate",
sub_agents=[drafter_agent, critic_agent],
max_iterations=3 # CRITICAL: Always set this
)
```
## ADK 2.0 Beta: Graph-Based Workflows (`Workflow`)
> ⚠️ ADK 2.0 Beta. Do not use in production.
The `Workflow` class defines deterministic directed graphs using an `edges` array. **There is NO `WorkflowAgent`, `add_node()`, or `add_edge()` method.** The graph is fully declarative.
### Basic Sequential Graph
```python
from google.adk import Workflow
root_agent = Workflow(
name="sequential_workflow",
edges=[("START", task_A_node, task_B_node)],
)
```
### Conditional Routing
```python
from google.adk import Workflow, Event
def router(node_input: str):
"""Return an Event with a route value to branch."""
if "urgent" in node_input:
return Event(route="URGENT_PATH")
return Event(route="NORMAL_PATH")
root_agent = Workflow(
name="routing_workflow",
edges=[
("START", task_A, router),
(router, {
"URGENT_PATH": urgent_handler,
"NORMAL_PATH": normal_handler,
}),
],
)
```
### Human-in-the-Loop (HITL)
```python
from google.adk.events import RequestInput
from google.adk import Workflow
def ask_user():
"""Pause execution and request human input."""
yield RequestInput(message="Select branch (1, 2, or 3):")
def process_input(node_input):
"""Process the human's response."""
return Event(output=f"User chose: {node_input}")
root_agent = Workflow(
name="hitl_workflow",
edges=[("START", ask_user, process_input)],
)
```
### RequestInput Options
```python
yield RequestInput(
message="Enter your choice:", # Text prompt
payload=some_data_dict, # Structured data context
response_schema=MyPydanticModel, # Expected response format
)
```
### Parallel Fan-Out + Join
```python
from google.adk.workflow import JoinNode
my_join = JoinNode(name="my_join")
root_agent = Workflow(
name="parallel_workflow",
edges=[
("START", task_A, my_join),
("START", task_B, my_join),
("START", task_C, my_join),
(my_join, final_task),
],
)
```
### Nested Workflows
```python
root_agent = Workflow(
name="parent_workflow",
edges=[
("START", task_A, router),
(router, {
"RUN_WORKFLOW_B": child_workflow_B,
"RUN_WORKFLOW_C": child_workflow_C,
}),
],
)
```
## Tools
### FunctionTool (Plain Python Function)
```python
# ADK auto-discovers tools from plain functions.
# Include in agent's tools list directly — no decorator needed.
def get_weather(city: str) -> dict:
"""Get weather for a city."""
return {"city": city, "temp": "72°F"}
agent = LlmAgent(
model='gemini-flash-latest',
name='weather_agent',
tools=[get_weather], # ADK wraps it automatically
)
```
### ToolContext (State Access Inside Tools)
```python
from google.adk.tools import ToolContext
def my_tool(query: str, tool_context: ToolContext) -> dict:
"""Tool with access to session state."""
# Read state
count = tool_context.state.get('call_count', 0)
# Write state (recorded in event state_delta)
tool_context.state['call_count'] = count + 1
return {"result": query, "calls": count + 1}
# NOTE: Do NOT include tool_context in the docstring.
# It is injected automatically by the ADK framework.
```
### McpToolset (Connect to MCP Servers)
```python
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
agent = LlmAgent(
model='gemini-flash-latest',
name='mcp_agent',
tools=[
McpToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command='node',
args=['path/to/mcp-server.js'],
),
),
# Optional: filter specific tools
# tool_filter=['tool_name_1', 'tool_name_2']
)
],
)
```
For remote MCP servers (HTTP/SSE):
```python
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://example.com/mcp",
headers={"Authorization": "Bearer ..."}
)
)
```
## Sessions & State
### State Prefixes (Scope)
| Prefix | Scope | Persisted Across |
|---|---|---|
| `state["key"]` | Session-scoped | Current session only |
| `state["app:key"]` | App-scoped | All sessions in app |
| `state["user:key"]` | User-scoped | All sessions for user |
| `state["temp:key"]` | Temporary | Current invocation only |
### Templating in Instructions
```python
agent = LlmAgent(
name="greeter",
instruction="Hello {user_name}, you have {task_count} tasks.",
# {user_name} and {task_count} are resolved from session state
)
```
### Runner (Execution)
```python
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
session_service = InMemorySessionService()
session = await session_service.create_session(
state={}, app_name='my_app', user_id='user1'
)
runner = Runner(
app_name='my_app',
agent=root_agent,
session_service=session_service,
)
events = runner.run_async(
session_id=session.id,
user_id=session.user_id,
new_message=content,
)
async for event in events:
print(event)
```
## Context Compaction (Anti-Amnesia)
Prevents context explosion during long sessions via sliding-window summarization.
```python
from google.adk.apps.app import App, EventsCompactionConfig
from google.adk.apps.llm_event_summarizer import LlmEventSummarizer
from google.adk.models import Gemini
app = App(
name='my-agent',
root_agent=root_agent,
events_compaction_config=EventsCompactionConfig(
compaction_interval=3, # Compress every 3 invocations
overlap_size=1, # Keep 1 event overlap for continuity
summarizer=LlmEventSummarizer(
llm=Gemini(model="gemini-flash-latest")
),
),
)
```
## Callbacks (Before/After Hooks)
Six callback types for observability and control:
| Callback | Signature | Blocking Behavior |
|---|---|---|
| `before_agent_callback` | `(callback_context) -> Optional[Content]` | Returning Content **bypasses entire agent run** |
| `after_agent_callback` | `(callback_context) -> Optional[Content]` | Appends additional response content |
| `before_model_callback` | `(callback_context) -> Optional[LlmRequest]` | Modify the prompt before LLM call |
| `after_model_callback` | `(callback_context) -> Optional[LlmResponse]` | Modify or replace LLM response |
| `before_tool_callback` | `(tool, args, tool_context) -> Optional[dict]` | Returning a dict **skips tool execution** and uses that dict as result |
| `after_tool_callback` | `(tool, args, tool_context, result) -> Optional[dict]` | Returning a dict **replaces** the original tool output |
Callbacks are set on the `LlmAgent`:
```python
def policy_guard(tool, args, tool_context):
"""Block tool if kill-list word detected."""
if "DROP TABLE" in str(args):
return {"error": "BLOCKED by policy"} # Skips tool
return None # Proceed normally
agent = LlmAgent(
model='gemini-flash-latest',
name='guarded_agent',
before_tool_callback=policy_guard,
after_tool_callback=my_after_tool_fn,
)
```
### Tool Confirmation Flow
For high-stakes tools, ADK supports manual approval:
```python
# When a tool requires confirmation, the runner emits
# a function call event for `adk_request_confirmation`.
# The client must respond with a FunctionResponse
# containing the user's approve/deny decision.
```
> ⚠️ **Server-side tools** (GoogleSearchTool, VertexAiSearchTool) do NOT trigger
> `before_tool_callback` or `after_tool_callback` — they execute inside the Gemini
> service. This is a critical blindspot for audit logging and security guardrails.
## Custom Agents (BaseAgent)
For arbitrary orchestration logic beyond Sequential/Loop/Parallel:
```python
from google.adk.agents import BaseAgent
class MyCustomAgent(BaseAgent):
my_sub_agent: LlmAgent # Declare sub-agents as attributes
async def _run_async_impl(self, ctx):
"""Override this to define custom execution logic."""
# Run sub-agents and yield their events
async for event in self.my_sub_agent.run_async(ctx):
yield event
```
Key rules:
- Must inherit from `BaseAgent`
- Must implement `_run_async_impl` as an async generator
- Pass sub-agents to `super().__init__(sub_agents=[...])` for framework discovery
## Sharp Edges (from Deep Research)
| Issue | Impact | Workaround |
|---|---|---|
| MCP stdio 5-second hardcoded timeout (v1.2.x) | Long-running tool calls fail | Custom session manager to extend timeout |
| `Workflow` inherits `BaseNode`, not `BaseAgent` | `after_agent_callback` **silently no-ops** on Workflow roots | Use node-level callbacks or custom wrapper |
| Server-side tools skip callbacks | GoogleSearchTool/VertexAiSearchTool bypass `before_tool_callback` | Implement audit at model callback level |
| JoinNode hangs if upstream fails | Workflow stuck indefinitely | Ensure every fan-out node has error fallback output |
| Session state Pickle→JSON migration (v1.22) | Old Pickle-format DBs incompatible | Re-create sessions or migrate schema |
| `--pre` flag doesn't override 1.x | `pip install google-adk --pre` fails if 1.x installed | Use `pip install google-adk --pre --force` |
| Workflow incompatible with live streaming | Graph workflows can't use real-time session modes | Use LlmAgent for live streaming use cases |
## PolicyEvaluator (Governance)
ADK integrates with governance engines via the `PolicyEvaluator` protocol. The `ADKPolicyEvaluator` is a YAML-configurable engine wired into `before_tool_callback`.
**Key principle: Monotonic Narrowing** — when a parent agent delegates to a sub-agent, the sub-agent's permissions (tools, max iterations) are always a **subset** of the parent's. A sub-agent can never escalate privileges.
```yaml
# Example k3_policy.yaml (wired via before_tool_callback)
policies:
- name: "kill_list"
scope: ["*"]
action: "reject"
condition: "output contains banned_word"
- name: "api_key_leak"
scope: ["*"]
action: "reject"
condition: "output matches AIzaSy.*"
```
## Migration: ADK 1.x → 2.0
- **Python 3.10+** required (1.x supported 3.9)
- **Install:** `pip install google-adk --pre --force`
- **`Workflow` replaces nested `SequentialAgent`/`LoopAgent`** — but they can coexist (1.x agents work as nodes in 2.0 graphs)
- **Session DB schema changed** from Pickle blobs to queryable JSON
- **`Optional` parameters removed** from builders for type safety
- **Security fix in v2.0.1** — upgrade is mandatory for enterprise
## CLI Commands
```bash
adk web # Launch debug web UI
adk web --no-reload # Windows fix for subprocess transport error
adk run <agent_dir> # Run agent from command line
adk api_server # Start API server for Cloud Run deployment
```
## Related Skills
Works with: `mcp-builder`, `gemini-api-dev`, `gemini-embedding-2`, `ai-agents-architect`
## Deep Research Source
Full 41-source technical reference: `forge-references/agentic/ADK-2.0-Technical-Reference-Guide.md`
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.