OpenAI Agents SDK in Practice
The OpenAI Agents SDK takes the thinnest abstraction layer of the three frameworks: agents are instructions + tools + handoffs, the run loop is a single function call, and tracing is built in. This lesson builds the benchmark agent and shows where the simplicity pays off.
The SDK’s Mental Model
The OpenAI Agents SDK was released in early 2025 as OpenAI’s official Python framework for building production agents. Its design philosophy is “as close to the raw API as possible, with the parts you always rebuild included.” An Agent is defined by its instructions (a system prompt string), the tools it can call, and the agents it can hand off to. The Runner executes the agent loop.
The SDK is intentionally small. It does not have LangGraph’s state management system or CrewAI’s role-based crew model. What it does have is built-in OpenAI Platform tracing (every run creates a trace you can inspect in the OpenAI dashboard), Pydantic-based structured output, and handoffs between agents that are first-class operations rather than tool calls.
Defining Tools
Tools in the SDK are Python functions decorated with @function_tool. The SDK infers the JSON schema from the type annotations and docstring automatically:
from agents import function_tool
@function_tool
def web_search(query: str) -> dict:
"""Search the web for information on a query.
Args:
query: The search query string.
Returns:
A dict with 'query' and 'results' (list of title/url/snippet dicts).
"""
return _web_search_impl(query) # implementation from Lesson 3
@function_tool
def fetch_document(url: str) -> dict:
"""Retrieve the full text content of a document by URL.
Args:
url: The URL to fetch.
Returns:
A dict with 'url', 'title', and 'content' keys.
"""
return _fetch_document_impl(url)
Defining the Agents
For the research task, we use the same two-agent structure as in the CrewAI lesson, but defined with the SDK’s lightweight syntax:
from agents import Agent
report_writer = Agent(
name="Report Writer",
instructions="""You write structured research reports.
Given research findings, synthesize them into a clear report with:
1. Direct answer to the research question
2. At least three sourced claims with their URLs
3. An explicit section on information gaps or caveats.
Write in clear, precise prose for a technical audience.""",
# No tools - this agent only synthesizes, does not search
)
researcher = Agent(
name="Research Specialist",
instructions="""You are a systematic research specialist.
Use web_search to find relevant sources, then fetch_document to read
the most promising pages in detail. Collect specific, quotable claims
with their source URLs.
When you have at least three well-sourced claims, hand off to the Report Writer.
If searches return no useful results after three attempts, note the gap and hand off.""",
tools=[web_search, fetch_document],
handoffs=[report_writer], # can transfer control to the report writer
)
Running the Agent
import asyncio
from agents import Runner
async def run_research_agent(question: str) -> str:
result = await Runner.run(
researcher,
input=question,
max_turns=20, # circuit breaker: max agent loop iterations
)
# result.final_output is the last agent's text response
return result.final_output
# Run synchronously in a script
report = asyncio.run(run_research_agent(
"What are the main approaches to AI agent memory?"
))
print(report)
How Handoffs Work
Handoffs are the SDK’s mechanism for multi-agent coordination. When an agent calls a handoff, the current agent stops executing and the target agent takes over with the same conversation history. From the model’s perspective, a handoff looks like a special tool call; the SDK handles the transition transparently:
# In the OpenAI dashboard trace, you will see:
# Turn 1: researcher called web_search("AI agent memory approaches")
# Turn 2: researcher called fetch_document("https://...")
# Turn 3: researcher called fetch_document("https://...")
# Turn 4: researcher called handoff_to_report_writer(...)
# → control transfers to report_writer
# Turn 5: report_writer generated final report
# In code, the result tells you which agent finished:
print(f"Final agent: {result.last_agent.name}")
print(f"Turns used: {len(result.raw_responses)}")
Structured Output
The SDK integrates with Pydantic for structured output. If your agent needs to return a typed object rather than a free-text string, define an output type:
from pydantic import BaseModel
from typing import List
class ResearchClaim(BaseModel):
claim: str
source_url: str
confidence: str # "high", "medium", "low"
class ResearchReport(BaseModel):
answer_summary: str
claims: List[ResearchClaim]
information_gaps: List[str]
structured_writer = Agent(
name="Structured Report Writer",
instructions="Write a research report with claims and gaps.",
output_type=ResearchReport, # SDK enforces this schema
)
result = await Runner.run(structured_writer, input="...")
report: ResearchReport = result.final_output # typed, not a string
Built-in Tracing
Every run creates a trace in the OpenAI Platform. You can inspect it at platform.openai.com → Traces. The trace shows every agent turn, tool call, and handoff in a timeline view. For teams already on OpenAI, this eliminates the need to configure a separate tracing tool for most use cases.
For custom tracing (sending traces to your own observability stack), the SDK provides trace hooks via the trace_processors parameter on Runner.run().
OpenAI Agents SDK: What It’s Good At
- Lowest boilerplate for OpenAI teams - if you are already on OpenAI, the SDK adds minimal surface area. One
@function_tool, oneAgent, oneRunner.run()call. - Built-in tracing with zero config - every run is traced automatically in the OpenAI Platform. No LangSmith account, no separate logging infrastructure needed.
- Structured output - Pydantic integration for typed agent outputs is first-class, not bolted on.
OpenAI Agents SDK: What It Costs
- OpenAI coupling - the SDK is designed for OpenAI models. Non-OpenAI providers work but receive less investment from the SDK authors.
- No built-in checkpointing - unlike LangGraph, there is no built-in mechanism to resume an interrupted run. Long-running agents that need resumption require custom persistence.
- Thinner abstraction = more manual work - the SDK does not provide a state management system, a role abstraction, or a process model. Simple cases are simple; complex orchestration requires more application code.
Ready to Go Deeper?
Live instructor-led courses from our partners. Affiliate disclosure.
AI & ML Courses - 30% Off
Live instructor-led AI, machine learning, data science, and cloud courses for working professionals. Use code Limited30 at checkout.
EdurekaDataCamp - AI & Data Science
Hands-on Python, machine learning, and AI courses with interactive exercises and real projects.
DataCampedX - Top AI Courses
University-level AI courses from MIT, Harvard, Stanford. Earn certificates that employers recognize.
edX