5. Workflow Agents (Sequential, Loop, Parallel)

This blog is part of the ADK Masterclass - Hands-On Series. While standard LLM Agents are great for open-ended tasks, many business processes require structure and predictability. This is where Workflow Agents come in.

Workflow Agents in ADK allow us to orchestrate other agents in predefined patterns: strict sequences, parallel execution, or iterative loops. They provide the control structure needed for robust applications.

View Code on GitHub

Table of Contents

1. What are Workflow Agents?

Workflow Agents are a unique class of components in ADK that focus exclusively on coordinating and scheduling other agents. They act as the traffic controllers of our agent system, dictating the order and timing of when each sub-agent executes.

While standard LLM Agents leverage language models to make intelligent decisions on the fly, Workflow Agents follow a rigid, code-defined blueprint. The sequence of operations is determined by the workflow type we choose (sequential, parallel, or loop) and is executed mechanically, with no AI reasoning involved in deciding what happens next. This mechanical approach ensures that our process runs the same way every time, with no surprises.

2. Why Use Workflow Agents?

In real-world applications, we can't afford to let an LLM "figure out" the process flow on its own. Workflow Agents solve this by giving us programmatic control over our agent orchestration, delivering three critical advantages:

  • Predictable Execution: The execution path is locked in at development time. We define the sequence once, and it runs the same way every single execution. No LLM can decide to skip a step or change the order.
  • Repeatable Results: Because the workflow structure is deterministic, we can test it, version it, and deploy it with confidence. The same input will always produce the same execution pattern.
  • Modular Architecture: Instead of one monolithic agent trying to do everything, we break complex problems into smaller, focused agents that the workflow coordinates. This makes our code easier to understand, modify, and maintain.

3. Core Workflow Patterns

ADK offers three fundamental workflow architectures, each serving a different organizational need:

Sequential Agents

These agents run their sub-agents in a strict, linear order. Each agent waits for the previous one to finish, then uses that output as its input. Think of it like a relay race where the baton (data) is passed from one runner (agent) to the next. This pattern works best when each step depends on the results of the previous step.

graph LR Input[Input] --> A[Agent A] A -->|Output A| B[Agent B] B -->|Output B| C[Agent C] C --> Output[Final Output] style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style A fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style B fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style C fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

Parallel Agents

These agents launch all their sub-agents simultaneously, giving them the same starting point. Each agent works independently, and we collect all their outputs at the end. It's like asking multiple experts to review the same document at the same time, which gives us faster results and multiple viewpoints. We use this when tasks are independent and can benefit from concurrent execution.

graph TD Input[Input] --> A[Agent A] Input --> B[Agent B] Input --> C[Agent C] A --> Output[Combined Output] B --> Output C --> Output style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style A fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style B fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style C fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

Loop Agents

These agents repeatedly execute their sub-agents until a stopping condition is satisfied. It's the AI equivalent of a "do-while" loop, where the agent keeps refining or retrying until it meets our criteria. This is invaluable for quality control, iterative improvement, or any scenario where we need the agent to self-correct until it gets it right.

graph TD Input[Input] --> Agent[Agent] Agent --> Check{Condition Met?} Check -->|No| Agent Check -->|Yes| Output[Final Output] style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style Agent fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Check fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

4. Tutorial

We'll build three different pipelines to demonstrate each workflow pattern. Before we start, let's set up our environment.

Prerequisites

Step 1: Setup Environment

python3 -m venv .venv
source .venv/bin/activate
pip install google-adk python-dotenv

# Set your API Key
export GEMINI_API_KEY=your_api_key_here

4.1. Building an Investment Research Pipeline - Sequential Agent

Let's build a practical Sequential Workflow for a financial services firm. We want to take a company ticker symbol and generate a comprehensive investment research report with analysis and recommendations.

Initialize the project:

adk create investment_pipeline
cd investment_pipeline
graph LR Input[Company Ticker] --> A subgraph Pipeline [SequentialAgent Pipeline] direction LR A[FinancialDataCollector] --> B[FinancialAnalyst] B --> C[ReportGenerator] end C --> Output[Investment Report] style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style Pipeline fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style A fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style B fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style C fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

Step 1: Define the Workers

We'll create three specialized agents that work together. Each agent stores its output in the shared state using output_key, allowing the next agent to access previous results.

from google.adk.agents import SequentialAgent, LlmAgent
import os

MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")

# Data Collector Agent: Gathers financial information
data_collector = LlmAgent(
    name="FinancialDataCollector",
    model=MODEL,
    instruction="""For the given company ticker, compile key financial data:
- Recent stock performance
- Revenue trends
- Profitability metrics
- Market position
- Industry context

Present as structured bullet points with numbers where relevant.""",
    description="Collects and structures financial data about a company.",
    output_key="financial_data"
)

# Analyst Agent: Performs financial analysis
financial_analyst = LlmAgent(
    name="FinancialAnalyst",
    model=MODEL,
    instruction="""Analyze this financial data and provide investment insights:

{financial_data}

Provide:
- Strengths and opportunities
- Risks and concerns
- Key financial ratios assessment
- Competitive positioning

Format as a structured analysis.""",
    description="Analyzes financial data and identifies key insights.",
    output_key="analysis"
)

# Report Generator Agent: Creates final report
report_generator = LlmAgent(
    name="ReportGenerator",
    model=MODEL,
    instruction="""Create a professional investment research report using:

Financial Data:
{financial_data}

Analysis:
{analysis}

Structure the report with:
- Executive Summary
- Financial Overview
- Investment Thesis
- Risk Assessment
- Recommendation (Buy/Hold/Sell)

Keep it professional and suitable for institutional investors.""",
    description="Generates comprehensive investment research reports.",
    output_key="final_report"
)

Step 2: Create the Workflow

We combine these agents into a SequentialAgent. The workflow will execute them in order: Collect Data → Analyze → Generate Report.

research_pipeline = SequentialAgent(
    name="InvestmentResearchPipeline",
    sub_agents=[data_collector, financial_analyst, report_generator],
    description="Generates investment research reports through data collection, analysis, and report generation."
)

root_agent = research_pipeline

Step 3: Run the Pipeline

We can run this pipeline using the ADK web interface. Each agent's output flows to the next via the shared state.

adk web

How It Works

When we run this SequentialAgent pipeline with a company ticker, ADK executes each sub-agent in order, automatically managing data flow through a shared state dictionary:

  1. Input: A company ticker (e.g., "AAPL") enters the SequentialAgent as the user query.
  2. Step 1 - FinancialDataCollector: The first sub-agent receives the ticker and gathers financial information. The output is stored in state['financial_data'] via output_key="financial_data".
  3. Step 2 - FinancialAnalyst: ADK automatically injects state['financial_data'] into the FinancialAnalyst's instruction. The analysis is stored in state['analysis'].
  4. Step 3 - ReportGenerator: ADK automatically injects both state['financial_data'] and state['analysis']. The final report is stored in state['final_report'].
  5. Output: The complete investment research report is returned.

The SequentialAgent ensures each sub-agent runs in the exact order we specified in sub_agents=[data_collector, financial_analyst, report_generator]. This state-based pattern modularizes our logic and makes data flow explicit.

4.2. Building a Risk Assessment Pipeline - Parallel Agent

Let's build a practical Parallel Workflow for comprehensive risk assessment. We want multiple analysts to evaluate the same investment opportunity simultaneously, each focusing on a different risk dimension.

Initialize the project:

adk create risk_assessment
cd risk_assessment
graph TD Input[Investment Opportunity] Output[Risk Analyses in State] subgraph Pipeline ["ParallelAgent Pipeline"] A[MarketRiskAnalyst] B[CreditRiskAnalyst] C[OperationalRiskAnalyst] end Input --> A Input --> B Input --> C A --> Output B --> Output C --> Output style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style Pipeline fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style A fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style B fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style C fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

Step 1: Define the Workers

We'll create three specialized risk assessment agents that work independently on the same input. Each agent focuses on a different risk category and stores its output in the shared state.

from google.adk.agents import ParallelAgent, LlmAgent
import os

MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")

# Market Risk Analyst: Evaluates market volatility and trends
market_risk_analyst = LlmAgent(
    name="MarketRiskAnalyst",
    model=MODEL,
    instruction="""Analyze the market risk factors for this investment:

{input}

Assess:
- Market volatility trends
- Sector performance
- Macroeconomic factors
- Market sentiment indicators

Provide a risk score (1-10) and detailed analysis.""",
    description="Evaluates market-related risks for investments.",
    output_key="market_risk_analysis"
)

# Credit Risk Analyst: Evaluates financial stability
credit_risk_analyst = LlmAgent(
    name="CreditRiskAnalyst",
    model=MODEL,
    instruction="""Analyze the credit risk factors for this investment:

{input}

Assess:
- Debt-to-equity ratios
- Credit ratings
- Liquidity position
- Financial leverage

Provide a risk score (1-10) and detailed analysis.""",
    description="Evaluates credit and financial risks for investments.",
    output_key="credit_risk_analysis"
)

# Operational Risk Analyst: Evaluates business operations
operational_risk_analyst = LlmAgent(
    name="OperationalRiskAnalyst",
    model=MODEL,
    instruction="""Analyze the operational risk factors for this investment:

{input}

Assess:
- Management quality
- Operational efficiency
- Regulatory compliance
- Business model sustainability

Provide a risk score (1-10) and detailed analysis.""",
    description="Evaluates operational and business risks for investments.",
    output_key="operational_risk_analysis"
)

Step 2: Create the Parallel Workflow

We combine these agents into a ParallelAgent. All three agents will execute simultaneously, receiving the same input and working independently. Each agent stores its analysis in the shared state using its output_key.

# Create the ParallelAgent (Runs risk analysts concurrently)
# This agent orchestrates the concurrent execution of the three risk analysts.
# It finishes once all analysts have completed and stored their results in state.
risk_assessment_pipeline = ParallelAgent(
    name="ParallelRiskAssessment",
    sub_agents=[market_risk_analyst, credit_risk_analyst, operational_risk_analyst],
    description="Runs multiple risk assessment agents in parallel to gather comprehensive risk analysis."
)

root_agent = risk_assessment_pipeline

Step 3: Run the Pipeline

We can run this pipeline using the ADK web interface. All three agents execute simultaneously, and their outputs are collected in the shared state.

adk web

How It Works

When we run this ParallelAgent pipeline, ADK executes all sub-agents simultaneously, each receiving the same input and working independently:

  1. Input: An investment opportunity enters the ParallelAgent as the user query.
  2. Parallel Execution: All three risk analysts (Market, Credit, Operational) receive the same input and execute simultaneously.
  3. State Storage: Each agent stores its analysis in separate state keys: state['market_risk_analysis'], state['credit_risk_analysis'], and state['operational_risk_analysis'].
  4. Output: All three risk assessments are available in the shared state for further processing or review.

The ParallelAgent ensures all sub-agents run concurrently, significantly reducing total processing time when tasks are independent. There is no automatic sharing of conversation history or state between the parallel branches during execution.

4.3. Building a Report Refinement Pipeline - Loop Agent

Let's build a practical Loop Workflow for iterative report refinement. We want an agent to repeatedly improve a report until it meets our quality criteria.

Initialize the project:

adk create report_refiner
cd report_refiner
graph TD Input[Initial Report] Output[Final Report] subgraph Pipeline ["LoopAgent Pipeline"] Checker[QualityChecker] Refiner[ReportRefiner] Check{No Issues Found?} Checker --> Refiner Refiner --> Check Check -->|No| Checker Check -->|Yes| Output end Input --> Checker style Input fill:#e1f5fe,stroke:#01579b,stroke-width:2px style Pipeline fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style Checker fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Refiner fill:#fff9c4,stroke:#fbc02d,stroke-width:2px style Check fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style Output fill:#ffebee,stroke:#c62828,stroke-width:2px

Step 1: Define the Workers

We'll create two agents that work together in the loop: a quality checker that evaluates the report, and a refiner that improves it based on feedback.

from google.adk.agents import LoopAgent, LlmAgent
import os

MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")

# Quality Checker: Evaluates the report against quality criteria
quality_checker = LlmAgent(
    name="QualityChecker",
    model=MODEL,
    instruction="""Review this investment report against quality criteria:

Current Report:
{refined_report}

Quality Criteria:
- Executive summary must be under 200 words
- All financial data must be cited
- Risk assessment must include specific metrics
- Recommendation must be clearly justified

IF the report meets all criteria:
Respond with exactly: "QUALITY_APPROVED"

ELSE:
Provide specific, actionable feedback on what needs improvement. Output *only* the feedback.""",
    description="Evaluates investment reports against quality criteria.",
    output_key="quality_feedback"
)

# Report Refiner: Improves the report based on feedback
report_refiner = LlmAgent(
    name="ReportRefiner",
    model=MODEL,
    instruction="""Refine this investment report based on quality feedback:

Current Report:
{refined_report}

Quality Feedback:
{quality_feedback}

IF the feedback is exactly "QUALITY_APPROVED":
The report is complete. Return the current report unchanged.

ELSE:
Apply the feedback to improve the report. Output *only* the refined report text.""",
    description="Refines investment reports based on quality feedback.",
    output_key="refined_report"
)

Step 2: Create the Workflow

We combine these agents into a LoopAgent with a maximum iteration limit. The loop will run the quality checker and refiner in sequence, repeating until the quality checker signals completion or the max iterations are reached.

# Create the LoopAgent (Runs quality checker and refiner iteratively)
# The loop will execute the sub-agents in order, repeating until max_iterations
# or until the quality checker signals completion
report_refinement_pipeline = LoopAgent(
    name="ReportRefinementPipeline",
    sub_agents=[quality_checker, report_refiner],
    max_iterations=5,
    description="Iteratively refines investment reports until quality criteria are met."
)

root_agent = report_refinement_pipeline

Step 3: Run the Pipeline

We can run this pipeline using the ADK web interface. The agent will loop until the report meets all quality criteria.

adk web

How It Works

When we run this LoopAgent pipeline, ADK repeatedly executes the sub-agents in sequence until the stopping condition is met or max iterations are reached:

  1. Input: An initial report enters the LoopAgent as the user query.
  2. Iteration 1: The QualityChecker evaluates the report. If it finds issues, it provides feedback stored in state['quality_feedback']. If no issues, it responds with "QUALITY_APPROVED".
  3. Refinement: The ReportRefiner receives both the report and feedback. If feedback indicates issues, it refines the report and stores it in state['refined_report']. If feedback is "QUALITY_APPROVED", it returns the report unchanged.
  4. Loop Decision: If the quality feedback is "QUALITY_APPROVED", the loop stops. Otherwise, the loop continues with the refined report (up to max_iterations=5).
  5. Output: The final refined report is stored in state['refined_report'] and returned.

The LoopAgent iterates through the sub-agents list in order for each iteration. You must implement a termination mechanism (like the "QUALITY_APPROVED" signal or max_iterations) to prevent infinite loops.

Next Steps

Now that we've covered workflow patterns, let's explore how multiple independent agents can collaborate:

Resources

Comments