OpenAI Agents SDK Basics
8 examples to get you started with the OpenAI Agents SDK - 5 basic and 3 intermediate.
You will install the package, run a single agent, add a function tool, continue a conversation, attach handoffs, and read the run result.
APIs move quickly; verify model names, package version, and imports at build against openai.github.io/openai-agents-python.
Prerequisites
- Python 3.10+ recommended
- An OpenAI API key with access to a chat/responses-capable model
- Comfort with
asynciofor asyncRunner.run(sync helpers exist too)
python -m venv .venv && source .venv/bin/activate
pip install openai-agents
export OPENAI_API_KEY="sk-..."Basic Examples
1. Hello World Agent
Define a named agent and run it once.
import asyncio
from agents import Agent, Runner
agent = Agent(
name="History Tutor",
instructions="You answer history questions clearly and concisely.",
)
async def main():
result = await Runner.run(agent, "When did the Roman Empire fall?")
print(result.final_output)
asyncio.run(main())Agentholds name, instructions, tools, handoffs, and optional model settings.Runner.runexecutes the agent loop until a final output is ready.result.final_outputis the text (or structured) answer for the run.
Related: What Native Provider Agent Primitives Give You Over a Framework
2. Synchronous Runner Shortcut
Use Runner.run_sync when you do not want an async entrypoint.
from agents import Agent, Runner
agent = Agent(
name="Assistant",
instructions="Reply in one short sentence.",
)
result = Runner.run_sync(agent, "Name one benefit of tool-using agents.")
print(result.final_output)run_syncwraps the async runner for scripts and notebooks.- Prefer async in servers so you do not block the event loop incorrectly.
- Same
RunResultshape either way.
3. Add a Function Tool
Decorate a Python function and pass it into tools.
import asyncio
from agents import Agent, Runner, function_tool
@function_tool
def history_fun_fact() -> str:
"""Return a short history fact."""
return "Sharks are older than trees."
agent = Agent(
name="History Tutor",
instructions=(
"Answer history questions clearly. "
"Use history_fun_fact when it helps."
),
tools=[history_fun_fact],
)
async def main():
result = await Runner.run(
agent,
"Tell me something surprising about ancient life on Earth.",
)
print(result.final_output)
asyncio.run(main())@function_toolbuilds a JSON schema from type hints and the docstring.- The runner invokes the tool when the model requests it and feeds results back.
- Keep tools pure and side-effect-aware; retries may re-call tools.
Related: Tool Use & Function Calling Basics
4. Tools with Parameters
Accept typed arguments so the model must fill a real schema.
from agents import Agent, Runner, function_tool
@function_tool
def get_weather(city: str) -> str:
"""Return a demo weather string for a city."""
# Replace with a real weather API in production.
demo = {"paris": "sunny, 22C", "tokyo": "cloudy, 19C"}
return demo.get(city.lower(), f"No data for {city}")
agent = Agent(
name="Weather Assistant",
instructions="Use get_weather for weather questions. Be brief.",
tools=[get_weather],
)
result = Runner.run_sync(agent, "What is the weather in Paris?")
print(result.final_output)- Parameter names and types become tool JSON schema properties.
- Docstrings become tool descriptions the model sees.
- Validate destructive args inside the function before side effects.
5. Multi-Agent Handoffs (Triage)
Route homework-style questions to specialists via handoffs.
import asyncio
from agents import Agent, Runner
history_tutor = Agent(
name="History Tutor",
handoff_description="Specialist agent for historical questions",
instructions="You answer history questions clearly and concisely.",
)
math_tutor = Agent(
name="Math Tutor",
handoff_description="Specialist agent for math questions",
instructions="You explain math step by step with worked examples.",
)
triage = Agent(
name="Triage Agent",
instructions="Route each homework question to the right specialist.",
handoffs=[history_tutor, math_tutor],
)
async def main():
result = await Runner.run(
triage,
"Who was the first president of the United States?",
)
print(result.final_output)
print("Answered by:", result.last_agent.name)
asyncio.run(main())- Handoffs appear to the model as tools such as
transfer_to_history_tutor. handoff_descriptionhelps the triage agent choose a destination.result.last_agentshows which specialist finished the run.
Intermediate Examples
6. Continue a Conversation with to_input_list
Pass prior run items back for a multi-turn script without sessions.
import asyncio
from agents import Agent, Runner
agent = Agent(
name="Coach",
instructions="You are a concise writing coach.",
)
async def main():
r1 = await Runner.run(agent, "My topic is remote work culture.")
print("Turn 1:", r1.final_output)
follow_up = r1.to_input_list() + [
{"role": "user", "content": "Give me three outline bullets only."}
]
r2 = await Runner.run(agent, follow_up)
print("Turn 2:", r2.final_output)
asyncio.run(main())to_input_list()rebuilds provider-agnostic history from the prior run.- Alternative memory strategies include SDK sessions and server-managed conversation ids (verify at build).
- Pick one memory strategy per product surface; do not mix casually.
7. Structured Final Output with output_type
Force the final answer into a Pydantic model.
from pydantic import BaseModel, Field
from agents import Agent, Runner
class TicketDraft(BaseModel):
title: str = Field(description="Short issue title")
priority: str = Field(description="low, medium, or high")
summary: str
agent = Agent(
name="Ticket Writer",
instructions="Turn the user complaint into a support ticket object.",
output_type=TicketDraft,
)
result = Runner.run_sync(
agent,
"My card was charged twice and I need this fixed today.",
)
print(result.final_output)
# TicketDraft(...)
print(result.final_output.priority)output_typeasks the SDK to produce a validated structured final value.- Prefer enums or constrained fields for anything your code will branch on.
- Structure does not guarantee factual truth; it guarantees shape.
8. Inspect the Run Result Beyond Final Text
Log which agent answered and that the run completed.
from agents import Agent, Runner, function_tool
@function_tool
def ping() -> str:
"""Health check tool for demos."""
return "pong"
agent = Agent(
name="Ops Bot",
instructions="Use ping if asked about health.",
tools=[ping],
)
result = Runner.run_sync(agent, "Run a health check.")
print("final:", result.final_output)
print("last agent:", result.last_agent.name)
# Explore result attributes in your installed version (items, usage, etc.)- Always log
last_agentin multi-agent systems for support debugging. - Prefer official tracing dashboards for deep tool timelines.
- Do not print secrets from tool arguments in production logs.
What to Practice Next
- Add input/output guardrails before exposing tools with side effects.
- Connect an MCP server as a tool source instead of hand-writing every integration.
- Decide explicitly when natives are enough versus LangGraph or a custom runtime.
Related: Native MCP Support in the OpenAI Agents SDK
Related: OpenAI Agents SDK & Native Primitives Best Practices
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.