OpenAI Agents SDK: handoffs & guardrails
A lightweight, production-minded agent framework: Agents, Runner, Tools, Handoffs, Guardrails, and Sessions. The default starting point for many production agentic systems in 2026.
What you'll learn
- The core primitives — Agent, Runner, tools, handoffs, guardrails, sessions
- How handoffs route a task between specialized agents
- Where input/output guardrails sit and why they matter
Before you start
After a wave of heavy frameworks, the OpenAI Agents SDK went the other way: small, explicit, few abstractions. In 2026 it’s a common default for production-grade agents, precisely because there’s so little magic — you can read the whole mental model in one lesson. (It’s provider-flexible too, not OpenAI-only.)
Five primitives
- Agent — an LLM plus instructions, a set of tools, and optionally some handoffs. That’s it.
- Runner — runs the agent loop: call the model, run any tool it picked, feed the result back, repeat until a final answer.
- Tools — Python functions exposed to the agent (plus hosted tools and MCP servers).
- Handoffs — one agent can delegate the conversation to another, more
specialized agent. A handoff is literally implemented as a tool call
(
transfer_to_X), so it shows up in the trace like any other action. - Guardrails — input and output checks that run alongside the agent and can halt it (e.g. block off-topic input, validate output) — see prompt injection & guardrails.
- Sessions — automatic conversation history across runs, so you don’t hand-thread state.
Handoffs: a triage agent routing to specialists
The signature pattern is handoffs: a cheap triage agent classifies the request and transfers to the right specialist. It’s the call-center move — a front-desk operator who doesn’t solve your problem but knows exactly which department to put you through to.
from agents import Agent, Runner, input_guardrail, GuardrailFunctionOutput
billing = Agent(name="Billing", instructions="Handle refunds and invoices.")
technical = Agent(name="Technical", instructions="Handle bugs and how-tos.")
@input_guardrail
async def on_topic(ctx, agent, user_input) -> GuardrailFunctionOutput:
ok = "support" in user_input.lower() or True # your real check here
return GuardrailFunctionOutput(tripwire_triggered=not ok, output_info={})
triage = Agent(
name="Triage",
instructions="Route the user to Billing or Technical.",
handoffs=[billing, technical], # delegate to a specialist
input_guardrails=[on_topic], # block off-topic before running
)
# result = await Runner.run(triage, "I want a refund on last month's invoice")
# → triage calls transfer_to_billing; Billing answers. The handoff is in the trace.
Because a handoff is a tool call, it obeys the same rules as any tool: the model picks it from the handoff’s name and description plus the triage agent’s instructions. When triage keeps answering itself, the fix is almost always there — make the handoff’s purpose explicit (“transfer anything about refunds, invoices, or charges”) and tell triage to route, not answer. Same levers as tool calling.
In one breath
- The OpenAI Agents SDK is deliberately minimal — few primitives, the agent loop is visible — which is why it’s a common production default (and it’s provider- flexible, not OpenAI-only).
- Six primitives: Agent (LLM + instructions + tools + handoffs), Runner (runs the loop), Tools, Handoffs, Guardrails, Sessions.
- A handoff is one agent delegating to a specialist — implemented as a
transfer_to_Xtool call, so it appears in the trace and obeys the usual name/description tool-selection rules. - Guardrails are input/output checks that run alongside the agent and can trip a tripwire to halt the run — block off-topic input, validate output.
- Reach for it for the common router + specialists + guardrails shape; for complex stateful graphs, LangGraph. Sessions give automatic history so you don’t hand-thread state.
Quick check
Quick check
Next
Whatever framework you pick, production agents need measurement and limits: evaluating agents, observability, and cost control.
Practice this in an interview
All questionsKey risks include prompt injection, especially indirect injection via tool or retrieval outputs, hijacking the agent, excessive tool permissions enabling damaging actions, data exfiltration, confused-deputy privilege escalation, and unbounded loops driving cost or harm. Mitigations include least-privilege tools, sandboxing, input and output guardrails, human-in-the-loop approval for sensitive actions, and audit logging.
Keep raw credentials outside model context and traces. Let the model propose typed intent, authorize the final action and arguments deterministically, then have a trusted executor inject a short-lived, narrowly scoped, audience-restricted credential for one call. Re-authorize downstream and gate high-impact writes with explicit approval.
An agent is an LLM placed in a loop where it reasons, chooses and calls tools or actions, observes the results, and repeats until a goal is met, rather than producing one response and stopping. The key differences are autonomy, tool use, memory and state, and multi-step control flow driven by the model's own decisions.
Operationalizing responsible AI means turning principles like fairness, transparency, and accountability into concrete, automated controls: bias and fairness tests in the pipeline, data and model documentation, human oversight, and continuous monitoring with audit trails. Under the EU AI Act, high-risk systems carry specific obligations including data governance and bias assessment, risk management, technical documentation, logging, human oversight, and post-market monitoring. The practical shift is that fairness and governance become gated, evidenced requirements rather than optional add-ons.