Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/openai/openai-cookbook/llms.txt

Use this file to discover all available pages before exploring further.

When a single agent grows too large — too many tools, too many responsibilities, too many edge cases to handle gracefully — the right move is to split it up. The orchestrator pattern solves this by introducing a coordinator agent whose only job is to understand intent and delegate work to specialist agents that each excel at a narrow task. This guide walks through the core ideas behind routines and handoffs, shows how to implement an orchestrator with the OpenAI Agents SDK, and covers when to use this pattern versus keeping everything in a single agent.

What is the orchestrator pattern?

An orchestrator is an agent that does not directly answer user requests. Instead, it reads the incoming message, determines which specialist is best suited to handle it, and hands off the conversation to that agent. The specialist then takes over, uses its own tools and instructions, and produces a response. This mirrors how a well-run support team works: a triage agent at the front desk routes calls to billing, technical support, or account management — each with their own expertise and scripts.

Orchestrator

Reads intent, applies routing logic, and delegates via handoffs. Does not answer directly.

Specialist agents

Handle a single domain — billing, technical support, scheduling — with focused tools and instructions.

When to use orchestration

Not every use case needs multiple agents. A single, well-prompted agent with a good set of tools handles most tasks effectively. Reach for orchestration when:
  • You have distinct domains that require different tools, instructions, or tone (e.g., legal vs. customer support).
  • The number of tools on a single agent exceeds ~10–15, causing performance to degrade.
  • You want independent scalability — different agents can use different models or be updated without touching the others.
  • Compliance or auditing requires clear attribution of which agent produced a given response.
If your tasks share the same tools and context, a single agent with a detailed prompt is almost always simpler and cheaper.

Core concepts

Routines

A routine is a set of natural-language instructions combined with the tools an agent needs to carry them out. Think of it as a script: step-by-step instructions the LLM follows, including conditionals and branching, to complete a workflow. Unlike a rigid state machine, the LLM interprets these instructions with some flexibility, which lets it handle edge cases without getting stuck.

Handoffs

A handoff is the mechanism by which control transfers from one agent to another. When the triage agent decides a request belongs to the billing specialist, it hands off — passing along the conversation history and any relevant context. The receiving agent then continues as if it had been there from the start.

Building a triage agent

The example below creates a triage agent that routes requests to a billing agent or a technical agent. Install the SDK first:
pip install openai-agents
Then define your agents:
from agents import Agent, Runner

billing_agent = Agent(
    name="Billing Agent",
    instructions="Handle billing and subscription questions."
)

technical_agent = Agent(
    name="Technical Agent",
    instructions="Handle technical support questions."
)

triage_agent = Agent(
    name="Triage Agent",
    instructions="Route the user request to the appropriate specialist agent.",
    handoffs=[billing_agent, technical_agent]
)

result = Runner.run_sync(triage_agent, "I need help with my invoice")
print(result.final_output)
Pass agent objects (not strings) to handoffs. The SDK resolves the handoff automatically based on the triage agent’s decision.

How handoffs work step by step

1

User sends a message

The runner delivers the message to the triage agent along with any prior conversation history.
2

Triage agent decides

The triage agent reads the message and determines which specialist is the best fit based on its instructions.
3

Handoff is triggered

The triage agent calls a special handoff tool that transfers control — and the full conversation context — to the selected specialist.
4

Specialist responds

The specialist agent takes over, uses its own tools if needed, and generates the final response returned to the user.

Shared context between agents

Context that the triage agent collects — such as a user’s account ID, language preference, or the detected intent — can be passed to specialist agents via a shared context object. Define a dataclass for the shared state and pass it when calling the runner:
from dataclasses import dataclass
from agents import Agent, Runner, RunContextWrapper

@dataclass
class SupportContext:
    user_id: str
    account_tier: str

billing_agent = Agent(
    name="Billing Agent",
    instructions="Handle billing questions. The user's account tier is available in context."
)

triage_agent = Agent(
    name="Triage Agent",
    instructions="Route the user request to the appropriate specialist.",
    handoffs=[billing_agent]
)

ctx = SupportContext(user_id="usr_123", account_tier="pro")
result = Runner.run_sync(triage_agent, "What's on my latest invoice?", context=ctx)
print(result.final_output)
Each specialist agent receives the same context object. Use it to carry authenticated user data, session metadata, or configuration flags — anything that should be available across the full workflow without being re-fetched at every step.

Tracing agent runs

The Agents SDK records a full trace of every agent run: which agents executed, what tools were called, what was handed off, and what the final output was. This is invaluable for debugging routing decisions and auditing multi-step workflows.
from agents import Agent, Runner, trace

async def run_with_trace(user_input: str):
    with trace("triage-workflow"):
        result = await Runner.run(triage_agent, user_input)
    return result.final_output

import asyncio
print(asyncio.run(run_with_trace("Can you reset my password?")))
The trace context manager records the full span — which agents ran, what tools were called, and what was handed off. In production, traces are available in the OpenAI dashboard, where each span links to the agent and tool that produced it.
Use tracing to verify your triage agent is routing correctly before going to production. Look for unexpected handoffs or cases where the triage agent answers directly when it should have delegated.

Choosing models per agent

Different agents in the same workflow can use different models. Use a capable model like gpt-4o for the triage agent — where reasoning quality matters most — and a faster, cheaper model for high-volume specialist tasks:
from agents import Agent

triage_agent = Agent(
    name="Triage Agent",
    instructions="Route requests to the right specialist.",
    model="gpt-4o",
    handoffs=[billing_agent, technical_agent]
)

billing_agent = Agent(
    name="Billing Agent",
    instructions="Handle billing and subscription questions.",
    model="gpt-4o-mini"
)

Extending the pattern

The triage-to-specialist pattern composes cleanly. A specialist can itself be an orchestrator for a deeper workflow, or you can add a synthesis agent at the end that combines outputs from multiple specialists into a single response. The key is keeping each agent’s instructions focused and its tool set minimal.

Parallel agents

Run multiple agents simultaneously to reduce latency on independent tasks.

Voice agents

Add real-time voice I/O to any agent workflow using the Realtime API.

Further reading

Build docs developers (and LLMs) love