Intermediate

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.

✍️ AI School Editorial Team · Lilly Tech Systems 📅 Published Jun 11, 2026 · Reviewed Jun 11, 2026

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.

Provider coupling: The OpenAI Agents SDK is designed for OpenAI models. It works with other providers that expose an OpenAI-compatible API surface, but first-class tracing, structured output, and handoffs are tested against OpenAI models. If your stack is multi-provider, LangGraph or CrewAI offer more uniform multi-provider support.

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:

tools.py - function_tool decorator
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)
💡
Schema inference: The SDK reads the type annotations and docstring to generate the tool schema it sends to the model. Unlike CrewAI, tools can return dicts directly - the SDK serializes them automatically. Unlike LangGraph’s ToolNode, error handling must be done in the tool function itself; unhandled exceptions propagate to the run loop.

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:

agents.py - defining agents with instructions and tools
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

run.py - the runner and result handling
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:

what a handoff looks like in the trace
# 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)}")
Handoffs vs. tool calls: In LangGraph, switching between agent behaviors is a graph routing decision (a conditional edge). In CrewAI, it is a task context dependency. In the OpenAI Agents SDK, it is an explicit handoff - the agent terminates and a new agent starts. Choose the model that matches how your team thinks about agent transitions.

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:

structured output with Pydantic
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, one Agent, one Runner.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.
📚
Authoritative reference: OpenAI Agents SDK documentation at openai.github.io/openai-agents-python (official docs). The tracing guide is at openai.github.io/openai-agents-python/tracing.

Ready to Go Deeper?

Live instructor-led courses from our partners. Affiliate disclosure.