teachyou.ai academy
← All posts
AI Agentsmulti-agent systemsLLM orchestrationagent architectureproduction AI

Agent Orchestration Patterns: Supervisor, Swarm, and Pipeline

Pramod Dutta · Jul 9, 2026 · 15 min read

Agent orchestration is the layer that decides which agent runs next, what context it sees, and how its output gets merged back into the system. Get this layer wrong and you end up with agents that step on each other, burn tokens re-deriving context, or silently drop the one piece of information that mattered. Get it right and a multi-agent system feels less like a pile of prompts and more like a team with a working process. This article walks through the three patterns that cover almost every production agent system: supervisor, swarm, and pipeline, plus when to reach for each one.

Before picking a pattern, it helps to be honest about why you're using multiple agents at all. The three real reasons are: the task needs different tools or context windows for different subtasks, the task benefits from parallel exploration before converging on an answer, or the task has a natural handoff structure where one stage's output is the next stage's input. If none of those apply, a single well-prompted agent with a good toolset will usually beat a multi-agent system on cost, latency, and debuggability. Multi-agent orchestration adds coordination overhead, and that overhead is not free.

What agent orchestration actually solves

A single agent loop looks like: read state, call a tool, observe the result, decide the next action, repeat until done. That works well for tasks with a single coherent objective and a bounded set of tools. It breaks down in three situations.

First, context pollution. If an agent has to read a 50-page spec, write code against it, and then also review its own code for security issues, all three of those activities compete for the same context window. The review quality suffers because the model is still holding the implementation details active in a way that biases it toward confirming its own choices.

Second, tool sprawl. An agent with 40 tools available has a harder time picking the right one than an agent with 6. Splitting responsibilities across agents lets each one carry a smaller, more coherent toolset.

Third, parallelism. Some tasks (research, code search, candidate generation) benefit from doing several independent things at once and comparing results, rather than committing to one path early.

Orchestration patterns are just different answers to "how do multiple agents share work and merge results." The three below map cleanly onto the three situations above.

Pattern 1: Supervisor (orchestrator-worker)

The supervisor pattern has one agent that owns the plan and delegates subtasks to worker agents, then integrates their results. The supervisor never does the leaf-level work itself; it decomposes, dispatches, and synthesizes.

This is the pattern behind most "coding agent that spawns subagents" systems, and it is what most people mean when they say "multi-agent system" without further qualification.

Structure:

User request
   |
Supervisor agent (plans, delegates, synthesizes)
   |-- Worker A (e.g. code search)
   |-- Worker B (e.g. test runner)
   |-- Worker C (e.g. doc writer)
   |
Supervisor merges results -> final response

The key design decision is what the supervisor passes down and what comes back up. Workers should get a self-contained brief: the specific subtask, any constraints, and enough background that they do not need to re-derive intent. Workers should NOT get the full conversation history by default, because that reintroduces the context pollution problem you were trying to solve.

A minimal supervisor loop in pseudocode:

def supervisor(user_request):
    plan = plan_subtasks(user_request)
    results = []
    for subtask in plan:
        worker_output = dispatch_worker(
            role=subtask.role,
            brief=subtask.brief,
            tools=subtask.tools,
        )
        results.append(worker_output)
    return synthesize(user_request, results)

Two things make or break this pattern in practice.

Brief quality. A supervisor that hands off "fix the bug" produces worse results than one that hands off "the login endpoint at auth/handler.py returns 500 when the email field has trailing whitespace; the fix is almost certainly a trim before validation; write the fix and a regression test." The supervisor's real job is compressing everything it knows into a brief the worker can act on without asking questions back. Treat brief-writing as the deliverable, not an afterthought.

Sequential vs parallel dispatch. If subtasks are independent, dispatch them in parallel and merge at the end. If subtask B needs subtask A's output, that is not actually a supervisor pattern for that pair anymore, it is a pipeline (see below) nested inside the supervisor's plan. Most real systems are a supervisor at the top with a mix of parallel and sequential dispatch underneath, decided dynamically based on dependencies in the plan.

When to use it: task decomposition is knowable up front or discoverable by the supervisor, subtasks are mostly independent or have shallow dependencies, and you want one place responsible for the final answer's coherence. This is the right default for most agentic coding tools, research assistants, and customer-support triage systems.

Failure modes to watch for: the supervisor over-delegates trivial work (dispatching a worker to answer something the supervisor already knows wastes a full round trip), or under-specifies the brief and workers return inconsistent formats that are expensive to reconcile. Put a schema on worker outputs. Even a loose one ("return findings as a bullet list with file paths") saves the supervisor from parsing free text.

Pattern 2: Swarm (peer-to-peer handoff)

In a swarm, there is no fixed supervisor. Agents hand control directly to each other based on the current state of the task, and any agent can decide the next agent is a better fit for what comes next. The classic example is a customer service system where a general intake agent hands off to a billing agent, which might hand off to a refunds agent, which might hand back to intake if the customer's question changes topic.

Structure:

Agent A (intake) --handoff--> Agent B (billing)
                                  |
                             --handoff--> Agent C (refunds)
                                  |
                             --handoff back--> Agent A

The defining trait of a swarm is that control transfer is a first-class action available to every agent, not something decided by a central planner. Each agent evaluates: can I handle what's needed right now, or should I pass to someone better suited? This makes swarms a good fit for conversational systems where topic and intent shift mid-interaction, and a poor fit for tasks with a knowable upfront structure (use supervisor for those, it is cheaper to reason about).

A simplified handoff mechanism:

def run_swarm(initial_agent, conversation_state):
    current_agent = initial_agent
    while not conversation_state.done:
        result = current_agent.step(conversation_state)
        conversation_state.update(result)
        if result.handoff_to:
            current_agent = get_agent(result.handoff_to)
    return conversation_state.final_response

Each agent in a swarm needs its own scoped instructions, tools, and a shared conversation state that persists across handoffs. What gets shared is the important design question. If every agent shares the full conversation, you regain coherence but pay a growing context cost per turn. If agents only see a compacted state object, you save tokens but risk losing nuance from earlier in the conversation. Most production swarm implementations use a shared state object with structured fields (customer id, issue category, resolution status) plus a rolling summary of the conversation, rather than raw transcript.

Swarms are appealing because they mirror how human teams actually work: nobody plans the whole interaction upfront, people just recognize when a colleague is better positioned to help and hand off. But that flexibility is also the risk. Without a supervisor holding the throughline, swarms can loop (agent A hands to B, B hands back to A, repeat) or lose the original goal across several handoffs. Two guardrails matter here.

Handoff budgets. Cap the number of handoffs per conversation and force a resolution or escalation to a human once the cap is hit. Unbounded handoff chains are the single most common swarm failure in production.

A retained goal statement. Even without a central supervisor, keep the original user request as an immutable field in the shared state that every agent can read but not silently drift away from. This is cheap insurance against topic creep across handoffs.

When to use it: interactive, multi-turn systems where the right specialist depends on how the conversation unfolds and cannot be fully planned at the start. Support routing, sales qualification bots, and multi-domain assistants are the common cases. If your task is a single batch job with a known shape, a swarm is the wrong tool; use a supervisor or pipeline instead.

Pattern 3: Pipeline (sequential stages)

A pipeline is the simplest pattern and the one people underrate. Agents run in a fixed sequence, each stage consuming the previous stage's output and producing input for the next. There is no dynamic routing and no delegation decision at runtime, the order is decided at design time.

Structure:

Input -> Agent 1 (extract) -> Agent 2 (transform) -> Agent 3 (validate) -> Output

This looks almost too plain to call "orchestration," but it is the backbone of most reliable production agent systems, because fixed structure is easier to test, cache, and debug than dynamic delegation. If stage 2 keeps failing, you know exactly where to look. If you need to add a stage, you add it at a known point in a known order rather than reasoning about how it changes a supervisor's dynamic plan.

def run_pipeline(input_data, stages):
    state = input_data
    for stage in stages:
        state = stage.run(state)
        if state.failed:
            return handle_failure(stage, state)
    return state

The design decisions that matter in a pipeline are different from the other two patterns because there is no delegation logic to get right. Instead, focus on:

Stage boundaries. Each stage should have one clear responsibility and a well-defined output contract. A stage that both extracts and validates is doing two jobs, and when it fails you cannot tell which job failed without extra logging. Split it.

Failure handling between stages. Decide up front whether a mid-pipeline failure should halt the whole pipeline, retry the failed stage, or route to a fallback stage. Silent pass-through of a failed stage's bad output into the next stage is the most common pipeline bug; it produces a plausible-looking final answer built on a broken intermediate step.

Checkpointing. Because stages are sequential and deterministic in order, you can persist state after each stage and resume from the last successful one instead of re-running the whole pipeline on failure. This matters a lot for pipelines with expensive stages (large document processing, multi-minute code generation) where re-running from scratch after a late failure is wasteful.

A concrete example: a document-to-course-content pipeline might run an extraction agent (pull structured facts from a source document), a drafting agent (turn facts into prose), and a fact-check agent (verify every claim in the draft traces back to the extraction stage's output, not to the drafting agent's own generation). That last stage only works because the pipeline kept the extraction output around as a reference; a swarm or supervisor pattern would need to explicitly thread that same data through, and it is easy to forget.

When to use it: the task has a genuinely sequential structure known at design time, where stage N's output is well-defined input for stage N+1. ETL-style content pipelines, multi-step code generation (plan, implement, test, review), and document processing are the classic cases. Do not force a pipeline onto a task with real branching logic, you will end up bolting a supervisor's decision-making onto a pattern that was not built for it, and the result is worse than just using a supervisor from the start.

Comparing the three

Here is the practical comparison that should drive the choice.

Supervisor fits when you have a single point of accountability for the final answer, subtasks are mostly independent, and you can afford one extra planning step before work starts. Cost profile: moderate, one planning call plus N worker calls. Debuggability: good, because every dispatch and merge goes through one place you can log.

Swarm fits when the right next step depends on runtime state that cannot be known in advance, especially in multi-turn conversations. Cost profile: variable and can spiral if handoffs are unbounded. Debuggability: hardest of the three, because control flow is decided by the agents themselves at runtime rather than fixed in code; you need good handoff logging to reconstruct what happened after the fact.

Pipeline fits when the task has a known sequential shape. Cost profile: predictable, N stages run N times, no dynamic branching to inflate that. Debuggability: best of the three, since the execution order is fixed and each stage's input/output contract can be tested in isolation.

A useful rule of thumb: start with a pipeline if you can. If a stage in that pipeline turns out to need dynamic decomposition into independent subtasks, replace just that stage with a supervisor. If the whole system needs to route based on evolving conversational state rather than a fixed document flow, that's when a swarm earns its complexity. Reaching for a swarm as the default, before you've established that runtime routing is actually necessary, is the most common orchestration mistake: it is the most flexible pattern and also the hardest to reason about, test, and keep bounded.

Combining patterns

Production systems rarely use exactly one pattern in isolation. A common real shape: a top-level supervisor decomposes a request into stages, one of those stages is internally a pipeline (extract, transform, validate), and a different stage is a swarm-style routing step (which specialist agent handles this particular sub-request). Nesting is fine as long as each layer has a single clear responsibility. What causes trouble is mixing responsibilities within one layer, for example a supervisor that also tries to do swarm-style dynamic handoffs among its own workers instead of delegating that decision to a sub-swarm it dispatches to.

When you nest patterns, keep the interface between layers narrow. The outer supervisor should not need to know that one of its workers is internally a three-stage pipeline; it should just see that worker's input and output contract. This is the same interface discipline that makes microservices maintainable, applied to agents instead of services.

Practical implementation notes

A few things matter across all three patterns regardless of which one you pick.

Context isolation is the main lever, not agent count. The value of orchestration comes from giving each agent a focused context, not from having more agents. A supervisor with three tightly-scoped workers usually outperforms one with eight loosely-scoped ones, because the eight-worker version reintroduces the tool-sprawl and context-pollution problems you were trying to avoid.

Structured outputs between agents beat free text. Whether it is a supervisor merging worker results, a pipeline stage feeding the next, or a swarm agent handing off state, define the schema of what crosses the boundary. Free-text handoffs are fine for a demo and expensive in production once you need to debug why a merge produced garbage.

Cost scales with the pattern's branching factor, not just token count per call. A supervisor dispatching 5 parallel workers multiplies your per-request cost by roughly 5, even if each worker call is cheap. Before adding a worker, ask whether the task genuinely needs a separate context, or whether it is scope creep dressed up as delegation.

Log the orchestration decisions, not just the model outputs. For a supervisor, log the plan and dispatch decisions. For a swarm, log every handoff and the reason for it. For a pipeline, log stage entry and exit state. When something goes wrong in a multi-agent system, the orchestration trace is usually more diagnostic than the individual agent transcripts, because the bug is often in how work was split or merged, not in what any single agent said.

FAQ

Is a swarm the same thing as a multi-agent debate? No. Debate patterns have multiple agents produce independent answers to the same question and then reconcile disagreement, usually with a judge step. A swarm has agents hand off a single unfolding task to whichever specialist is best suited next. They can be combined (a swarm agent could internally run a debate to decide something), but they solve different problems.

Do I need a framework to build these, or can I do it with raw API calls? All three patterns can be built with plain function calls and conditional logic around a model API; none of them requires a specific framework. Frameworks mostly save you boilerplate around state passing, tool schemas, and handoff bookkeeping. Start without one until the boilerplate becomes genuinely painful, so you understand what the framework is doing for you when you do adopt it.

How many workers is too many for a supervisor? There is no fixed number, but past 5 to 7 parallel workers on a single request, coordination and merge cost usually outweighs the benefit, and you should ask whether some of those workers should be collapsed into fewer, broader-scoped agents instead. Wide fan-out sounds efficient but the supervisor still has to read and reconcile everything that comes back, and that reconciliation step does not get cheaper just because the fan-out was parallel.

Which pattern is cheapest to run? Pipeline, because its cost is fixed and predictable: N stages, N calls, no dynamic branching. Supervisor is next, with cost proportional to the number of dispatched workers. Swarm is the least predictable because handoff count is decided at runtime and can grow if you do not cap it.

Can a single agent switch patterns mid-task? Yes, and this is common in mature systems. An agent operating inside a pipeline stage might, on discovering the subtask has independent parts, spin up its own mini-supervisor to parallelize just that stage. Treat the three patterns as tools you reach for locally at each decision point, not as a single global architecture you commit to for the whole system.