Skip to content

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:

Stage 1 / 3
1. Parallel Fan-Out3 Concurrent Sub-Agents2. Unique output_keyZero State Overwrites!3. Sequential GatherSynthesizer Reads All 3
COMPOSITE PATTERN: PARALLEL FAN-OUT + SEQUENTIAL GATHER
1. Concurrent Execution with ParallelAgent
How It Works
ParallelAgent launches CreditAgent, FraudAgent, and IncomeAgent simultaneously, reducing three 4-second lookups from 12 seconds down to 4 seconds!
Core Architecture Rule
ParallelAgent is a deterministic Workflow Agent—it never calls an LLM to decide which branch to run; it runs ALL branches concurrently!

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)!