Developer’s guide to multi-agent patterns in ADK

Published: (January 27, 2026 at 07:04 PM EST)
9 min read

Source: Google Developers Blog

Source: Google Developers Blog
Date: Dec 16, 2025


The world of software development has already learned this lesson: monolithic applications don’t scale. Whether you’re building a massive e‑commerce platform or a complex AI application, relying on a single, all‑in‑one entity creates bottlenecks, increases debugging costs, and limits specialized performance.

The same principle applies to an AI agent. A single agent tasked with too many responsibilities becomes a “Jack of all trades, master of none.” As the complexity of instructions increases, adherence to specific rules degrades, and error rates compound, leading to more and more “hallucinations.” If your agent fails, you shouldn’t have to tear down the entire prompt to find the bug.

Reliability comes from decentralization and specialization. Multi‑Agent Systems (MAS) let you build the AI equivalent of a micro‑services architecture. By assigning specific roles (a Parser, a Critic, a Dispatcher) to individual agents, you build systems that are inherently more modular, testable, and reliable.

In this guide we’ll use the Google Agent Development Kit (ADK) to illustrate eight essential design patterns—from the Sequential Pipeline to the Human‑in‑the‑loop pattern—providing concrete patterns and pseudocode you need to build production‑grade agent teams.


1. Sequential Pipeline Pattern (aka the assembly line)

Think of this pattern as a classic assembly line where Agent A finishes a task and hands the baton directly to Agent B. It is linear, deterministic, and refreshingly easy to debug because you always know exactly where the data came from.

Typical use‑case: processing raw documents.
ParserExtractorSummarizer

Sequential pattern

In ADK, the SequentialAgent primitive handles the orchestration for you. The secret sauce is state management: simply use output_key to write to the shared session.state so the next agent in the chain knows exactly where to pick up the work.

# ADK Pseudocode

# Step 1: Parse the PDF
parser = LlmAgent(
    name="ParserAgent",
    instruction="Parse raw PDF and extract text.",
    tools=[PDFParser],
    output_key="raw_text"
)

# Step 2: Extract structured data
extractor = LlmAgent(
    name="ExtractorAgent",
    instruction="Extract structured data from {raw_text}.",
    tools=[RegexExtractor],
    output_key="structured_data"
)

# Step 3: Summarize
summarizer = LlmAgent(
    name="SummarizerAgent",
    instruction="Generate summary from {structured_data}.",
    tools=[SummaryEngine]
)

# Orchestrate the Assembly Line
pipeline = SequentialAgent(
    name="PDFProcessingPipeline",
    sub_agents=[parser, extractor, summarizer]
)

2. Coordinator / Dispatcher Pattern (aka the concierge)

Sometimes you don’t need a chain; you need a decision‑maker. In this pattern, a central, intelligent agent acts as a dispatcher. It analyzes the user’s intent and routes the request to the specialist agent best suited for the job.

Typical use‑case: complex customer‑service bots that need to route a user to a “Billing” specialist or a “Tech Support” specialist.

Coordinator‑dispatcher pattern

This relies on LLM‑driven delegation. Define a parent CoordinatorAgent and provide a list of specialist sub_agents. ADK’s AutoFlow mechanism transfers execution based on the descriptions you provide for the children.

# ADK Pseudocode

billing_specialist = LlmAgent(
    name="BillingSpecialist",
    description="Handles billing inquiries and invoices.",
    tools=[BillingSystemDB]
)

tech_support = LlmAgent(
    name="TechSupportSpecialist",
    description="Troubleshoots technical issues.",
    tools=[DiagnosticTool]
)

# The Coordinator (Dispatcher)
coordinator = LlmAgent(
    name="CoordinatorAgent",
    instruction=(
        "Analyze user intent. Route billing issues to BillingSpecialist "
        "and bugs to TechSupportSpecialist."
    ),
    sub_agents=[billing_specialist, tech_support]
)

3. Parallel Fan‑Out / Gather Pattern (aka the octopus)

Speed matters. If you have tasks that don’t depend on each other, why run them one by one? In this pattern, multiple agents execute tasks simultaneously to reduce latency or gain diverse perspectives. Their outputs are then aggregated by a final “synthesizer” agent.

Typical use‑case: automated code review. Spawn a Security Auditor, a Style Enforcer, and a Performance Analyst in parallel, then combine their feedback with a Synthesizer agent.

Parallel fan‑out pattern

The ParallelAgent in ADK runs sub_agents concurrently. Although these agents operate in separate execution threads, they share the same session state, so be mindful of race conditions when writing to shared keys.

# ADK Pseudocode

security_auditor = LlmAgent(
    name="SecurityAuditor",
    instruction="Check the PR for security vulnerabilities.",
    tools=[StaticAnalyzer]
)

style_enforcer = LlmAgent(
    name="StyleEnforcer",
    instruction="Enforce coding style guidelines.",
    tools=[Linter]
)

performance_analyst = LlmAgent(
    name="PerformanceAnalyst",
    instruction="Identify performance bottlenecks.",
    tools=[PerfProfiler]
)

# Synthesizer that gathers the three reports
synthesizer = LlmAgent(
    name="ReviewSynthesizer",
    instruction=(
        "Combine the outputs from SecurityAuditor, StyleEnforcer, and "
        "PerformanceAnalyst into a single, cohesive review comment."
    ),
    tools=[TextCombiner]
)

# Parallel orchestration
parallel_review = ParallelAgent(
    name="ParallelCodeReview",
    sub_agents=[security_auditor, style_enforcer, performance_analyst],
    gather_agent=synthesizer
)

The remaining five patterns (Human‑in‑the‑loop, Critic‑Reviewer, Adaptive Routing, Stateful Conversation, and Self‑Healing) follow similar principles and are detailed in the full ADK documentation.

1. Parallel fan‑out (aka the “Swarm”)

When a task can be broken into independent sub‑tasks, you can run several agents in parallel and then combine their results.
Each sub‑agent writes its output to a unique key in the session state to avoid race conditions.

# ADK Pseudo

# Define parallel workers
security_scanner = LlmAgent(
    name="SecurityAuditor",
    instruction="Check for vulnerabilities like injection attacks.",
    output_key="security_report"
)

style_checker = LlmAgent(
    name="StyleEnforcer",
    instruction="Check for PEP8 compliance and formatting issues.",
    output_key="style_report"
)

complexity_analyzer = LlmAgent(
    name="PerformanceAnalyst",
    instruction="Analyze time complexity and resource usage.",
    output_key="performance_report"
)

# Fan‑out (the Swarm)
parallel_reviews = ParallelAgent(
    name="CodeReviewSwarm",
    sub_agents=[security_scanner, style_checker, complexity_analyzer]
)

# Gather / Synthesize
pr_summarizer = LlmAgent(
    name="PRSummarizer",
    instruction=(
        "Create a consolidated Pull Request review using "
        "{security_report}, {style_report}, and {performance_report}."
    )
)

# Wrap in a sequence
workflow = SequentialAgent(sub_agents=[parallel_reviews, pr_summarizer])

2. Hierarchical decomposition (aka the Russian doll)

Large tasks may exceed a single agent’s context window. A high‑level agent can break the goal into sub‑tasks and delegate them to lower‑level agents. Unlike simple routing, the parent may wait for a sub‑task’s result before continuing its own reasoning.

hierarchical task decomposition agent

You can treat a sub‑agent as a tool by wrapping it in AgentTool. The parent agent then calls the whole sub‑workflow as a single function.

# ADK Pseudocode

# Level 3: Tool agents
web_searcher = LlmAgent(
    name="WebSearchAgent",
    description="Searches the web for facts."
)

summarizer = LlmAgent(
    name="SummarizerAgent",
    description="Condenses text."
)

# Level 2: Coordinator agent
research_assistant = LlmAgent(
    name="ResearchAssistant",
    description="Finds and summarizes info.",
    # Coordinator manages the tool agents
    sub_agents=[web_searcher, summarizer]
)

# Level 1: Top‑level agent
report_writer = LlmAgent(
    name="ReportWriter",
    instruction=(
        "Write a comprehensive report on AI trends. "
        "Use the ResearchAssistant to gather info."
    ),
    # Expose the sub‑agent hierarchy as a tool for the parent
    tools=[AgentTool(research_assistant)]
)

3. Generator & Critic (aka the editor’s desk)

Separate creation from validation. The Generator produces a draft; the Critic checks it against hard‑coded criteria. If the draft fails, feedback is sent back to the Generator for revision. This loop continues until the output passes the quality gate.

generator‑critic agent pattern

Implementation uses a SequentialAgent for the draft‑review interaction and a LoopAgent to enforce the exit condition.

# ADK Pseudocode

# Generator
generator = LlmAgent(
    name="Generator",
    instruction=(
        "Generate a SQL query. If you receive {feedback}, "
        "fix the errors and generate again."
    ),
    output_key="draft"
)

# Critic
critic = LlmAgent(
    name="Critic",
    instruction=(
        "Check if {draft} is valid SQL. If correct, output 'PASS'. "
        "If not, output error details."
    ),
    output_key="feedback"
)

# Loop that repeats until the critic returns PASS
validation_loop = LoopAgent(
    name="ValidationLoop",
    sub_agents=[generator, critic],
    condition_key="feedback",
    exit_condition="PASS"
)

4. Iterative refinement (aka the sculptor)

For tasks that benefit from progressive improvement rather than a simple pass/fail, use a loop of Generator → Critic → Refinement agents. The loop terminates when a quality threshold is met, either after a fixed number of iterations or when an agent signals early completion (escalate=True).

iterative refinement agent pattern

# ADK Pseudocode

# Generator
generator = LlmAgent(
    name="Generator",
    instruction="Create a first draft of the document.",
    output_key="draft"
)

# Critic (provides improvement notes)
critic = LlmAgent(
    name="Critic",
    instruction="Review {draft} and return a list of improvement suggestions.",
    output_key="feedback"
)

# Refinement (applies suggestions)
refiner = LlmAgent(
    name="Refiner",
    instruction=(
        "Take {draft} and the suggestions in {feedback}, "
        "and produce an improved version."
    ),
    output_key="refined"
)

# Loop that continues until the critic signals quality or max_iterations is hit
refinement_loop = LoopAgent(
    name="IterativeRefinement",
    sub_agents=[generator, critic, refiner],
    condition_key="feedback",
    exit_condition="QUALITY_OK",   # can be set by the critic
    max_iterations=5
)

Summary of patterns

PatternWhen to useCore primitives
Parallel fan‑outIndependent sub‑tasks that can run concurrentlyParallelAgent, SequentialAgent
Hierarchical decompositionTasks too large for a single context windowNested LlmAgents wrapped with AgentTool
Generator & CriticNeed strict correctness or compliance checksSequentialAgent + LoopAgent
Iterative refinementQuality improves over multiple passesLoopAgent with custom exit logic

These patterns can be mixed and matched to build sophisticated, reliable workflows with the ADK framework.

Cleaned‑up Markdown

generator = LlmAgent(
    name="Generator",
    instruction="Generate an initial rough draft.",
    output_key="current_draft"
)

# Critique Agent
critic = LlmAgent(
    name="Critic",
    instruction="Review {current_draft}. List ways to optimize it for performance.",
    output_key="critique_notes"
)

# Refiner Agent
refiner = LlmAgent(
    name="Refiner",
    instruction="Read {current_draft} and {critique_notes}. Rewrite the draft to be more efficient.",
    output_key="current_draft"   # Overwrites the draft with a better version
)

# The Loop (Critique → Refine)
loop = LoopAgent(
    name="RefinementLoop",
    max_iterations=3,
    sub_agents=[critic, refiner]
)

# Complete Workflow
workflow = SequentialAgent(sub_agents=[generator, loop])

7. Human‑in‑the‑loop (the human safety net)

AI agents are powerful, but sometimes you need a human in the driver’s seat for critical decision‑making. In this model, agents handle the groundwork, but a human must authorize high‑stakes actions—especially those that are irreversible or carry significant consequences (e.g., executing financial transactions, deploying code to production, or acting on sensitive data). This ensures safety and accountability.

The diagram shows a Transaction Agent processing routine work. When a high‑stakes check is needed, it calls an ApprovalTool Agent, which pauses execution and waits for a Human Reviewer to say “Yes” or “No”.

human‑in‑the‑loop pattern

ADK allows you to implement this via custom tools. An agent can call an approval_tool which pauses execution or triggers an external system to request human intervention.

# ADK Pseudocode
transaction_agent = LlmAgent(
    name="TransactionAgent",
    instruction="Handle routine processing. If high stakes, call ApprovalTool.",
    tools=[ApprovalTool]
)

approval_agent = LlmAgent(
    name="ApprovalToolAgent",
    instruction="Pause execution and request human input."
)

workflow = SequentialAgent(sub_agents=[transaction_agent, approval_agent])

8. Composite patterns (the mix‑and‑match)

Real‑world enterprise applications rarely fit into a single box. You will likely combine these patterns to build production‑grade systems.

Example: A robust Customer‑Support system might use a Coordinator to route requests. If the user has a technical issue, that branch could trigger a Parallel search of documentation and user history. The final answer might then go through a Generator → Critic loop to ensure tone consistency before being sent to the user.

composite agent pattern


A few pro‑tips before you start

  • State management is vital: In ADK, session.state is your whiteboard. Use descriptive output_key names so downstream agents know exactly what they are reading.
  • Clear descriptions: When using routing, the description field of your sub‑agents acts as API documentation for the LLM. Be precise.
  • Start simple: Don’t build a nested loop system on day one. Begin with a sequential chain, debug it, then add complexity.

Get Started Now

Ready to build your team of agents? Check out the ADK Documentation to get started. We can’t wait to see what you build.

Back to Blog

Related posts

Read more »

A Guide to Fine-Tuning FunctionGemma

markdown Jan 16, 2026 In the world of Agentic AI, the ability to call tools is what translates natural language into executable software actions. Last month, we...

A Guide to Fine-Tuning FunctionGemma

markdown January 16, 2026 In the world of Agentic AI, the ability to call tools is what translates natural language into executable software actions. Last month...