intermediate5 sectionsUpdated Jun 15, 2025

Supervisor Pattern

A central orchestrator agent decomposes complex tasks into subtasks, delegates them to specialized worker agents, and aggregates results into a coherent final output.

Algorithm / Pseudocode
function Supervisor(task, workers):
    state = { task, subtasks: [], results: [] }

    // Phase 1: Decompose the task
    subtasks = LLM.decompose(task, workers.descriptions)
    state.subtasks = subtasks

    // Phase 2: Execute subtasks
    while state.has_pending_subtasks():
        next_task = state.get_next_ready_subtask()
        worker = route(next_task, workers)

        try:
            result = worker.execute(next_task, state.context)
            state.results.append(result)
            state.mark_completed(next_task)
        catch error:
            if retries_remaining(next_task):
                state.retry(next_task)
            else:
                state.mark_failed(next_task)

    // Phase 3: Aggregate results
    return LLM.synthesize(state.results)

When to Use

  • Complex tasks that naturally decompose into distinct, well-defined subtasks
  • When you have specialized agents for different domains (research, coding, analysis)
  • Workflows requiring deterministic execution order and dependency management
  • Systems where observability and debugging are important — the supervisor provides a clear control flow
  • When you need centralized error handling, retries, and quality validation

When NOT to Use

  • Simple tasks that a single agent can handle without decomposition
  • When the supervisor becomes a latency bottleneck in real-time systems
  • Tasks requiring emergent behavior, negotiation, or creative exploration
  • When workers need to communicate with each other directly and frequently
  • If the task decomposition is ambiguous and hard to define upfront

Architecture Overview

The Supervisor pattern establishes a hub-and-spoke architecture for multi-agent systems. A single supervisor agent acts as the central coordinator — it receives a user request, analyzes it, decomposes it into subtasks, assigns each subtask to an appropriate worker agent, collects and validates results, and synthesizes a final response.

This pattern mirrors organizational structures found in software engineering teams: a tech lead decomposes a feature into tickets and assigns them to developers with the appropriate expertise. The supervisor doesn't do the actual work; instead, it manages the workflow, handles dependencies between tasks, and ensures the final output is coherent and complete.

The key components of the pattern are:

  • Supervisor Agent: The orchestrator with a global view of the task. It maintains a task queue, tracks completion status, routes subtasks, and handles failures. It typically uses a more capable model to handle complex planning and decision-making.
  • Worker Agents: Specialized agents, each configured with a specific system prompt, toolset, and (optionally) a specialized model. Workers know nothing about each other — they receive a task, execute it, and return results to the supervisor.
  • Shared State: A message log or state object that the supervisor uses to track progress. In graph-based frameworks, this is typically an explicit state schema; in SDK-based approaches, it may be the conversation history itself.

Routing and Delegation Logic

The supervisor's most critical function is routing — deciding which worker to invoke for each subtask. There are several strategies for implementing this:

LLM-based routing: The supervisor uses the LLM itself to analyze the task and decide which worker is best suited. The supervisor's system prompt includes a description of each available worker and their capabilities. The LLM selects the worker by name or ID, and this selection is parsed and used to dispatch the subtask. This approach is flexible and handles novel task types well, but adds latency (one LLM call per routing decision) and can occasionally misroute.

Rule-based routing: A set of deterministic rules (keyword matching, regex, classifiers) determines which worker handles each subtask. This is faster and more predictable but less flexible. It works well when the task categories are well-defined and don't change frequently.

Hybrid routing: Combine a fast classifier for common task types with an LLM fallback for ambiguous cases. This gives you the speed of rule-based routing with the flexibility of LLM routing.

When implementing routing, the supervisor should also manage task dependencies. If subtask B depends on the result of subtask A, the supervisor must ensure A completes before dispatching B. Graph-based frameworks like LangGraph make these dependencies explicit through edge definitions, while SDK-based approaches typically handle them through sequential execution logic.

State Management and Error Handling

Robust state management is what separates production-grade supervisor implementations from prototypes. The supervisor must track:

  • Task registry: Which subtasks have been created, their status (pending, in-progress, completed, failed), and their dependencies.
  • Worker outputs: The results returned by each worker, stored in a structured format for aggregation.
  • Error state: Which tasks have failed, how many retries have been attempted, and whether fallback strategies should be invoked.

Error handling in the supervisor pattern requires particular attention because failures in one worker can cascade. Key strategies include:

  • Retry with backoff: If a worker fails (tool error, timeout, or low-quality output), the supervisor retries the subtask, potentially with a modified prompt or different parameters.
  • Fallback workers: If the primary worker for a task type fails repeatedly, route to an alternative worker or a general-purpose agent.
  • Graceful degradation: If a non-critical subtask fails, the supervisor can proceed with partial results and note the gap in the final output rather than failing the entire request.
  • Quality gates: The supervisor can validate worker outputs before accepting them — checking for format compliance, completeness, or running a lightweight verification step.

Implementation Example

In LangGraph, the supervisor pattern is implemented as a state graph with the supervisor as the entry node. The supervisor node produces a routing decision (which worker to call next), and conditional edges dispatch to the appropriate worker node. Each worker node processes its subtask and returns results to the supervisor, which then decides the next step. LangGraph's built-in state persistence means you can checkpoint the workflow, enabling human-in-the-loop review between steps.

In the OpenAI Agents SDK, the supervisor is implemented using the handoff mechanism. The supervisor agent is defined with handoff targets pointing to each worker agent. When the supervisor decides to delegate, it performs a handoff to the appropriate worker. The worker completes its task and returns control to the supervisor. This is cleaner than manual routing but gives you less control over the intermediate state.

In CrewAI, the supervisor maps to a "manager" agent that uses a hierarchical process. You define a Crew with process=Process.hierarchical and designate a manager_llm. CrewAI handles the routing automatically — the manager analyzes the tasks and delegates to crew members based on their role descriptions.

Supervisor vs. Peer Topologies

The supervisor pattern is not always the best choice. Understanding when a centralized orchestrator adds value versus when it becomes a bottleneck is essential:

FactorSupervisorPeer / Decentralized
Task structureWell-decomposable, clear subtasksEmergent, exploration-oriented
Coordination overheadLow — single point of controlHigher — agents must negotiate
Single point of failureYes — supervisor is criticalNo — more resilient
ScalabilityBottleneck at supervisorScales horizontally
DebuggingEasy — clear chain of controlHarder — distributed interactions
Best forWorkflows, pipelines, structured tasksCreative, debate, brainstorming

In general, prefer the supervisor pattern when you can clearly decompose the task into independent or sequentially dependent subtasks, when you need predictable execution order, and when debugging and observability are priorities. Consider peer-based approaches when the task requires negotiation, debate, or emergent solutions.

Explore Related Content