What This Agent Does

The Writer takes a structured pile of findings and produces a short, opinionated brief. It has no tools — no web access, no calculator, nothing. Its only input is the text the Orchestrator hands it.

Splitting research and writing into two agents has practical benefits:

  • The Writer can be a smaller, cheaper model if you want — it has no search to do
  • The Writer's instruction is shorter and more focused — clearer output
  • You can swap the Writer later (a different team, a different style) without touching the Researcher
  • Failures are easier to debug — bad findings vs bad prose are now two separate problems

Write the Agent

Open writer/agent.py:

# writer/agent.py
# ==========================================
# Brief writer — no tools, just composition
# Exposed over A2A on port 8002
# ==========================================
 
from google.adk import Agent
from google.adk.a2a.utils.agent_to_a2a import to_a2a
 
INSTRUCTION = """You are an executive brief writer.
 
You receive raw research findings as input. Each finding has a claim,
a source URL, and sometimes a quote.
 
Produce a brief in this exact structure:
 
# {Topic}
 
## Bottom Line
A two-sentence verdict. What is the current state of the topic?
 
## Key Findings
Three to five bullet points. Each bullet is one short sentence followed by
a source citation in markdown link form.
 
## What to Watch
One short paragraph on what is likely to change in the next 6 months,
grounded in the findings (no speculation beyond them).
 
Rules:
- Cite every claim. Use markdown links: [source](url).
- Do not invent information beyond what the findings provide.
- Keep the whole brief under 300 words.
- Plain prose. No marketing language. No hedging adverbs.
"""
 
root_agent = Agent(
    model="gemini-flash-latest",
    name="writer",
    description="Turns raw research findings into a concise, cited executive brief.",
    instruction=INSTRUCTION,
)
 
a2a_app = to_a2a(root_agent, port=8002)

Notice what is missing: no tools= argument. This agent does not need any. Its work is pure transformation — text in, text out.

Run It Locally

Open a third terminal (leave the Researcher running in the second):

uv run uvicorn writer.agent:a2a_app --host localhost --port 8002

You should see Uvicorn running on http://localhost:8002.

Verify the Agent Card

curl http://localhost:8002/.well-known/agent-card.json | jq .name
# "writer"

Two agents, two cards, two ports.

Test the Writer in Isolation

You can drive the Writer directly with some fake research findings to confirm it does its job:

curl -X POST http://localhost:8002 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "message/send",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"kind": "text", "text": "Topic: AI agent observability in 2026.\n\nFindings:\n1. OpenTelemetry added a GenAI semantic convention in early 2026 — source: https://opentelemetry.io/docs/specs/semconv/gen-ai/\n2. Langfuse and Helicone both report 3-4x growth in agent traces - source: https://langfuse.com/blog/2026-recap\n3. A2A traces are now first-class citizens with their own span attributes - source: https://a2a-protocol.org/latest/observability/"}],
        "messageId": "msg-1"
      }
    }
  }'

You should get back a 200-300 word brief with that exact three-section structure. If the structure drifts, sharpen the instruction — the Writer's instruction is the single point of control for output format.

The Pattern

You now have a pattern you will reuse:

  1. Define a focused Agent with one clear job.
  2. Pass it to to_a2a() with a unique port.
  3. Run it under uvicorn.
  4. The Agent Card at /.well-known/agent-card.json becomes the public contract.

Add a new specialist — say, a fact-checker — and you repeat that pattern on port 8003. The Orchestrator (next step) does not care how many specialists you have.

Key Takeaways

  • Specialists are smaller and sharper. The Writer has zero tools and a much shorter instruction than the Researcher.
  • The A2A wrapper is identical regardless of what the agent does — to_a2a(root_agent, port=N) and you are done.
  • Testing each agent in isolation with curl catches instruction bugs early, before the orchestrator's behavior makes them hard to diagnose.

Reference: ADK Agent class · A2A message/send spec