Fasttrack· 09· 25 min

Agent Orchestration Patterns

What you'll learn
  • Know the four core agent orchestration patterns
  • Choose the right pattern for your use case
  • Compose agents with plain Python — no framework required

One agent rarely covers a real production system. A customer support system might need one agent for billing, another for technical support, and a third for account management. A research pipeline might need a researcher agent feeding into a writer agent. These four patterns cover the vast majority of multi-agent architectures you will encounter.

4
Orchestration patterns
Single, Sequential, Parallel, Router
1
Language needed
Plain Python — no framework required
3
Lines to compose agents
result = agent_b.invoke(agent_a.invoke(...))
Single agent with multiple tools diagram
Click to zoom
Pattern 1: Single agent with multiple tools handles most simple use cases

Pattern 1 — Single Agent

The simplest pattern: one agent, many tools. The agent decides which tools to call based on the user's question. Handles most use cases that do not require specialist knowledge or parallel execution. Start here and only add complexity when you hit a real limitation.

pattern_single.py
agent = create_react_agent(
    model=model,
    tools=[search_web, query_database, send_email, read_file],
)
# The agent autonomously decides which tools to call
result = agent.invoke({'messages': [HumanMessage(content='Summarise today's sales and email the report to the team.')]})
Sequential agent pipeline: Agent A output feeds into Agent B
Click to zoom
Pattern 2: Agent A feeds its output into Agent B

Pattern 2 — Sequential

Two or more agents run in sequence: the output of the first becomes the input of the second. Classic use case: a researcher agent gathers information, then a writer agent turns it into a polished document. Each agent has a clear, focused role.

pattern_sequential.py
from langchain_core.messages import HumanMessage

researcher = create_react_agent(model=model, tools=[search_web, read_arxiv])
writer = create_react_agent(model=writer_model, tools=[check_grammar])

# Step 1: Researcher gathers facts
research_result = researcher.invoke({
    'messages': [HumanMessage(content='Research the latest advances in quantum computing.')]
})
research_text = research_result['messages'][-1].content

# Step 2: Writer turns facts into an article
final_result = writer.invoke({
    'messages': [HumanMessage(
        content=f'Write a blog post based on this research:\n\n{research_text}'
    )]
})
print(final_result['messages'][-1].content)
Parallel agent pattern: fan-out to multiple agents, merge results
Click to zoom
Pattern 3: Fan-out to parallel agents, merge results for lower latency

Pattern 3 — Parallel

Run multiple independent agents concurrently with asyncio.gather() and merge their outputs. Use this when tasks are independent and latency matters — three agents running in parallel take the same time as one, not three times longer.

pattern_parallel.py
import asyncio
from langchain_core.messages import HumanMessage

weather_agent = create_react_agent(model=model, tools=[get_weather])
news_agent = create_react_agent(model=model, tools=[search_news])
stocks_agent = create_react_agent(model=model, tools=[get_stock_price])

async def morning_briefing(city: str, topic: str, stock: str) -> str:
    # All three run in parallel — total time = max(weather, news, stocks)
    weather, news, stocks = await asyncio.gather(
        weather_agent.ainvoke({'messages': [HumanMessage(content=f'Weather in {city}?')]}),
        news_agent.ainvoke({'messages': [HumanMessage(content=f'Top news about {topic}?')]}),
        stocks_agent.ainvoke({'messages': [HumanMessage(content=f'Price of {stock}?')]}),
    )
    return '\n\n'.join([
        weather['messages'][-1].content,
        news['messages'][-1].content,
        stocks['messages'][-1].content,
    ])

result = asyncio.run(morning_briefing('London', 'AI', 'NVDA'))
print(result)
Router pattern: supervisor agent dispatches to specialist sub-agents
Click to zoom
Pattern 4: Supervisor dispatches to specialist sub-agents based on query type

Pattern 4 — Router / Supervisor

A supervisor agent classifies the incoming request and routes it to the appropriate specialist. The specialist agents are wrapped as @tool functions — the supervisor calls them like any other tool. This pattern scales cleanly to many specialists without growing the supervisor's prompt.

pattern_router.py
from langchain_core.tools import tool

billing_agent = create_react_agent(model=model, tools=[get_invoice, process_refund])
tech_agent = create_react_agent(model=model, tools=[check_system_status, run_diagnostics])

@tool
def route_to_billing(query: str) -> str:
    """Handle billing, payment, and invoice questions."""
    result = billing_agent.invoke({'messages': [HumanMessage(content=query)]})
    return result['messages'][-1].content

@tool
def route_to_tech_support(query: str) -> str:
    """Handle technical issues, bugs, and system problems."""
    result = tech_agent.invoke({'messages': [HumanMessage(content=query)]})
    return result['messages'][-1].content

# Supervisor routes to the right specialist
supervisor = create_react_agent(
    model=model,
    tools=[route_to_billing, route_to_tech_support],
    prompt='Route customer queries to the appropriate specialist.',
)

Choosing the right pattern

Single
one agent, many tools
  • Simple chatbots and assistants
  • Tasks that fit in one context window
  • Start here — add patterns only when needed
Sequential
pipeline of specialists
  • Research → Write → Review pipelines
  • Data transformation workflows
  • Output of A must feed input of B
Parallel
concurrent fan-out
  • Independent tasks with latency budget
  • Dashboard aggregation from multiple sources
  • Tasks must not depend on each other
Router
supervisor + specialists
  • Many specialist domains to handle
  • Customer support with multiple teams
  • Clean separation of specialist prompts
Agents are just callables — orchestrate them with normal Python, not a framework. asyncio.gather() for parallelism, a plain function call for sequencing, a @tool wrapper for routing. The patterns above are all pure Python. No special orchestration library needed.
Knowledge Check
When should you choose the parallel pattern over the sequential pattern?
Recap — what you just learned
  • Four patterns cover almost every multi-agent architecture: Single, Sequential, Parallel, Router
  • Start with Single and add patterns only when you hit a real scaling or complexity limit
  • Parallel uses asyncio.gather() — tasks must be independent of each other
  • Router wraps specialist agents as @tool functions for a clean supervisor interface
Next up: 10 — Evals & Prompt Engineering