TL;DR:
- The OpenAI Agents SDK is a Python-first framework for building multi-agent pipelines with first-class support for handoffs between agents
- Guardrails let you validate agent inputs and outputs without cluttering your main agent logic
- Built-in tracing integrates with the OpenAI dashboard — no additional observability setup needed
OpenAI’s Agents SDK arrived in early 2026 as the production-grade successor to the experimental Swarm library. Where the Assistants API focuses on stateful, server-managed threads, the Agents SDK is code-first and gives you full control over orchestration logic in Python. It builds on top of the Responses API and is designed for real multi-agent workflows — not just a single model with tools.
Core Concepts
The SDK has four main building blocks: Agents, Handoffs, Guardrails, and Runners.
Agents
An Agent is defined by its instructions, the tools it can call, and the other agents it can hand off to:
from agents import Agent, tool
@tool
def search_docs(query: str) -> str:
"""Search the internal knowledge base."""
return knowledge_base.search(query)
triage_agent = Agent(
name="Triage",
instructions="Classify the user's request and route to the right specialist.",
handoffs=["billing_agent", "technical_agent"],
)
technical_agent = Agent(
name="Technical Support",
instructions="Resolve technical issues. Use search_docs to look up solutions.",
tools=[search_docs],
)
Instructions support dynamic values via a callable, which is useful when you need to inject runtime context (current user, session state) into the system prompt.
Handoffs
Handoffs are the key innovation over previous approaches. Rather than a parent orchestrator agent explicitly calling sub-agents as tools, any agent can transfer control directly to another agent by including it in its handoffs list. The SDK handles the mechanics — the receiving agent picks up with full conversation history.
from agents import Runner
async def main():
result = await Runner.run(
triage_agent,
input="My invoice shows the wrong amount and I can't log in.",
)
print(result.final_output)
When the triage agent decides the issue is billing-related, it hands off to billing_agent. If billing determines the login issue is technical, it hands off to technical_agent. Each handoff preserves the conversation context.
You can also force a specific agent as the final responder using Runner.run(..., terminal_agent=billing_agent), which prevents infinite handoff loops.
Guardrails
Guardrails are validation hooks that run before input reaches an agent (input guardrails) or before output leaves one (output guardrails). They’re designed to separate policy logic from agent logic:
from agents import InputGuardrail, GuardrailFunctionOutput
from pydantic import BaseModel
class SafetyCheck(BaseModel):
is_safe: bool
reason: str
async def content_safety_check(ctx, agent, input):
result = await Runner.run(
safety_classifier,
input=input,
context=ctx.context,
)
output = result.final_output_as(SafetyCheck)
return GuardrailFunctionOutput(
output_info=output,
tripwire_triggered=not output.is_safe,
)
protected_agent = Agent(
name="Customer Service",
instructions="Help customers with their orders.",
input_guardrails=[InputGuardrail(guardrail_function=content_safety_check)],
)
If a guardrail trips, the SDK raises a GuardrailTripwireTriggered exception that you catch and handle in your application layer. This keeps your agents focused on their task rather than defensive checks.
Context
The RunContextWrapper carries arbitrary context through an entire agent run, including across handoffs. Define a typed context class and every agent and tool in the pipeline gets access to it:
from dataclasses import dataclass
from agents import RunContextWrapper
@dataclass
class UserContext:
user_id: str
subscription_tier: str
locale: str
@tool
def get_account_details(ctx: RunContextWrapper[UserContext]) -> str:
user = ctx.context
return fetch_account(user.user_id)
This replaces the pattern of threading user state through tool arguments or hiding it in system prompt injections.
Tracing
Every Runner.run() call automatically creates a trace visible in the OpenAI platform dashboard. You can see each agent step, tool call, handoff event, and guardrail evaluation — without any additional instrumentation. For custom trace attributes, wrap operations with with trace("my operation"):.
If you’re running outside OpenAI models (the SDK supports third-party models via a LiteLLM bridge), you can export traces to any OpenTelemetry-compatible backend by setting set_trace_processors([...]).
When to Use It vs Alternatives
The OpenAI Agents SDK is the right choice if:
- You’re already using OpenAI models and want tight dashboard integration
- Your primary orchestration pattern is handoffs between specialist agents
- You want guardrails as a first-class feature, not bolted on
If you need stateful long-running workflows with durable execution guarantees, LangGraph or Temporal are better fits (the Agents SDK holds state in-process and doesn’t survive restarts). If you need deep tool integration across 100+ SaaS apps, Composio adds a useful layer on top.
For new OpenAI-stack projects starting in 2026, the Agents SDK has largely superseded both Swarm and the Assistants API for complex agent work. The Assistants API still makes sense for simpler single-agent deployments where you want server-managed thread storage.
Getting Started
pip install openai-agents
The official cookbook has working examples for customer service bots, research pipelines, and code review agents. The examples/multi_agent directory is the best starting point for understanding handoff patterns in practice.