Building AI Agents with the OpenAI Agents SDK: A Practical Guide
OpenAI's Agents SDK is a small, production-minded framework built on four ideas: agents, tools, handoffs, and guardrails. This is the runnable tour — from your first agent to a multi-agent triage system with safety rails.
OpenAI's Agents SDK is refreshingly small. Where some frameworks give you fifty concepts, this one gives you four that matter — agents, tools, handoffs, and guardrails — plus sessions and tracing that mostly stay out of your way. It's the production-minded successor to OpenAI's earlier Swarm experiment, and its whole design philosophy is that you shouldn't need to learn a framework to build an agent; you should need to learn agents. This guide is the runnable tour: we'll build a single agent, give it tools, turn it into a multi-agent triage system, and put a safety rail on the front — with code you can paste and run at each step.
An LLM with instructions, a model, and tools. The core unit you compose everything from.
Six primitives. Everything you build with the SDK is a combination of these.
Your first agent
An agent is an LLM with instructions and, optionally, tools. A tool is any Python function you decorate with @function_tool — the SDK reads its signature and docstring to build the schema the model sees. And a Runner drives the loop for you: it calls the model, runs any tool the model requests, feeds the result back, and returns the final answer. Here's the whole thing:
# pip install openai-agents
from agents import Agent, Runner, function_tool
@function_tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's 18°C and clear in {city}."
agent = Agent(
name="Weather Assistant",
instructions="You are concise. Use get_weather when asked about the weather.",
tools=[get_weather],
)
result = Runner.run_sync(agent, "What's the weather in Tokyo?")
print(result.final_output) # -> "It's 18°C and clear in Tokyo."That's a complete, tool-using agent in a dozen lines. Runner.run_sync is the synchronous convenience wrapper; in an async app you'd await Runner.run(agent, ...) instead. Either way, result.final_output is your answer. Under the hood, the SDK ran this loop:
The Runner drives the loop for you: it calls tools, feeds results back, and stops at a final answer.
Handoffs: multi-agent, the OpenAI way
The SDK's answer to multi-agent systems is the handoff: one agent can delegate the conversation to another. You build specialists as ordinary agents, give each a handoff_description so the router knows what it's for, and list them on a triage agent's handoffs. The routing is the model's decision — you write no dispatch logic.
from agents import Agent, Runner
billing = Agent(
name="Billing",
handoff_description="Handles charges, invoices and refunds",
instructions="Resolve billing questions. Be precise about amounts.",
)
tech = Agent(
name="Tech",
handoff_description="Handles bugs, errors and login problems",
instructions="Help the user troubleshoot technical issues.",
)
triage = Agent(
name="Triage",
instructions="Route each request to the right specialist.",
handoffs=[billing, tech],
)
result = Runner.run_sync(triage, "I was double-charged for my order.")
print(result.final_output)I see the duplicate charge and I've issued a refund.
A triage agent with `handoffs=[…]` routes each message to the right specialist — no routing code of your own.
Guardrails: stop a bad run before it costs you
Guardrails are cheap checks that run alongside your agent and can abort it before it spends money or does harm. An input guardrail inspects the incoming request; if it trips its wire, the run halts immediately. The shape is a decorated function that returns a GuardrailFunctionOutput with tripwire_triggered set:
from agents import Agent, input_guardrail, GuardrailFunctionOutput
@input_guardrail
async def block_injection(ctx, agent, user_input) -> GuardrailFunctionOutput:
tripped = "ignore your rules" in str(user_input).lower()
return GuardrailFunctionOutput(output_info={"blocked": tripped}, tripwire_triggered=tripped)
agent = Agent(
name="Support",
instructions="Answer support questions from the knowledge base.",
input_guardrails=[block_injection],
)The guardrail passes and the agent runs normally.
The point of a guardrail is economics: run a fast, cheap classifier first so your expensive agent never processes input that was always going to be rejected. Output guardrails work the same way on the way out.
Sessions and tracing come for free
Two things you'd normally have to build yourself are built in. Sessions persist conversation history across Runner.run calls, so the agent remembers without you re-sending the transcript. And tracing records every run, tool call, and handoff automatically — which is the difference between debugging an agent and guessing at it. Both are opt-in defaults rather than extra libraries to wire up.
When to reach for the OpenAI Agents SDK
Its sweet spot is exactly its design: you want a small, well-supported framework, you're comfortable in the OpenAI ecosystem, and you value handoffs and built-in tracing over maximal control of the graph. If you need custom control flow — arbitrary loops, branching, human-in-the-loop pauses — a graph-based framework like LangGraph gives you more room, and if you want a role-based team, CrewAI is faster to stand up. Our framework comparison lines them up honestly.
Learn it by running it
Reading the code is one thing; running it is where it sticks. The OpenAI Agents SDK notebook track builds every concept here in the browser, cell by cell — the run loop, handoffs and triage, input and output guardrails, structured output, sessions, and streaming with tracing. And once you've got an agent you like, the Agent Builder lets you ship it — and the 15 agent examples give you working patterns to start from.
The reason this SDK is a good first framework is the reason it's a good last one: it doesn't hide the agent from you. Four primitives, a loop you can see, and the safety and observability you need in production — build one agent with it and you'll understand every other framework faster.
Further reading & references
Was this useful?
Comments
Loading comments…