Skip to content
Blog

Building a Multi-Agent System with Google ADK

Move from single-prompt chatbots to a team of collaborating agents. Use Google ADK hierarchy, workflow agents, and session state to orchestrate a research-and-write pipeline.

Published on August 8, 2026

AI Assistant

One complex prompt asks one model to do everything at once. A multi-agent system divides the job between several specialized agents, each doing what it is good at while sharing state through a pipeline. Google’s Agent Development Kit (ADK) makes this composition explicit — and dramatically easier to debug — than a single mega-prompt.

The problem multi-agent design solves

Single-prompt agents fail at compound tasks. Ask one agent to “research a topic, write a pitch, sanity-check it, and save it” and it will do a one-pass job: no verification, no revision, and no clean hand-off between stages. The same task split across a researcher, a writer, and a critic produces verifiably better output because each agent has a narrow job and a validation step in the loop.

ADK building blocks

ADK (Python 3.10+) organizes agents into a tree:

  • Agent (LlmAgent) — the reasoning primitive: a system prompt, tools, a model. It decides what to call and what to return.
  • SequentialAgent — runs sub-agents one after another, each writing to the shared state.
  • LoopAgent — repeats a sequence (with max_iterations) until a condition or an exit_loop tool call stops it.
  • ParallelAgent — runs independent sub-agents concurrently, each writing to a unique output_key.

All agents share a Session with a session.state dictionary — the “whiteboard” that carries results between agents via output_key and key templating like {outline?}.

Prerequisites

  • Python 3.10+, pip install google-adk
  • A Gemini API key (GOOGLE_API_KEY) from Google AI Studio — no billing account needed
  • A directory structure ADK expects: each agent project has an __init__.py exposing a root_agent

Build a research → write → critique team

Put this in team_agent/agent.py:

from google.adk.agents import Agent, LoopAgent, SequentialAgent

MODEL = "gemini-2.5-flash"

researcher = Agent(
    name="researcher",
    model=MODEL,
    description="Gathers verified facts about a topic.",
    instruction=(
        "Research the topic from the user. "
        "Return a compact list of verifiable facts and save them "
        "to state key 'facts'."
    ),
    output_key="facts",
)

writer = Agent(
    name="writer",
    model=MODEL,
    description="Writes a short technical post from the facts.",
    instruction=(
        "Write a 300-word technical post using {facts}. "
        "Save the draft to 'draft'."
    ),
    output_key="draft",
)

critic = Agent(
    name="critic",
    model=MODEL,
    description="Reviews the draft and decides if it is ready.",
    instruction=(
        "Review {draft}. If it is accurate, well-structured, and "
        "concise, reply exactly 'ok'. Otherwise reply 'revise' "
        "plus one concrete improvement required."
    ),
)

writer_room = LoopAgent(
    name="writer_room",
    description="Loop writer + critic until the critic says ok.",
    sub_agents=[writer, critic],
    max_iterations=3,
)

pipeline = SequentialAgent(
    name="pipeline",
    sub_agents=[researcher, writer_room],
)

root_agent = Agent(
    name="team",
    model=MODEL,
    description="Coordinator that delegates to the pipeline.",
    sub_agents=[pipeline],
)

Key mechanics:

  • output_key="facts" automatically stores the agent’s response into state["facts"] so the writer can reference {facts}.
  • The critic gating the loop means bad drafts loop internally up to 3 times before the pipeline proceeds — a self-correcting writer’s room.
  • The root agent delegates; it doesn’t do the reasoning itself.

Run and inspect

From the package root (the directory containing team_agent/):

adk web        # open http://127.0.0.1:8000, pick the agent
# or
adk run team_agent

adk web shows real-time traces: which agent is active, what each sub-agent wrote to state, and which tools fired. This is why ADK beats a single prompt for debugging — step-by-step visibility instead of a black box.

Fan out with ParallelAgent

Independent research jobs run concurrently with a ParallelAgent, each writing a unique key:

box_office = Agent(name="box_office", ... output_key="box_office_report")
casting = Agent(name="casting", ... output_key="casting_report")

preproduction = ParallelAgent(
    name="preproduction",
    sub_agents=[box_office, casting],
)

Unique output_keys avoid the race condition where the last-finishing agent overwrites everyone else’s result.

Conclusion & Next Steps

You turned a monolithic prompt into a team with an explicit hierarchy, shared state, and an iterative quality gate. Next: add a real tool (a requests-based fetch) to the researcher, wire session state from a previous turn into the loop, and deploy the same agent to Vertex AI Agent Engine with a single CLI command when you need managed scaling.

References / Sources