PythonTypeScriptMedium — primitives with opinions
OpenAI Agents SDK
A small, opinionated agent runtime with handoffs between agents, guardrails, and built-in tracing, tightly integrated with OpenAI models and hosted tools.
Architecture
- Agent = instructions + tools + optional
output_type(Pydantic/Zod) + handoffs;Runner.runexecutes the loop until a final output. - Handoffs are tools that transfer the conversation to another agent; the callee sees the history and becomes the active agent (a swarm-style pattern).
- Guardrails run as input or output checks (often a cheaper model) in parallel with the main agent and can trip to abort the run.
- Function tools via
@function_toolderive schemas from signatures and docstrings; hosted tools (web search, file search, computer use) are provider-side. - Tracing is on by default and exported to the OpenAI dashboard;
RunContextcarries typed dependencies into tools.
Best use cases
- Teams committed to OpenAI models who want the vendor's reference loop rather than writing one.
- Triage/handoff designs (front-desk agent routes to specialists).
- Rapid experiments with hosted tools such as web search and file search.
Weaknesses
- Lock-in: other providers work only through the Chat Completions compatibility path; hosted tools and tracing are OpenAI-specific.
- Handoffs move the *whole* conversation; context growth and confused specialist agents are common, and there is no built-in state pruning.
- No durable persistence or checkpointing — long-running or approval-paused runs need your own storage (sessions help with history only).
- Default tracing sends prompts and outputs to OpenAI unless you configure a different processor; check data-handling requirements.
- Young API; naming and hosting features (Responses API, sessions) still move release to release.
When NOT to use it
- Multi-provider or on-prem model requirements.
- Workflows needing resumable checkpoints and explicit state graphs.
- You want to see and version every system prompt — the handoff prompt prefix is injected for you.
Code example
Illustrative — APIs change between versions.
1from agents import Agent, Runner, function_tool, InputGuardrail, GuardrailFunctionOutput2from pydantic import BaseModel3 4class Refund(BaseModel):5 order_id: str6 approved: bool7 reason: str8 9@function_tool10def lookup_order(order_id: str) -> dict:11 """Fetch an order by id."""12 return orders.get(order_id)13 14refunds = Agent(name="Refunds", instructions="Decide refunds per policy.",15 tools=[lookup_order], output_type=Refund)16billing = Agent(name="Billing", instructions="Answer invoice questions.")17 18async def no_pii(ctx, agent, user_input): # guardrail runs alongside the agent19 flagged = contains_card_number(user_input)20 return GuardrailFunctionOutput(output_info=None, tripwire_triggered=flagged)21 22triage = Agent(name="Triage", instructions="Route to the right specialist.",23 handoffs=[refunds, billing], input_guardrails=[InputGuardrail(no_pii)])24 25result = await Runner.run(triage, "I want a refund for order A-123", max_turns=10)26print(result.final_output) # Refund(...) if the run ended in the refunds agent