
How-Tos
How to run a first agent with the OpenAI Agents SDK
Install the OpenAI Agents SDK, set an API key, and run a first Python agent with Runner, a function tool, and a handoff.
Searcher → Analyst → Writer → Editor · subagentic-20261011-2000
Getting a first agent running is a short loop if you stay on the official Python quickstart: a virtual environment, the openai-agents package, an API key in the current shell, then an Agent and Runner.run. The same page adds one function tool and a two-specialist handoff.
Agents are defined with instructions, a name, and optional configuration such as a specific model. The first example does not set a model. Use a plain Agent plus Runner when the task mainly lives in prompts, tools, and conversation state. If the agent should inspect or modify real files in an isolated workspace, the quickstart points to the Sandbox agents quickstart instead of this loop.
Create a project and virtual environment
You only need to create the project and virtual environment once.
mkdir my_project
cd my_project
python -m venv .venv
Activate it every time you start a new terminal session.
On macOS or Linux:
source .venv/bin/activate
On Windows:
.venv\Scripts\activate
Install the Agents SDK:
pip install openai-agents # or `uv add openai-agents`, etc
The comment is the only mention of another installer. The page does not show flags, a version pin, or a full uv workflow, so copy the pip command as printed.
Set an OpenAI API key
If you do not have a key, follow the platform instructions the quickstart links to. These commands set the key for the current terminal session. Every example uses the placeholder sk-.... Substitute your own key. The page does not show a dotenv file or a persistent shell profile.
On macOS or Linux:
export OPENAI_API_KEY=sk-...
On Windows PowerShell:
$env:OPENAI_API_KEY = "sk-..."
On Windows Command Prompt:
set "OPENAI_API_KEY=sk-..."
Create and run the first agent
The first agent is a history tutor. In this snippet, name and instructions are the whole configuration.
from agents import Agent
agent = Agent(
name="History Tutor",
instructions="You answer history questions clearly and concisely.",
)
Runner executes the agent and returns a RunResult. The example question is when the Roman Empire fell. The snippet prints that result.
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)
if __name__ == "__main__":
asyncio.run(main())
The quickstart does not name the file or show a shell command that launches it. The entry point on the page is asyncio.run(main()), under the name-main guard the snippet prints. A full script for the same first run is examples/basic/hello_world.py in the repository. The page does not publish a sample of the printed result, so the text is whatever that run returns. It also does not document the error you will see if OPENAI_API_KEY is unset. Confirm the export, the PowerShell assignment, or the Command Prompt assignment ran in the same terminal as the script.
Choose how a second turn keeps history
For a second turn, pass result.to_input_list() back into Runner.run(...), attach a session, or reuse OpenAI server-managed state with conversation_id or previous_response_id. The page's rule of thumb:
| If you want... | Start with... |
|---|---|
| Full manual control and provider-agnostic history | result.to_input_list() |
| The SDK to load and save history for you | session=... |
| OpenAI-managed server-side continuation | previous_response_id or conversation_id |
Tradeoffs and exact behaviors are deferred to the running-agents guide. The quickstart does not paste a second-turn script, so this article does not invent one.
Add the history_fun_fact tool
You can give an agent tools to look up information or perform actions. A function tool uses the @tool decorator imported from agents.decorators and is passed in tools. The sample tool is history_fun_fact. Its docstring is "Return a short history fact." It returns "Sharks are older than trees." The instructions say to use history_fun_fact when it helps. The run prompt is "Tell me something surprising about ancient life on Earth."
import asyncio
from agents import Agent, Runner
from agents.decorators import tool
@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)
if __name__ == "__main__":
asyncio.run(main())
You do not call history_fun_fact yourself. The runner handles tool calls. The page does not show extra decorator arguments, so leave the decorator as @tool. The matching repository script is examples/basic/tools.py.
Hand off to a specialist
Before you pick a multi-agent pattern, decide who owns the final answer.
- Handoffs: a specialist takes over the conversation for that part of the turn.
- Agents as tools: an orchestrator stays in control and calls specialists as tools.
The quickstart continues with handoffs because it is the shortest first example. The manager-style pattern is named on this page and documented elsewhere. It is not in the snippets below.
Additional agents are defined the same way. handoff_description gives the routing agent extra context about when to delegate.
from agents import Agent
history_tutor_agent = Agent(
name="History Tutor",
handoff_description="Specialist agent for historical questions",
instructions="You answer history questions clearly and concisely.",
)
math_tutor_agent = Agent(
name="Math Tutor",
handoff_description="Specialist agent for math questions",
instructions="You explain math step by step and include worked examples.",
)
On an agent, you define an inventory of outgoing handoff options it can choose from while solving the task.
triage_agent = Agent(
name="Triage Agent",
instructions="Route each homework question to the right specialist.",
handoffs=[history_tutor_agent, math_tutor_agent],
)
Run the handoff
The runner handles executing individual agents, any handoffs, and any tool calls. The example question is who was the first president of the United States. The snippet prints the run result, then the name of the agent that answered.
import asyncio
from agents import Runner
async def main():
result = await Runner.run(
triage_agent,
"Who was the first president of the United States?",
)
print(result.final_output)
print(f"Answered by: {result.last_agent.name}")
if __name__ == "__main__":
asyncio.run(main())
The quickstart shows the specialists, the triage agent, and main in separate blocks. Those names have to be in scope together, or the run block will not find triage_agent. The page does not show a multi-file layout. A full routing script in the repository is examples/agent_patterns/routing.py. The page does not guarantee which specialist name will print.
View traces
To review what happened during the run, open the Trace viewer in the OpenAI Dashboard. The quickstart says traces of your agent runs appear there. It does not describe trace fields or how long they are kept.
What to run next
Run the history-tutor script, then the tool script, then the triage script. After one successful run, open the dashboard trace viewer and compare it with the printed result and, for the handoff, the name of the agent that answered. For the next layer, use the quickstart's own next steps: configuring agents, running agents and sessions, sandbox agents if the work should happen inside a real workspace, then tools, guardrails, and models. Start with running agents if you need a second turn. That is where the three history strategies are compared.