AI/TLDR

What Is the OpenAI Agents SDK? Handoffs and Guardrails Explained

Learn the three primitives the OpenAI Agents SDK is built on — agents, handoffs, and guardrails — and how they snap together into a working app.

BEGINNER11 MIN READUPDATED 2026-06-12

In plain English

The OpenAI Agents SDK is an open-source Python (and TypeScript) library that gives you a tiny, production-ready framework for wiring AI agents together. Released by OpenAI in March 2025 as the official successor to their experimental Swarm project, it distils everything a multi-agent app needs into three primitives: agents, handoffs, and guardrails. That's genuinely it — the whole framework fits in a mental model you can hold in your head.

A good analogy is a well-run customer-service call centre. The agents are the specialist staff: a billing expert, a technical support rep, an account manager. The handoff is the moment one rep says "Let me transfer you to someone who handles that" and the caller lands with the right person, full context in hand. The guardrails are the compliance rules posted on the wall — things no rep is allowed to say or agree to, no matter what the caller asks. The SDK models all three of these with actual Python objects and a runtime that manages the execution flow.

Why it matters

Building a useful AI product with a single agent hits a ceiling fast. A single context window can only hold so much. A single set of instructions can't cover every domain well. And a single agent with every tool is harder to test, reason about, and secure. The answer is to split the work across specialised agents — but then you immediately need to solve routing, context passing, and safety.

Before the Agents SDK, those problems had no standard solution. Developers glued agents together with bespoke orchestration code: manual if/else routing, ad-hoc context copying between API calls, and safety checks bolted on wherever they remembered. The Agents SDK is the case against rebuilding all of that by hand, because it makes routing (handoffs) and safety (guardrails) first-class objects in the framework rather than an afterthought in your application code.

Who it's designed for

  • Developers building on OpenAI models who need more than a single chat loop — routing, specialisation, validation.
  • Teams migrating from Swarm who want the same lightweight multi-agent philosophy with production-grade primitives.
  • Beginners who want to ship a working multi-agent app quickly and understand the architecture clearly — the SDK's surface area is deliberately small.
  • Builders adding guardrails to an existing agentic system — the SDK's tripwire mechanism snaps on top of any agent without rewriting its logic.

How it works

The SDK's runtime is a Runner. You call Runner.run(agent, input) (or the synchronous Runner.run_sync), and the Runner takes over: it calls the model, executes tool calls the model requests, feeds results back, follows any handoff the agent decides to make, and stops when the active agent produces a final text response. You get back a RunResult with the full conversation history.

Primitive 1 — Agent

An Agent is a dataclass wrapping a model configuration. At minimum it needs a name and instructions. You can give it tools (plain Python functions decorated with @function_tool), a list of other agents it's allowed to handoff_to, and input_guardrails / output_guardrails for safety checks. That's the full API surface for defining an agent.

Minimal agentpython
from agents import Agent, Runner

billing_agent = Agent(
    name="Billing Agent",
    instructions="You handle billing questions. Be concise and accurate.",
    model="gpt-4o",
)

result = Runner.run_sync(billing_agent, "What is my current balance?")
print(result.final_output)

Primitive 2 — Handoff

A handoff lets one agent transfer control to another. You list the target agents in the source agent's handoffs parameter. The model then decides at runtime whether to hand off — it calls a special handoff tool, and the Runner switches the active agent, passing the full conversation history to the new one. The new agent continues as if it had been there from the start.

Primitive 3 — Guardrail

A guardrail is a function that checks the input to (or output from) an agent and returns a GuardrailFunctionOutput. That object has two fields: output_info (any data you want to attach) and tripwire_triggered (a boolean). If tripwire_triggered is True, the Runner immediately raises an exception — InputGuardrailTripwireTriggered or OutputGuardrailTripwireTriggered — and your code can catch it and respond appropriately rather than letting the agent continue.

Building a multi-agent app

Here's a complete example that wires the three primitives into a customer-support router. A triage agent decides which specialist to hand off to; an input guardrail blocks off-topic messages before any model call completes.

Installbash
pip install openai-agents   # Python 3.10+
export OPENAI_API_KEY=sk-...
multi_agent_support.pypython
import asyncio
from agents import (
    Agent,
    Runner,
    InputGuardrail,
    GuardrailFunctionOutput,
    RunContextWrapper,
)
from pydantic import BaseModel


# --- Guardrail ---
class TopicCheck(BaseModel):
    is_off_topic: bool
    reason: str


guardrail_agent = Agent(
    name="Topic Guardrail",
    instructions="Decide if the message is off-topic (not about billing or support).",
    output_type=TopicCheck,
)


async def check_topic(
    ctx: RunContextWrapper, agent: Agent, input: str
) -> GuardrailFunctionOutput:
    result = await Runner.run(guardrail_agent, input, context=ctx.context)
    check: TopicCheck = result.final_output
    return GuardrailFunctionOutput(
        output_info=check,
        tripwire_triggered=check.is_off_topic,
    )


# --- Specialist agents ---
billing_agent = Agent(
    name="Billing Agent",
    instructions="Handle billing and payment questions accurately.",
)

technical_agent = Agent(
    name="Technical Support Agent",
    instructions="Help users troubleshoot technical problems step by step.",
)

# --- Triage agent with handoffs and guardrail ---
triage_agent = Agent(
    name="Triage Agent",
    instructions=(
        "Route to Billing Agent for payment/invoice questions, "
        "or Technical Support Agent for technical problems."
    ),
    handoffs=[billing_agent, technical_agent],
    input_guardrails=[InputGuardrail(guardrail_function=check_topic)],
)


async def main():
    result = await Runner.run(triage_agent, "My payment failed last week.")
    print(result.final_output)


asyncio.run(main())

When you run this, the triage agent sees a billing question, calls the handoff tool for billing_agent, and the Runner transparently switches context. The input guardrail fires in parallel — if the user had typed something unrelated, the tripwire would trigger and you'd catch InputGuardrailTripwireTriggered before the billing agent ever touched the message.

Tracing and observability

Every Runner.run call automatically produces a trace: a structured record of every model call, tool invocation, handoff, and guardrail check. Traces are uploaded to the OpenAI platform dashboard by default, giving you a visual replay of exactly what happened during a run. This is built in — you get it for free without instrumenting your code.

The tracing system also has an open processor interface. Third-party integrations (Weights & Biases, Langfuse, LangSmith, Arize Phoenix, and others) can hook in via custom trace processors, so you're not locked into the OpenAI dashboard. TypeScript support arrived in June 2025, and the TypeScript SDK (openai/openai-agents-js) mirrors all the same primitives and tracing features.

FeaturePython SDKTypeScript SDK
Packageopenai-agents (pip)@openai/agents (npm)
Agents + toolsYesYes
HandoffsYesYes
GuardrailsYesYes
Built-in tracingYesYes
Voice / RealtimeAgentYesYes
Available sinceMarch 2025June 2025

Going deeper

Once the three primitives are comfortable, there are several directions worth exploring for production use.

Structured outputs

Set output_type on an Agent to any Pydantic model and the SDK instructs the model to produce JSON that matches that schema — then parses and validates it for you. This is essential for guardrail agents (as shown above) and for any agent whose output needs to be consumed programmatically rather than shown to a user.

Dynamic instructions and context

Agent instructions can be a callable instead of a plain string. The callable receives a RunContext at execution time, so the agent's system prompt can include the current user's name, their subscription tier, the time of day, or any other runtime data — without recreating the agent object for each request. This is the idiomatic way to personalise agents without losing the benefits of reusable, stateless agent definitions.

Tool guardrails for mid-chain safety

Input guardrails only fire for the first agent in a handoff chain; output guardrails only fire for the last. If you need a safety check on a specific tool call — say, blocking a database write above a certain row count — use tool guardrails instead. These attach directly to a @function_tool and fire every time that specific function is called, regardless of which agent in the chain invoked it.

MCP server integration

The SDK has native support for the Model Context Protocol (MCP). Pass MCP server configs to a Runner call and the agents in that run can call tools exposed by any MCP-compatible server — databases, browsers, internal APIs — without you writing tool wrappers. This is how you connect the SDK's orchestration layer to your broader tool ecosystem.

The April 2026 evolution

In April 2026, OpenAI shipped a significant update to the Agents SDK: a sandboxing primitive for safely executing untrusted code inside agents, and a long-horizon harness that checkpoints agent state across turns — enabling tasks that span hours or days without losing context. If you're building agents that need to run long autonomous tasks rather than single-turn workflows, the long-horizon harness is the current frontier to explore.

FAQ

What is the OpenAI Agents SDK?

It's an open-source Python and TypeScript library from OpenAI (released March 2025) for building multi-agent applications. It provides three core primitives — agents (LLMs with instructions and tools), handoffs (routing between agents), and guardrails (input/output safety checks) — plus a Runner that manages execution, and built-in tracing.

Is the OpenAI Agents SDK the same as OpenAI Swarm?

They share the same conceptual model, but they are different libraries. Swarm (October 2024) was explicitly labelled experimental and educational. The Agents SDK (March 2025) is the production-ready successor with a typed API, guardrail machinery, structured outputs, built-in tracing, and active maintenance. Build on the Agents SDK, not Swarm.

How do handoffs work in the OpenAI Agents SDK?

You list target agents in the source agent's handoffs parameter. When the model decides to route, it calls a special handoff tool; the Runner then switches the active agent and passes the full conversation history to the new agent. The new agent continues the conversation directly — it fully takes over rather than returning a result to an orchestrator.

What is the difference between a handoff and using an agent as a tool?

A handoff transfers conversation ownership — the receiving agent responds directly to the user. Agents-as-tools keep an orchestrator in charge: the orchestrator calls a specialist as a regular tool call and incorporates the result into its own response. Use handoffs when the specialist should fully handle the conversation; use agents-as-tools when you want a coordinator to synthesise multiple specialist results.

How do guardrails work, and what happens when one triggers?

A guardrail is a Python function that returns a GuardrailFunctionOutput with a tripwire_triggered boolean. If it's True, the Runner immediately raises InputGuardrailTripwireTriggered (for input guardrails) or OutputGuardrailTripwireTriggered (for output guardrails). You catch those exceptions in your application code and decide how to respond — typically by returning a safe fallback message to the user.

Does the OpenAI Agents SDK work with models other than OpenAI's?

The SDK is designed primarily for OpenAI models, but it supports any model provider that exposes an OpenAI-compatible API endpoint. You can configure a custom base_url on the model, which makes it possible to use compatible third-party models — though features like structured outputs depend on the provider's support for JSON schema enforcement.

Further reading