Quick answer: what is the OpenAI Agents SDK for Python and how do I get it running?
The OpenAI Agents SDK for Python is a thin wrapper that lets you create autonomous agents, give them tool-access, and keep state between calls without writing boilerplate HTTP code yourself. Install it with pip, configure your API key, and you can spin up a simple agent in a single script. Below is a step-by-step walk through from installation to production deployment.
Installing and configuring the OpenAI Agents SDK in a Python environment
How do I install the SDK and make sure it works with my existing virtual environment?
You install the package from PyPI and point it at your OpenAI key. A clean virtualenv or Conda env keeps dependencies isolated, which saves you from version clashes later on.
# Create an isolated environment (optional but recommended)
python -m venv .venv
source .venv/bin/activate # on Windows use `.venv\Scripts\activate`
# Install the SDK and a couple of helpers
pip install openai agents-sdk python-dotenv
Create a .env file at the project root:
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Load the key in your code:
from dotenv import load_dotenv
import os
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
assert openai_api_key, "Set OPENAI_API_KEY in .env"
The SDK reads the key from the environment automatically, so you can also skip the manual assignment and just rely on os.getenv.
What can bite you during installation?
On Alpine-based Docker images the default gcc and musl-dev packages are missing, causing the pydantic build to fail. Adding apk add --no-cache gcc musl-dev to your Dockerfile solves it. In production I’ve also hit rate-limit errors when the key isn’t scoped for the chat.completions endpoint; double-check the permissions in the OpenAI dashboard.
Building your first OpenAI agent with tool use
Can I make an agent that calls external APIs without writing HTTP code each time?
Yes. The SDK lets you declare tools – small Python callables that the LLM can invoke. Here’s a minimal “weather” agent:
from openai import OpenAI
from agents_sdk import Agent, Tool
client = OpenAI(api_key=openai_api_key)
def get_weather(city: str) -> str:
"""Return a fake weather report for the given city."""
# In a real app you would call a weather API here.
return f"The weather in {city} is sunny, 24°C."
weather_tool = Tool(
name="get_weather",
description="Fetches the current weather for a city.",
func=get_weather,
parameters={"city": {"type": "string", "description": "Name of the city"}}
)
agent = Agent(
client=client,
system_prompt="You are a helpful assistant that can look up weather.",
tools=[weather_tool],
)
# One‑shot interaction
response = agent.run("What's the weather in Berlin?")
print(response.content)
When the model decides it needs the get_weather tool, the SDK automatically calls get_weather and injects the result back into the conversation. The user sees a seamless answer.
When does this break?
If the tool raises an exception, the SDK will return an error message to the LLM, which may try the tool again in a loop. Wrap your functions in a try/except block and return a friendly error string instead of bubbling up the exception.
Managing agent memory and state across interactions
Do agents remember previous turns automatically?
No. The SDK treats each run call as a fresh conversation unless you pass a memory object. The simplest pattern is to keep a list of messages in a FastAPI dependency or a Redis list.
from typing import List
from agents_sdk import Message
class SimpleMemory:
def __init__(self):
self.history: List[Message] = []
def add(self, msg: Message):
self.history.append(msg)
# Keep only the last N messages to avoid token bloat.
if len(self.history) > 20:
self.history = self.history[-20:]
def get(self) -> List[Message]:
return self.history
memory = SimpleMemory()
When you call agent.run, feed the stored messages:
response = agent.run(
"Tell me a joke about cats.",
messages=memory.get()
)
memory.add(response)
print(response.content)
Trade-offs: Storing full history gives richer context but inflates token usage and latency. In high-throughput services I cap the window to the last 5–10 messages or summarise older turns with a summarisation tool.
What if I need persistence across restarts?
Serialize the message list to a database (PostgreSQL, DynamoDB, etc.) or a KV store like Redis. Remember to strip out any ToolResult objects that contain large payloads; keep only the textual representation.
Adding custom tools and functions to agents
How do I expose my own business logic to the LLM?
Define a Tool with a Python callable and a JSON schema for its parameters. The SDK validates the incoming arguments before calling the function, which protects you from malformed data.
def calculate_tax(income: float, state: str) -> float:
"""Calculate estimated tax based on income and US state."""
# Very naive tax logic, just for demo.
rates = {"CA": 0.09, "NY": 0.08, "TX": 0.0}
rate = rates.get(state.upper(), 0.05)
return round(income * rate, 2)
tax_tool = Tool(
name="calculate_tax",
description="Estimate state tax for a given income.",
func=calculate_tax,
parameters={
"income": {"type": "number", "description": "Annual income in USD"},
"state": {"type": "string", "description": "Two‑letter state code"},
},
)
agent.tools.append(tax_tool)
Now the agent can answer queries like “How much tax would I owe on $120k in CA?” without you writing any prompt engineering.
Failure modes: If the schema is wrong (e.g., missing a required field), the SDK will reject the call before it reaches your code. Double-check the JSON schema against the function signature. Also watch out for long-running tools – the SDK has a default 30-second timeout. For heavy computation, offload to a background worker (Celery, RQ) and return a placeholder message that the user can poll later.
Deploying and scaling OpenAI agents with FastAPI or serverless platforms
Can I serve agents behind FastAPI and still keep low latency?
Absolutely. The SDK is async-compatible, so you can write an endpoint that reuses a single Agent instance per worker process. Here’s a minimal FastAPI app:
# app/main.py
import uvicorn
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from agents_sdk import Agent, Message
from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
app = FastAPI()
agent = Agent(
client=client,
system_prompt="You are a helpful assistant with access to custom tools.",
tools=[],
)
class ChatRequest(BaseModel):
user_message: str
session_id: str | None = None
# Simple in‑memory session store (replace with Redis in prod)
_sessions: dict[str, list[Message]] = {}
def get_memory(session_id: str | None):
if not session_id:
return []
return _sessions.get(session_id, [])
@app.post("/chat")
async def chat(req: ChatRequest):
memory = get_memory(req.session_id)
response = await agent.run(req.user_message, messages=memory)
# Update memory
if req.session_id:
_sessions.setdefault(req.session_id, []).extend([Message(role="user", content=req.user_message), response])
return {"reply": response.content}
Run with uvicorn app.main:app --workers 4. Each worker holds its own Agent instance, which reuses the underlying HTTP connection pool to OpenAI.
Scaling beyond a single VM?
-
Serverless (AWS Lambda, Cloud Functions): The SDK works fine, but cold starts add ~200 ms overhead. Keep the
Agentobject at module level so it survives warm invocations. -
Kubernetes: Deploy the FastAPI container with a horizontal pod autoscaler (HPA) based on CPU or request latency. Remember to set
OPENAI_API_KEYas a secret and limit outbound traffic to the OpenAI endpoint to avoid unexpected egress costs.
Cost considerations: Each LLM call charges per token. If you keep a large conversation history, token usage can balloon. Trim the history or use a summarisation tool after every N turns. Also watch the number of tool invocations – each call still counts as a separate LLM request.
When NOT to use the SDK: If you need ultra-low latency (<30 ms) or run in an environment without internet access, the SDK’s reliance on remote OpenAI models makes it unsuitable. In those cases you’d need an on-prem LLM or a distilled model served locally.
Frequently asked questions
How do I debug a tool that the LLM refuses to call?
Enable SDK logging by setting AGENTS_SDK_LOG_LEVEL=debug. The logs show the model’s thought process and the exact JSON payload it tried to send. Often the issue is a mismatched parameter name or a missing required field.
Can I use the SDK with multiple OpenAI models simultaneously?
Yes. Pass a different model argument when constructing each Agent. For example, Agent(..., model="gpt-4o-mini") for cheap tasks and Agent(..., model="gpt-4o") for high-quality responses.
What’s the best way to store session memory for a large user base?
Redis is the go-to solution: store a list of serialized Message objects under a key like session:{session_id}. Set an expiration (e.g., 24 h) to avoid unbounded growth. If you already use PostgreSQL for other data, a JSONB column works too, but Redis gives you sub-millisecond reads.
Does the SDK support streaming responses?
Yes. Call agent.run(..., stream=True) and iterate over the async generator. This is useful for chat UIs that want to display partial results. Remember to forward the stream chunks to the client without buffering the whole response.
Key Takeaways
- The OpenAI Agents SDK for Python removes most of the boilerplate needed to build tool-aware agents.
- Install with
pip install agents-sdk, load your API key from.env, and you’re ready to write a single-function agent. - Use Tool objects to expose internal services; validate parameters with JSON schemas to avoid runtime errors.
- Manage state with a lightweight memory class or a persistent store like Redis; prune history to control token costs.
- Deploy with FastAPI for low-latency HTTP endpoints, or use serverless functions for bursty traffic; keep the
Agentinstance at module level to reuse connections. - Watch for hidden costs: long conversation histories, frequent tool calls, and cold-start latency in serverless environments.
By following the patterns above you can move from a notebook prototype to a production-grade AI assistant that lives alongside your existing FastAPI services, scales with Kubernetes, and stays within a predictable budget. Happy building!
Top comments (0)