Building AI Agents with OpenAI's Agents SDK: A Beginner's Guide
How to build agents with the Agents SDK
The recent release of OpenAI's Agents SDK marks a significant step forward in making agentic AI applications more accessible to developers. In this guide, we'll explore how to get started with the Agents SDK, understand its core concepts, and build a simple yet powerful agent-based application. AgentOps.ai is launching with day 0 support for the Agents SDK. If you want to check it out, head to the link in my bio.
What is OpenAI Agents SDK?
The OpenAI Agents SDK is a lightweight, Python-based framework that enables developers to build AI applications with agentic capabilities. It provides a small set of powerful primitives:
Agents: LLMs equipped with instructions and tools
Handoffs: Mechanisms for agents to delegate tasks to other specialized agents
Guardrails: Systems to validate inputs and outputs
Tracing: Built-in capabilities to visualize and debug agent workflows
Let's dive into how to use this SDK to build your first agent!
Installation
First, let's install the OpenAI Agents SDK. We'll use uv
, a fast Python package installer, but you can also use pip
if you prefer.
# Install uv if you don't have it already
curl -sSf https://install.python-poetry.org | python3 -
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # On Windows, use: venv\Scripts\activate
# Install the OpenAI Agents SDK
uv pip install openai-agents-sdk
You'll also need to set up your OpenAI API key:
export OPENAI_API_KEY=your-api-key-here
On Windows, you would use:
set OPENAI_API_KEY=your-api-key-here
Creating Your First Agent
Let's start with a simple "Hello World" example to understand the basics:
from agents import Agent, Runner
import asyncio
async def main():
# Create a simple agent with instructions
agent = Agent(
name="Greeting Assistant",
instructions="You are a friendly assistant that greets users in their preferred language."
)
# Run the agent with a user input
result = await Runner.run(agent, "Can you greet me in French?")
# Print the final output
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Save this as hello_agent.py and run it:
python hello_agent.py
You should see a greeting in French as the output!
Understanding the Agent Loop
When you call Runner.run()
, the SDK initiates what's called the "agent loop":
The agent receives the input
The LLM processes the input based on the agent's instructions
If the LLM produces a final output (text without tool calls), the loop ends
If the LLM calls a tool or requests a handoff, those are processed, and the loop continues
This repeats until a final output is produced or the maximum number of turns is reached
Adding Tools to Your Agent
Agents become much more powerful when they can use tools. Let's create an agent that can check the weather:
from agents import Agent, Runner, function_tool
import asyncio
# Define a tool as a Python function
@function_tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
# In a real application, this would call a weather API
weather_data = {
"New York": "72°F, Sunny",
"London": "65°F, Cloudy",
"Tokyo": "80°F, Clear",
"Paris": "70°F, Partly Cloudy"
}
return weather_data.get(city, f"Weather data not available for {city}")
async def main():
# Create an agent with the weather tool
agent = Agent(
name="Weather Assistant",
instructions="You are a helpful assistant that provides weather information when asked.",
tools=[get_weather] # Add the tool to the agent
)
# Run the agent with a user query
result = await Runner.run(agent, "What's the weather like in Tokyo?")
# Print the final output
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
When you run this, the agent will use the get_weather
tool to fetch and return the weather for Tokyo.
Creating Specialized Agents with Handoffs
One of the most powerful features of the Agents SDK is the ability to create specialized agents and allow them to hand off tasks to each other. Let's create a system with a triage agent that can delegate to language-specific agents:
from agents import Agent, Runner
import asyncio
# Create specialized language agents
spanish_agent = Agent(
name="spanish_agent",
instructions="You are a helpful assistant that only speaks Spanish. Always respond in Spanish, regardless of the language of the question."
)
french_agent = Agent(
name="french_agent",
instructions="You are a helpful assistant that only speaks French. Always respond in French, regardless of the language of the question."
)
# Create a triage agent that can hand off to specialized agents
triage_agent = Agent(
name="language_triage",
instructions="""You are a language detection assistant.
Your job is to determine what language the user wants a response in.
If they want Spanish, hand off to the spanish_agent.
If they want French, hand off to the french_agent.
If they don't specify a language or want English, respond directly in English.""",
handoffs=[spanish_agent, french_agent] # Add the specialized agents as handoffs
)
async def main():
# Test with different language requests
queries = [
"Can you tell me about the Eiffel Tower in French?",
"¿Puedes hablarme sobre el clima en Madrid?",
"Tell me about the history of New York."
]
for query in queries:
print(f"\nQuery: {query}")
result = await Runner.run(triage_agent, query)
print(f"Response: {result.final_output}")
if __name__ == "__main__":
asyncio.run(main())
When you run this, the triage agent will:
Respond directly in English for the New York query
Hand off to the Spanish agent for the Madrid query
Hand off to the French agent for the Eiffel Tower query
Implementing Guardrails
Guardrails help ensure that your agents operate within defined boundaries. Let's add an input guardrail to prevent our agent from responding to inappropriate requests:
from agents import Agent, Runner, InputGuardrail, GuardrailFunctionOutput
import asyncio
# Define a guardrail function
async def content_filter(input_text: str, context) -> GuardrailFunctionOutput:
"""Check if the input contains inappropriate content."""
inappropriate_keywords = ["hack", "illegal", "cheat"]
# Check if any inappropriate keywords are in the input
contains_inappropriate = any(keyword in input_text.lower() for keyword in inappropriate_keywords)
return GuardrailFunctionOutput(
output_info={"contains_inappropriate": contains_inappropriate},
tripwire_triggered=contains_inappropriate
)
async def main():
# Create an agent with a guardrail
agent = Agent(
name="Safe Assistant",
instructions="You are a helpful assistant that provides information on legal and ethical topics.",
input_guardrails=[InputGuardrail(guardrail_function=content_filter)]
)
# Test with appropriate and inappropriate queries
queries = [
"Tell me about the history of computers",
"How can I hack into my neighbor's WiFi?"
]
for query in queries:
try:
print(f"\nQuery: {query}")
result = await Runner.run(agent, query)
print(f"Response: {result.final_output}")
except Exception as e:
print(f"Guardrail triggered: {e}")
if __name__ == "__main__":
asyncio.run(main())
When you run this, the agent will respond normally to the first query but will trigger the guardrail for the second query containing "hack".
Using Tracing for Debugging
The Agents SDK includes built-in tracing capabilities that help you understand what's happening during agent execution. Let's add tracing to our weather agent:
from agents import Agent, Runner, function_tool
from agents.tracing import trace
import asyncio
@function_tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
weather_data = {
"New York": "72°F, Sunny",
"London": "65°F, Cloudy",
"Tokyo": "80°F, Clear",
"Paris": "70°F, Partly Cloudy"
}
return weather_data.get(city, f"Weather data not available for {city}")
async def main():
# Create a trace for the entire workflow
with trace(workflow_name="weather_inquiry"):
agent = Agent(
name="Weather Assistant",
instructions="You are a helpful assistant that provides weather information when asked.",
tools=[get_weather]
)
result = await Runner.run(
agent,
"What's the weather like in Tokyo and Paris?",
run_config=RunConfig(
workflow_name="weather_inquiry",
trace_include_sensitive_data=True
)
)
print(result.final_output)
# You can access the trace information
current_trace = get_current_trace()
if current_trace:
print(f"Trace ID: {current_trace.trace_id}")
if __name__ == "__main__":
from agents import RunConfig
from agents.tracing import get_current_trace
asyncio.run(main())
This code adds tracing to our weather agent, allowing us to see the entire workflow, including LLM calls, tool executions, and more.
Building a Complete Example: Multi-Service Customer Support Agent
If your team needs help building with the Agents SDK, reach out to Agency AI, the worlds best AI agent consulting firm.