3.2 Multi-Agent Workflow Patterns: Sequential, Parallel, Loop & Dynamic Routing
1. Key Concept Definitions: The 6 ADK Orchestration Primitives
Section titled “1. Key Concept Definitions: The 6 ADK Orchestration Primitives”ADK separates Deterministic Workflow Agents (which execute in code without an LLM deciding the control flow) from Dynamic LLM Routing and Custom Imperative Agents:
1. SequentialAgent
Executes its
sub_agents list in strict chronological order (Step 1 -> Step 2 -> Step 3), passing the exact same InvocationContext and session.state along the chain.2. ParallelAgent
Executes independent
sub_agents concurrently to slash latency. All branches share the same session.state, so each branch must use a unique output_key to avoid race-condition overwrites!3. LoopAgent & escalate=True
Repeatedly runs its
sub_agents in sequence until either max_iterations is reached OR a sub-agent/tool emits an Event with EventActions(escalate=True).4. Dynamic sub_agents Transfer
Attaching children to an
LlmAgent(sub_agents=[…]) lets the LLM call transfer_to_agent(agent_name=…) based on each child’s description—handing conversation control over to the target agent.5. AgentTool (Agent-as-a-Tool)
Wraps a specialist agent inside
AgentTool(agent=…) and passes it in tools=[…]. The specialist runs in a sub-invocation and returns its answer back to the parent agent, which keeps control!6. CustomAgent (BaseAgent)
Subclasses
BaseAgent and overrides _run_async_impl(ctx) to implement arbitrary imperative Python control flow (such as if/else branching on session.state) between sub-agents.2. Interactive Multi-Agent Orchestration Switcher
Section titled “2. Interactive Multi-Agent Orchestration Switcher”Switch between the 3 Orchestration Modes below and click the 3 stages in each view to trace Sequential + Parallel Fan-Out/Gather, LoopAgent Termination, and Agent Transfer vs. AgentTool:
3. Master Multi-Agent Orchestration Matrix
Section titled “3. Master Multi-Agent Orchestration Matrix”Compare the six ADK orchestration mechanisms across control flow, state sharing, and primary architectural triggers:
| Orchestration Pattern | Who Controls the Flow? | How State & Outputs Flow | Primary Architectural Trigger |
|---|---|---|---|
SequentialAgent |
Deterministic Code (Fixed order: A -> B -> C) |
Shares InvocationContext; Step A writes output_key="k1", Step B reads {k1}. |
Multi-stage pipelines where every step must run in a guaranteed order. |
ParallelAgent |
Deterministic Code (All branches run concurrently) | Shares session.state concurrently; every branch needs a unique output_key. |
Running independent lookups (Credit + Fraud + Income) simultaneously to cut latency. |
LoopAgent |
Deterministic Code (Repeats sub_agents in a cycle) |
Iterates until max_iterations OR a sub-agent/tool emits EventActions(escalate=True). |
Generator + Critic refinement loops or iterative self-correction until a rubric passes. |
LlmAgent(sub_agents=[...]) |
Dynamic LLM Reasoning (transfer_to_agent) |
Parent LLM reads child description fields and hands conversation control to the selected child. |
Triage/concierge routers dispatching unpredictably structured user requests to domain bots. |
AgentTool(agent=...) |
Dynamic LLM Reasoning (Parent calls child as a tool) | Child runs in an isolated sub-invocation and returns its result back to the parent agent. | Parent must consult multiple specialists and synthesize the final answer itself (or wrap a Built-In Search agent). |
CustomAgent (BaseAgent) |
Imperative Python Code (_run_async_impl) |
Full programmatic inspection of ctx.session.state with Python if/else branching across child agents. |
Complex conditional workflows where branch selection depends on deterministic Python rules rather than LLM choice. |
4. Real-World Deep Dive: Workflow Agent Brain-Twisters
Section titled “4. Real-World Deep Dive: Workflow Agent Brain-Twisters”| Architect Question | How It Works Under the Hood in Production |
|---|---|
“In a LoopAgent, why doesn’t the loop stop when the Critic Agent outputs the text 'APPROVED'—and how does tool_context.actions.escalate = True stop it?” |
Deterministic Event Signal vs. Free Text: LoopAgent does not use an LLM to read its sub-agents’ text outputs! Instead, after each sub-agent finishes, LoopAgent checks the emitted ADK Event.actions.escalate boolean flag. Give the Critic Agent a simple exit_loop(tool_context: ToolContext) function tool that sets tool_context.actions.escalate = True when the draft passes! |
“Can we nest Workflow Agents inside each other—for example, putting a ParallelAgent and a LoopAgent inside a parent SequentialAgent?” |
100% Composable Hierarchy (BaseAgent): Because SequentialAgent, ParallelAgent, LoopAgent, and LlmAgent all inherit from BaseAgent, you can nest them arbitrarily! A classic production blueprint is SequentialAgent([ ParallelAgent([Credit, Fraud]), SynthesizerAgent, LoopAgent([Drafter, ComplianceCritic]) ]). |
“When should we subclass BaseAgent (CustomAgent) instead of using SequentialAgent or LlmAgent(sub_agents=[...])?” |
Deterministic Conditional Branching (if/else): SequentialAgent always runs every sub-agent in its list, while LlmAgent relies on probabilistic LLM routing. If you need deterministic conditional logic—such as “Run HighRiskAuditAgent ONLY if ctx.session.state['loan_amount'] > 500000, otherwise skip directly to FastApprovalAgent”—subclass BaseAgent and write a standard Python if/else block inside _run_async_impl(ctx)! |