What This Agent Does
The Researcher has one job: take a topic, search the web, return a structured pile of findings. No formatting. No opinion. No final report. That is the Writer's job in the next step.
Keeping each specialist single-purpose is the whole point of multi-agent systems. The narrower the role, the more reliable the agent.
Write the Agent
Open researcher/agent.py:
# researcher/agent.py
# ==========================================
# Web research specialist — google_search + Gemini
# Exposed over A2A on port 8001
# ==========================================
from google.adk import Agent
from google.adk.tools import google_search
from google.adk.a2a.utils.agent_to_a2a import to_a2a
INSTRUCTION = """You are a research specialist.
Given a topic, run focused web searches and return raw findings. For each
finding include:
- A one-sentence claim
- The source URL
- A short verbatim quote when relevant
Return between 5 and 10 findings. Do NOT write a final report or executive
summary — that is downstream. Be neutral, exhaustive on the topic, and
prefer recent, high-quality sources.
"""
root_agent = Agent(
model="gemini-flash-latest",
name="researcher",
description="Searches the web and returns raw research findings on a topic.",
instruction=INSTRUCTION,
tools=[google_search],
)
# Wrap the agent for A2A. The helper generates the Agent Card, sets up
# the HTTP server scaffolding, and exposes the agent at the well-known path.
a2a_app = to_a2a(root_agent, port=8001)A few things to notice:
google_searchis a built-in ADK tool. No extra API key, no setup. Gemini handles the queries and the result fusion behind the scenes.- The instruction is strict about scope. The agent does not write final reports. That separation is what makes the team composable.
to_a2a()is the entire A2A integration. The helper:- Generates a JSON Agent Card from the agent's
name,description, andinstruction - Mounts it at
/.well-known/agent-card.json - Wires the A2A message endpoints (JSON-RPC and gRPC bindings)
- Returns an ASGI app you can hand to uvicorn
- Generates a JSON Agent Card from the agent's
Run It Locally
uv run uvicorn researcher.agent:a2a_app --host localhost --port 8001You should see something like:
INFO: Started server process [12345]
INFO: Uvicorn running on http://localhost:8001 (Press CTRL+C to quit)Inspect the Agent Card
In a second terminal:
curl http://localhost:8001/.well-known/agent-card.json | jqYou should see something close to:
{
"name": "researcher",
"description": "Searches the web and returns raw research findings on a topic.",
"version": "1.0.0",
"url": "http://localhost:8001",
"skills": [...],
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"]
}That JSON document is the entire contract. Any A2A client — from any framework, in any language — can read it and start calling your agent.
Send a Test Message
A2A speaks JSON-RPC over HTTP. You can hit it directly with curl to confirm:
curl -X POST http://localhost:8001 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "Research the state of AI agent observability in 2026."}],
"messageId": "msg-1"
}
}
}'After a few seconds you should get back a JSON response with the researcher's findings inline. If the search returns nothing useful, the agent will say so explicitly — it will not fabricate.
Leave the researcher running. We will wire the writer next on a different port.
Key Takeaways
to_a2a()is a single function call — that is the whole A2A server setup.- Built-in
google_searchmeans you do not need a separate search API key. - The Agent Card at
/.well-known/agent-card.jsonis the discovery layer for the entire protocol. - A narrow instruction (only return raw findings, no writeup) is what makes specialists composable.
Reference: ADK A2A Quickstart: Exposing · Agent Card spec · ADK built-in tools