GGoldwater.dev
All labs
ADK Series · Part 3 of 5Intermediate45–60 min·Updated June 2026

Multi-Agent Systems

Compose multiple ADK agents into a coordinated system with delegation and sub-agents — the building block for complex workflows.

Download starter repo

Where we are in the series

  1. Your first agent — a single agent with one tool. (done)
  2. Tools, state & memory — the agent remembers context. (done)
  3. Multi-agent systems (this lab) — a coordinator delegating to specialists, plus deterministic workflows.
  4. Evaluation, callbacks & safety — evalsets, guardrails, tracing.
  5. Deploy & connect — ship it, and connect over A2A and MCP.

We keep the Acme domain. The single assistant now becomes a small support team.


What you'll build

You'll turn one agent into a multi-agent system, two ways:

  • A coordinator with specialists — a front-line LlmAgent that routes each request to an orders specialist or a returns specialist. The model decides who handles what, based on each specialist's description. The customer talks to one agent; the right expert answers.
  • A deterministic pipeline — an ADK `Workflow` that runs agents in a fixed order (triage → responder) using a graph of edges, for when the steps are known up front.

You'll run the coordinator and watch requests route to different specialists, and you'll see how ADK 2.0's graph-based Workflow expresses fixed control flow.


Why this matters (the 5-minute business case)

Read this section before handing the lab to your team.

Multi-agent design is how you scale an AI system past what a single agent can reliably do — organizationally and technically. As you pile tools, instructions, and edge cases onto one agent, it gets slower, more expensive, harder to reason about, and more error-prone (its instruction balloons; its context fills with things irrelevant to the task at hand). Splitting the work across focused specialists, coordinated by a router, is the same move that took software from monoliths to services. ADK makes both the dynamic (model-routed) and deterministic (graph-defined) versions first-class.

Three business reasons this matters:

  1. Specialists are better, cheaper, and clearer than one generalist. A focused agent with a tight instruction and a few relevant tools outperforms a sprawling do-everything agent — and it's easier to test and to reason about. Narrow scope means less prompt to get wrong and a smaller surface for mistakes. "What is this agent allowed to do?" has a short, reviewable answer per specialist.
  2. It maps to how organizations actually work. Different teams own different capabilities. With multi-agent systems, the orders team owns the orders specialist and the returns team owns the returns specialist; the coordinator just routes. Teams improve their own agent independently, on their own cadence — the same decoupling that lets microservices scale across an org. (This is the in-process cousin of the cross-org A2A pattern from the protocols series.)
  3. You can choose control vs. autonomy per problem. Some flows should be repeatable and auditable (a compliance review pipeline that must always run the same steps in the same order). Others should be adaptive (route to whoever fits this messy request). ADK lets you pick: a deterministic Workflow graph for the former, model-driven delegation for the latter — and mix them.

The honest caveats, because pragmatic adoption means naming them:

  • More agents, more moving parts. Multi-agent systems are distributed systems in miniature: routing can misfire, handoffs can drop context, and debugging spans multiple agents. Don't reach for it until a single agent is genuinely straining — premature decomposition adds cost and latency (every hop is more tokens and another model call) for no benefit.
  • Routing is a model decision, and model decisions can be wrong. A coordinator can send a request to the wrong specialist, especially when descriptions overlap or the request is ambiguous. Specialist descriptions are now load-bearing infrastructure — they deserve the same care as an API contract, and routing accuracy is something you should evaluate (Lab 4).
  • Deterministic isn't automatically better. A fixed Workflow is predictable but rigid; it can't adapt to an unexpected request. Use graphs where repeatability matters, model routing where flexibility does — and be honest about which a given flow needs.

A useful framing for a non-technical stakeholder: "Instead of one assistant trying to know everything, we're building a team: focused specialists plus a coordinator that routes each request to the right one — which is more accurate, easier for different teams to own, and lets us make some flows strictly repeatable and others adaptive."


Concepts you'll use (2-minute primer)

  • Sub-agents / delegation — give an LlmAgent a list of sub_agents. ADK lets it transfer a request to a sub-agent; it chooses based on each sub-agent's `description`. This is dynamic, model-driven routing.
  • Coordinator (router) pattern — a top agent whose job is mostly to route, with specialists doing the real work.
  • Shared session — sub-agents run in the same session, so state and history are shared across the handoff (the memory from Lab 2 carries over).
  • Workflow — ADK 2.0's graph-based orchestrator. You define edges ([("START", a, b)]) and agents run as nodes in that order; output flows along edges. This is deterministic, developer-defined control flow. (It replaces the now-deprecated SequentialAgent / ParallelAgent / LoopAgent.)
  • `event.author` — on each event, which agent produced it — how you see who actually answered.

Prerequisites

You needNotes
Labs 1–2 helpfulThis builds on the same ideas/domain
Python 3.11+ and pipADK 2.0
A Gemini API keyFree at aistudio.google.com/apikey
Get the starter repo. adk-lab-03/ has two agent packages — acme_support/ (coordinator) and pipeline/ (Workflow) — plus main.py and test_tools.py.

Setup (3 minutes)

bash
cd adk-lab-03
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp acme_support/.env.example acme_support/.env     # set GOOGLE_API_KEY=...
cp pipeline/.env.example pipeline/.env             # same key

python test_tools.py                                # 7/7 pass, no key needed
Each specialist owns its logic. orders_logic.py and returns_logic.py are separate, plain-Python modules — mirroring how different teams would own different agents — and both are unit-tested offline. You just verified the capabilities before any model is involved.

Exercise 1 — Build focused specialists (12 min)

Goal: Create two small, single-purpose agents — the building blocks of the team.

Open acme_support/agent.py. Each specialist is a plain LlmAgent with a tight instruction, its own tools, and — crucially — a `description`:

python
orders_agent = Agent(
    name="orders_specialist",
    model="gemini-2.5-flash",
    description=("Handles order STATUS questions: where an order is, its total, "
                 "and its estimated delivery date. Use for 'where is my order', "
                 "'when will it arrive', 'how much was order X'."),
    instruction="You are the Acme orders specialist. Use get_order_status ...",
    tools=[get_order_status],
)

returns_agent = Agent(
    name="returns_specialist",
    description=("Handles RETURNS and refunds: whether an order can be returned "
                 "and opening a return (RMA). Use for 'I want to return' ..."),
    instruction="You are the Acme returns specialist. Use check_return_eligibility ...",
    tools=[check_return_eligibility, start_return],
)

Two things to notice:

  • The `description` is for the *coordinator*, not the user. In Lab 1 description barely mattered; here it's how the router decides where a request goes. Notice it's written with example phrasings ("where is my order", "I want to return") — those are routing cues.
  • Each specialist is small. A tight instruction and 1–2 tools each. That focus is exactly why specialists are more reliable than a generalist juggling everything.
Business callout: specialist descriptions are now part of your system's contract. A vague or overlapping description causes mis-routing — the multi-agent equivalent of a bad API signature. They deserve review, and (Lab 4) evaluation.

Checkpoint: You have two focused experts. Now give them a manager.


Exercise 2 — Coordinate with dynamic delegation (12 min)

Goal: Add a coordinator that routes each request to the right specialist — and watch it happen.

The coordinator is just an LlmAgent with sub_agents:

python
root_agent = Agent(
    name="acme_support_coordinator",
    model="gemini-2.5-flash",
    instruction=("You are Acme's support coordinator. Route order/delivery/total "
                 "questions to the orders specialist; returns/refund questions to "
                 "the returns specialist. Don't answer specialist questions "
                 "yourself."),
    sub_agents=[orders_agent, returns_agent],
)

That sub_agents list is all it takes — ADK gives the coordinator the ability to transfer control to a sub-agent. Run it:

bash
python main.py
text
User:  Where is my order A-1024 and when will it arrive?
Agent: Order A-1024 is shipped; it's estimated to arrive 2026-06-25.    [answered by: orders_specialist]

User:  I'd like to return order A-1100 — is it eligible?
Agent: Yes — A-1100 was delivered, so it's eligible for return within 30 days. ...    [answered by: returns_specialist]

The [answered by: ...] comes from each event's `author` — proof the coordinator handed off to a different specialist each time, even though the customer only addressed one agent. Run adk web ., pick acme_support, and you'll see the transfer in the event stream before the specialist replies.

Business callout: this is the org chart made executable. One front door for the customer; specialized teams behind it, each independently ownable and improvable. The coordinator's only job is good routing — a small, testable responsibility.
Tip — shared context: because sub-agents share the session, anything one specialist stored in state (Lab 2's active_order, the customer's name) is visible to the next. Context follows the customer across the handoff instead of being lost.

Checkpoint: You have a working coordinator + specialists. Now the deterministic alternative.


Exercise 3 — Deterministic orchestration with Workflow (12 min)

Goal: Build a fixed pipeline where you control the order, not the model.

Sometimes you don't want the model deciding the path — you want the same steps, every time, in the same order (think: triage → respond, or validate → process → notify). That's a `Workflow`. Open pipeline/agent.py:

python
from google.adk import Agent, Workflow

triage_agent = Agent(name="triage_agent", ...,
    instruction="Classify the message (ORDER_STATUS/RETURN/BILLING/OTHER), note any order ID, summarize in one line.")

responder_agent = Agent(name="responder_agent", ...,
    instruction="Given the triage summary, draft a short friendly reply with the next step.")

root_agent = Workflow(
    name="support_pipeline",
    edges=[("START", triage_agent, responder_agent)],
)

The edges define a graph: START → triage_agent → responder_agent. Each node runs in order, and the output of one flows to the next. Run it:

bash
adk web .     # pick "pipeline", then send a customer message

You'll see triage run first (classification + summary), then the responder draft a reply from it — deterministically, the same path every time.

What changed in ADK 2.0: the graph-based Workflow is the current way to express orchestration. The older SequentialAgent, ParallelAgent, and LoopAgent are deprecated. A linear edge chain (like ours) is the "sequential" case; you express parallel fan-out, joins, and loops by adding more edges — one mental model for all control flow.
Business callout: deterministic workflows are what you reach for when repeatability and auditability matter — regulated processes, anything that must always run the same checks in the same order. The graph is the documentation: anyone can read the edges and know exactly what runs when.

Checkpoint: You can build both model-routed and developer-defined multi-agent systems. Now: how to choose.


Exercise 4 — Choose the right pattern (10 min)

Goal: Build judgment about when to use delegation vs. a Workflow vs. just one agent.

Use this decision guide, then sanity-check it against the two systems you built:

If the flow is…Use…Because…
One focused task, a few toolsA single agent (Labs 1–2)Don't add agents you don't need; every hop costs latency + tokens.
Path depends on the user's intentCoordinator + `sub_agents`The model routes adaptively to the best specialist.
Steps are known and must be repeatable`Workflow` graphYou fix the order; it's predictable and auditable.
Both: adaptive entry, fixed sub-processMix theme.g. a coordinator that routes into a Workflow for a regulated step.

Two judgment calls worth internalizing:

  • Don't decompose prematurely. Two specialists and a coordinator is three model calls where one might do. Split when a single agent is genuinely straining (too many tools, conflicting instructions, mis-using tools) — not by default.
  • Routing quality is a real metric. A coordinator that mis-routes is a bug you can't see without measuring. Note for Lab 4: "did the right specialist handle this?" is exactly the kind of thing an eval set should check.

Checkpoint: You can pick the simplest multi-agent shape that fits a problem — including "none, use one agent."


Wrap-up

You turned one agent into a coordinated team. You can now:

  • Build focused specialist agents whose `description` drives routing
  • Add a coordinator with `sub_agents` for dynamic, model-driven delegation
  • Build a deterministic `Workflow` graph (the ADK 2.0 way) for fixed control flow
  • Choose between one agent, delegation, and a Workflow based on the problem

The one idea to carry forward: multi-agent design is about matching structure to the problem — focused specialists for reliability, model routing for adaptivity, Workflow graphs for repeatability — without decomposing further than the problem demands. ADK gives you all three on one foundation, and the shared session means context follows the work across every handoff.


Looking ahead to Lab 4

You now have a system with multiple agents and a router — which raises the obvious question: is it actually routing correctly, and behaving safely? Lab 4 adds evaluation (evalsets to score routing and answers), callbacks as guardrails (filter inputs/outputs, gate tool use), and tracing. It builds on this repo.


Stretch challenges

  1. Add a third specialist. Create a billing_specialist (e.g. an "explain my charge" tool) with a clear description and add it to sub_agents. Test that billing questions route to it.
  2. Agent-as-tool. Instead of a sub-agent transfer, wrap a specialist as a tool with AgentTool so the coordinator calls it and keeps control. Compare the two delegation styles.
  3. Branch the Workflow. Extend the pipeline graph so triage routes BILLING messages to a different responder than ORDER_STATUS — practice expressing branching with edges.
  4. Measure routing. Jot 10 example requests and the specialist each should go to — a head start on the Lab 4 eval set for routing accuracy.

Troubleshooting

SymptomLikely cause / fix
ModuleNotFoundError: google.adkpip install -r requirements.txt (Python 3.11+). The tool tests run without it.
Requests go to the wrong specialistSharpen each specialist's description (distinct scopes, example phrasings) and the coordinator's routing instruction.
adk web shows only one agentRun it from the folder containing both packages; keep each package's __init__.py.
Coordinator answers instead of routingTell it explicitly not to answer specialist questions itself; ensure specialists have clear descriptions.
SequentialAgent deprecation warningExpected — use Workflow (this lab does).
Workflow node order seems offCheck the edges chain; output flows along edges in the order you declared.

References

Technical details follow the ADK 2.0 Python API:

A note on accuracy for your readers: code targets ADK 2.0 (Agent(sub_agents=[...]) for delegation; from google.adk import Workflow with edges=[("START", a, b)]; SequentialAgent/ParallelAgent/LoopAgent deprecated). The specialists' tool logic is unit-tested here; the agent/workflow wiring is syntax-verified against the 2.0 source. Pin your google-adk version and re-run before publishing.
WG

Written by Wes Goldwater, Director of Engineering at Prosigliere.

Hands-on cloud & pragmatic AI from Goldwater.dev.