AI Engineering Bootcamp · Week 3

Building
multi-agent
AI systems

From concepts to production. With ADK.
Session
Live · in cohort
You bring
Python 3.10+, a Gemini API key
Led by
Aki WijesundaraAki Wijesundara
Manu JayawardanaManu Jayawardana
Overview

Seven sections.

The path from a single-agent loop to a full multi-agent system with MCP and A2A.

Section
Type
1 · What are AI agents, really?
Lecture
2 · From single agent to multi-agent
Lecture
3 · Introducing ADK. Your build tool.
Lecture + Demo
4 · MCP. Giving agents tools.
Lecture + Demo
5 · A2A. Agents talking to agents.
Lecture + Demo
6 · Full system. Putting it all together.
Lecture + Demo
7 · Homework and next steps.
Assignment
Section 1 · What are AI agents, really?

Agents are LLMs with a loop.

A chatbot does input to output. An agent does think, act, observe, repeat.

Four core components
  • Instructions. System prompt. What to do, constraints, personality.
  • Model. GPT, Gemini, Claude, Llama. The reasoning engine.
  • Tools. Functions. Search, query DB, send email, call APIs.
  • Memory. Short-term (session) and long-term (across sessions).
Use agents when: multi-step tasks, ambiguous requests, external systems, unknown paths. Skip agents when: simple prompt/response, deterministic workflow, latency-critical.
The agent loop (ReAct)
User input
Reason (LLM)
Act (Tools)
Observe (Results)
Done? No, back to Reason.
Section 2 · From single agent to multi-agent

Why multi-agent, and how to design it.

One agent with fifteen or more tools breaks. Split by domain, each agent gets a focused job, short instructions, and limited tools.

Four multi-agent patterns
  • Router / Delegation. Root reads intent, delegates to specialist. We build this today.
  • Sequential Pipeline. Fixed order. A to B to C. Content gen, data processing.
  • Parallel Fan-Out. Simultaneous agents, merge results. Research, aggregation.
  • Loop / Refinement. Produce, review, loop until quality met. Writing, code gen.
Key design decisions
  • How many agents? Split by domain, not by task.
  • Who routes? LLM (adaptive) or workflow (deterministic).
  • Data sharing? Session state, output keys, or external DB.
  • Failure handling? Escalation, fallback to human, retry.
ModularitySpecializationReusabilityTestabilityScalability
Section 3 · Introducing ADK

What is ADK?

Agent Development Kit. Google's open-source framework for building and deploying AI agents.

Open source

Multi-language from the start

Python, TypeScript, Go, Java.

Model-agnostic

Use anything

Gemini, Claude, Ollama, LiteLLM, or any model.

Deployment-agnostic

Run anywhere

Locally, on Cloud Run, GKE, or Vertex AI.

Native MCP + A2A

Built-in support

Both open protocols that matter for production agent systems.

Designed to make agent development feel like software development. Not prompt engineering with extra steps.
Section 3 · Introducing ADK

Why ADK over other frameworks?

Framework
Strength
Trade-off
LangGraph
Graph-based orchestration, strong community.
Steeper learning curve.
CrewAI
Role-based multi-agent, easy to start.
Less control over execution flow.
AutoGen
Research-grade multi-agent conversations.
Complex setup, Microsoft-centric.
ADK
Multi-language, native MCP + A2A, built-in eval + dev UI.
Newer ecosystem, still maturing.
ADK's differentiator: natively supports both MCP (tool standard) and A2A (agent communication standard).
Section 3 · Introducing ADK

Your first agent in ADK.

Tools are plain Python functions. ADK wraps them automatically.

from google.adk.agents import Agent def lookup_customer(email: str) -> dict: "Look up customer account information by email." return {"name": "Jane Doe", "plan": "Pro"} def check_order_status(order_id: str) -> dict: "Check the current status of an order." return {"order_id": order_id, "status": "shipped"} support_agent = Agent( name="support_agent", model="gemini-2.5-flash", instruction="You are a helpful customer support agent.", tools=[lookup_customer, check_order_status], )
The LLM reads the function names and docstrings to decide when to call them. No schema definitions needed.
Section 3 · Introducing ADK

Your first multi-agent system in ADK.

The root agent reads each sub-agent's description and decides who handles the query.

billing_agent = Agent( name="billing_agent", model="gemini-2.5-flash", description="Handles billing: invoices, payments, refunds.", instruction="Help customers with billing issues.", tools=[lookup_invoice, process_refund], ) technical_agent = Agent( name="technical_agent", model="gemini-2.5-flash", description="Handles technical issues: bugs, outages, how-to.", instruction="Help customers with technical problems.", tools=[search_knowledge_base, check_system_status], ) root_agent = Agent( name="support_router", model="gemini-2.5-flash", instruction="Route customer queries to the right specialist.", sub_agents=[billing_agent, technical_agent], )
No explicit routing logic needed. The LLM reads description and delegates automatically.
Section 3 · Demo 1

Multi-agent support system in ADK.

Building the multi-agent customer support system from the diagram.

Architecture
Root Agent (Router)
Billing
Technical
Escalation
What to notice
  • The router agent has no tools. It only routes.
  • Each specialist has a focused instruction and limited tools.
  • Try a billing question, then a technical question.
  • Watch the routing in the trace view.
  • ADK Dev UI shows the full execution path.
Section 4 · MCP. Giving agents tools.

What is MCP?

In Demo 1, we hardcoded tools as Python functions. In reality, agents need databases, SaaS platforms, APIs. MCP is the standard.

Think of it as USB for AI agents

One universal connector instead of a custom cable for every device.

Client-server architecture

  • MCP Server. Exposes tools, resources, data. Supabase, Asana, filesystem.
  • MCP Client. Your agent. Discovers and uses those tools.
What you can connect
  • Databases. Customer records, order data.
  • SaaS platforms. Asana, Jira, Salesforce.
  • Internal APIs. Knowledge bases, CRMs.
  • File systems. Documents, logs.
Section 4 · MCP

How MCP works.

Your agent discovers tools at runtime through a client-server protocol.

Your Agent
(MCP Client)
MCP Protocol
MCP Server
(Supabase)
Consuming
  • Your ADK agent connects to an MCP server, auto-discovers tools, and calls them transparently via McpToolset.
Exposing
  • Wrap your ADK tools as an MCP server. Any MCP client can use them. Claude Desktop, Cursor, other agents.
Section 4 · MCP

MCP in ADK. The code.

No hardcoded database functions. The agent discovers tools from the MCP server automatically.

from google.adk.agents import Agent from google.adk.tools.mcp_tool import McpToolset, StdioConnectionParams from mcp.client.stdio import StdioServerParameters supabase_mcp = McpToolset( connection_params=StdioConnectionParams( server_params=StdioServerParameters( command="npx", args=["-y", "@supabase/mcp-server-supabase@latest", "--access-token", TOKEN], ), ), ) billing_agent = Agent( model="gemini-2.5-flash", name="billing_agent_mcp", instruction="You are a billing specialist with real database access.", tools=[supabase_mcp], )
The agent discovers every available tool from the MCP server automatically. Zero custom integration code.
Section 4 · MCP

What you can connect via MCP.

Pre-built MCP servers in the ecosystem.

01

Databases

Supabase, Spanner, AlloyDB, Postgres (MCP Toolbox).

02

Project management

Asana (30+ tools), Atlassian (Jira + Confluence).

03

Google Cloud

BigQuery, Bigtable, Cloud API Registry.

04

Media

Imagen, Veo, Chirp 3 HD, Lyria (Genmedia MCP).

05

File systems

Local filesystem access, document reading.

06

Custom APIs

Any API via Apigee or your own MCP server.

The MCP ecosystem is growing fast. If it does not exist, build your own with FastMCP.
Section 4 · MCP

In production, always filter. Do not give an agent write access if it only needs to read.

Tool filtering. Use tool_filter to whitelist only the tools the agent needs. Security in production.
Section 4 · Demo 2

Agent + Supabase via MCP.

The Billing Agent now connects to a real Supabase database via MCP.

Setup
  • Supabase project with tables: customers, orders, support_tickets.
  • Supabase MCP server running locally.
  • Billing Agent connected via McpToolset.
What to notice
  • We did not write a single database query function.
  • Agent auto-discovers table operations from MCP server.
  • In the trace: see MCP tool discovery, then actual queries.
  • Agent figures out how to join data across tables on its own.
Section 5 · A2A. Agents talking to agents.

What is A2A?

MCP connects agents to tools. But what connects agents to other agents across systems? A2A is the open standard.

MCP

agent ↔ tool

Giving an agent a toolkit.

Multi-Agent

agent ↔ agent, same app

Teammates in the same room.

A2A

agent ↔ agent, across network

Calling a colleague at another office.

A2A lets a Python agent talk to a Java agent, or your support system call a partner's shipping agent. Without knowing how it is built.
Section 5 · A2A

How A2A works.

Two steps: expose and consume.

Step 1. Expose

Make your agent available on the network.

Your Agent to_a2a() A2A Server
Gets an Agent Card + network endpoint.
Step 2. Consume

Use someone else's agent.

Your Agent RemoteA2aAgent(url) Remote A2A
Feels like a local sub-agent. ADK handles networking.
Section 5 · A2A

Agent Cards. Discovery.

Every A2A agent has an Agent Card. A JSON file describing what it can do.

What the card carries
  • What the agent does.
  • What inputs it accepts.
  • What outputs it returns.
  • Where to reach it. A URL.
Think of it as

An API spec, but for agents. ADK auto-generates Agent Cards when you use to_a2a().

Discoverable, self-describing agents. No manual wiring per integration.
Section 5 · A2A

A2A in code. Expose and consume.

Two sides of the same protocol.

Expose
from google.adk.agents import Agent from google.adk.a2a.utils.agent_to_a2a import to_a2a shipping_agent = Agent( name="shipping_status_agent", model="gemini-2.5-flash", instruction="Look up shipping status.", tools=[get_shipping_status], ) app = to_a2a(shipping_agent, port=8001) # uvicorn agent:app --port 8001
Consume
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent remote_shipping = RemoteA2aAgent( name="shipping_agent", agent_card="http://localhost:8001", ) root_agent = Agent( name="customer_support", sub_agents=[billing, technical, remote_shipping], )
The remote agent sits alongside local sub-agents. The LLM routes to it like any other. Any framework, any language.
Section 5 · A2A

Real-world A2A use cases.

Where agent-to-agent communication makes sense.

Microservices architecture

Order Agent ↔ Inventory Agent ↔ Shipping Agent ↔ Payment Agent. Each an independent service, A2A as the communication layer.

Cross-org collaboration

Your support agent calls a partner's warranty verification agent. You do not know their tech stack.

Cross-language

Python orchestrator talks to a Java compliance agent and a Go data processing agent. A2A standardizes communication.

Third-party services

A financial data provider exposes real-time stock prices through an A2A agent. Your advisor agent consumes it.

Section 5 · Demo 3

A2A in action.

A separate Shipping Agent that our support system talks to via A2A.

Terminal 1. Shipping Agent (port 8001)
  • Standalone agent with tools.
  • Exposed via to_a2a().
Terminal 2. Support System (port 8000)
  • Multi-agent support system from Demo 1.
  • Now includes RemoteA2aAgent.
What to notice
  • Two separate processes, two terminals.
  • Support agent does not know how shipping agent works.
  • Reads the Agent Card, discovers capabilities, delegates.
  • In the trace: see the A2A network call.
  • Shipping agent could be swapped for any A2A-compatible agent.
Section 6 · Full system

The complete architecture.

Three layers. One system.

Root Agent (Router)
Billing
MCP: Supabase
Technical
MCP: Knowledge
RemoteA2a: Shipping
↓ A2A
Shipping Agent
(separate service)
Local + tools + remote agents. All routed by the LLM, all made discoverable by ADK.
Section 6 · Full system

When to use what.

A decision guide for the three patterns.

You need to
Use
Connect an agent to a database, API, or file system.
MCP
Split a complex task into focused agents in one app.
Multi-Agent
Call an agent running as a separate service.
A2A
Build a predictable pipeline (step 1 to 2 to 3).
Workflow Agents
Let the LLM decide which agent handles a request.
LLM Delegation
Make your agent usable by anyone, any framework.
A2A (expose)
Section 6 · Demo 4

The full system.

Everything together in one demo.

Components
  • Root Agent routes customer queries.
  • Billing Agent connects to Supabase via MCP.
  • Technical Agent uses a knowledge base MCP server.
  • Shipping goes to remote agent via A2A.
Test scenarios
  • "What is the status of my order #1234?" → Billing Agent → MCP → Supabase.
  • "My app keeps crashing on login." → Technical Agent → MCP → Knowledge Base.
  • "Where is my package?" → A2A → Remote Shipping Agent.
Section 6 · Full system

Evaluation and deployment.

Before you ship: test. When you ship: pick the right target.

ADK evaluation framework
  • Response Quality. Is the final answer correct? Define test cases with expected outputs.
  • Trajectory. Did the agent call the right tools and route to the correct sub-agent?
Deployment options
ADK Dev UI
Local dev and debugging.
CLI
Quick testing, CI/CD.
Agent Engine
Managed production (Vertex AI).
Cloud Run
Containerized, custom infra.
GKE
Kubernetes, multi-service.
All paths support A2A. Agents can be exposed and consumed regardless of where they run.
Section 7 · Homework and next steps

Homework assignment.

Build a Multi-Agent Customer Support System with MCP and A2A.

01

Supabase setup

Create a Supabase project with customers, orders, support_tickets tables. Seed with 10+ records per table.

02

Multi-agent system in ADK

Root router + at least 2 specialist sub-agents. At least one connected to Supabase via MCP.

03

Returns Agent via A2A

Separate service with check_return_eligibility + initiate_return. Exposed via to_a2a().

04

Connect and test

Connect Returns Agent via RemoteA2aAgent. Test 3 scenarios: billing (MCP), returns (A2A), escalation.

Deliverables: working code in a GitHub repo, README with architecture diagram, screen recording of test scenarios in ADK Dev UI. Stretch: LoopAgent, tool filtering, eval test cases (5+), expose via A2A.
Section 7 · Resources

Resources.

Everything you need to build with ADK, MCP, and A2A.

Documentation
  • ADK Documentation. google.github.io/adk-docs/
  • A2A Protocol. google.github.io/adk-docs/a2a/
  • MCP Tools Guide. google.github.io/adk-docs/tools-custom/mcp-tools/
  • Multi-Agent Systems. google.github.io/adk-docs/agents/multi-agents/
Repositories
  • ADK Python. github.com/google/adk-python
  • ADK TypeScript. github.com/google/adk-js
  • Supabase MCP. github.com/supabase-community/supabase-mcp
Key takeaways

Three things to remember.

MCP

agent ↔ tool

How agents access tools and data.

Multi-Agent

agent ↔ agent, same app

How agents work together locally.

A2A

agent ↔ agent, across network

How agents collaborate across boundaries.

These three patterns compose. Start with the concepts, pick the right pattern, then implement with ADK.
Bonus Section

New Kids on the Block.

Terms you'll hear over the coming months. Awareness only, no demos, not required for homework.

New Kids on the Block

The Five Layers of AI Engineering.

Five layers, stacked. Today's session sat at the Loop and Graph layers.

Layer What you engineer Your role Core question
PromptThe single requestOperatorAm I asking well?
ContextWhat the model seesEditorDoes it have the right information?
HarnessTools, memory, scaffoldingToolmakerCan it act and remember?
LoopThe cycle one agent repeatsSystem designerWhen does it check its work and stop?
GraphCoordination between many agentsOrg designerWho does what, in what order, sharing what state?
The stack is cumulative, not a ladder you climb away from. A graph is full of nodes, a good node is a well designed loop, a good loop needs a real harness. Skip a lower layer and the graph on top just fails in a more elaborate way.
New Kids on the Block

Graph Engineering.

Three ideas: nodes, edges, and the state that flows between them.

Nodes

Units that do work, one job each. A specialised agent or a plain deterministic step.

Edges

The routing between nodes: straight, conditional, fan-out, fan-in.

State

The object travelling along the edges that every node reads from and writes to.

You already built a graph today, we just didn't call it that. ADK's SequentialAgent is a straight edge, ParallelAgent is fan-out then fan-in, LoopAgent is an edge back to itself, and an LlmAgent with sub_agents is a conditional edge decided at runtime.
New Kids on the Block

Is This Just LangGraph?

Short answer: the mechanics are not new. Directed graphs, state machines, and agent-to-agent protocols predate the term by years.

Harrison Chase, creator of LangGraph

Replied that he didn't really know what graph engineering was and still doesn't, but it's basically just LangGraph.

David Khourshid, creator of XState

Dismissed it as slop.

What's new is a shared name for design decisions these frameworks always asked of you: what are the nodes, what are the edges, what's in the state. The label is optional. The escalation from one loop to coordinated specialised nodes is real.
New Kids on the Block

Loop Engineering.

Three different things get called "loop". The ReAct cycle inside one agent (Section 1). ADK's LoopAgent, a refinement pattern. And loop engineering, the third one, covered here.

Designing the system that prompts the agent, instead of being the person who prompts it. A recursive goal where you define the purpose and the AI iterates until complete.

Boris Cherny, head of Claude Code at Anthropic, says he doesn't prompt Claude anymore. He has loops running that prompt Claude and figure out what to do. His job is to write loops.

1. Automations

Scheduled discovery and triage. The heartbeat.

2. Worktrees

So parallel agents don't collide on the same files.

3. Skills

Project knowledge written down instead of guessed every session.

4. Connectors

Which are MCP. The thing you learned in Section 4.

5. Sub-agents

So the one who writes isn't the one who checks. Same principle as router plus specialists.

6. State

A file or board outside the conversation, because the model forgets everything between runs.

Token cost blows up fast, and verification stays with you. A loop running unattended is also a loop making mistakes unattended. "Done" is a claim, not a proof.

New Kids on the Block

Harness and Context Engineering.

Two layers beneath the loop.

Harness, the six components

What makes a single agent able to act at all.

Context Tools Orchestration State Evaluation Recovery

ADK gave you most of this for free today, which is why we didn't have to talk about it.

Context, the bottleneck nobody demos
  • The context window fills with tool observations, not just conversation
  • Compaction and summarisation happen between turns
  • What belongs in session state versus what gets re-injected each turn
  • Truncating tool output before it hits the model
If your nodes are weak agents, wiring them into an org chart just gives you a weak org. An agent with 15 tools doesn't break because of the tool count, it breaks because the context fills with junk.
01 / 34