Use this file to discover all available pages before exploring further.
The OpenAI Agents SDK (openai-agents Python package) is the AI backbone of this workshop. It gives you a high-level API for building LLM-powered agents that can call tools, hand off to other agents, and produce structured outputs—without managing raw API requests yourself. This page explains every SDK primitive you will use across the four workshop exercises.
An Agent is the central object in the SDK. You construct one by declaring its identity, behaviour, and capabilities:
from agents import Agentagent = Agent( name="Weather Agent", instructions="You help users get weather alert information for US states. " "Use the get_weather_alerts tool to fetch real data from the " "National Weather Service.", tools=[get_weather_alerts],)
Parameter
Type
Purpose
name
str
Human-readable label; appears in OpenAI traces
instructions
str
System prompt that shapes the agent’s behaviour
tools
list
Functions the LLM can invoke (decorated with @function_tool)
model
str
OpenAI model to use, e.g. "gpt-4" (defaults to gpt-4o)
Runner.run() is an async method that drives the full agent loop—sending the user query to the LLM, executing any tool calls the LLM requests, feeding results back, and repeating until the LLM produces a final answer.
from agents import Runnerresult = await Runner.run(agent, "Are there any weather alerts for California?")print(result.final_output)# → "There are currently 2 active weather alerts for California: ..."
The returned object exposes .final_output (the agent’s last text response) and .new_messages (the full message history for that run).
@function_tool converts any async Python function into a tool the LLM can call. The docstring becomes the tool description that the LLM reads to decide when to use it; type hints become the JSON schema for the tool’s parameters.
from agents import function_toolimport httpx@function_toolasync def get_weather_alerts(state: str) -> str: """ Get current weather alerts for a US state from the National Weather Service. Args: state: Two-letter US state code (e.g., 'CA', 'NY', 'TX') Returns: String describing current weather alerts """ url = f"https://api.weather.gov/alerts/active/area/{state.upper()}" headers = {"User-Agent": "OpenAI-Agents-Workshop (educational)"} async with httpx.AsyncClient() as client: response = await client.get(url, headers=headers, timeout=10.0) response.raise_for_status() data = response.json() features = data.get("features", []) if not features: return f"No active weather alerts for {state.upper()}." alerts = [] for feature in features[:5]: properties = feature.get("properties", {}) event = properties.get("event", "Unknown") headline = properties.get("headline", "No headline") severity = properties.get("severity", "Unknown") alerts.append(f"- {event} ({severity}): {headline}") return f"Active weather alerts for {state.upper()}:\n" + "\n".join(alerts)
The docstring is the tool’s “manual” for the LLM. Write it clearly and include the expected input format—the LLM uses it to decide when and how to call the tool.
Understanding the execution loop is key to reasoning about agent behaviour:
User query submitted to Runner.run() ↓ LLM receives query + tool definitions ↓ LLM decides: answer directly OR call a tool ↓ (if tool chosen) SDK invokes the Python function ↓ Tool result appended to message history ↓ LLM generates next response ↓ (loop repeats if another tool call) LLM produces final text response ↓ result.final_output returned to caller
The LLM decides autonomously whether to use a tool on each turn. Your Python code handles the mechanics; the model handles the reasoning.
The handoffs parameter lets an agent transfer control to a specialist agent. The receiving agent takes over the conversation from that point. This pattern powers Exercise 4’s language-routing workflow:
from agents import Agentdef french_agent() -> Agent: return Agent( name="French Agent", instructions="You only speak French. Respond naturally to user queries in French.", model="gpt-4", )def spanish_agent() -> Agent: return Agent( name="Spanish Agent", instructions="You only speak Spanish. Respond naturally to user queries in Spanish.", model="gpt-4", )def english_agent() -> Agent: return Agent( name="English Agent", instructions="You only speak English. Respond naturally to user queries in English.", model="gpt-4", )def triage_agent() -> Agent: return Agent( name="Triage Agent", instructions=( "Identify the primary language of the user's message. " "Never answer directly. " "Immediately hand off using one of the following rules: " "- French → French Agent " "- Spanish → Spanish Agent " "- English → English Agent " "If detection is uncertain or the language is unsupported, hand off to English Agent." ), handoffs=[french_agent(), spanish_agent(), english_agent()], model="gpt-4", )
When Runner.run() executes the triage agent and a handoff is triggered, the SDK transparently continues execution with the specialist agent—no extra code required.
trace() is a context manager that groups all SDK operations inside it under a single named trace in the OpenAI dashboard. In Exercise 4 it is used directly inside the Temporal workflow:
The trace() name appears in the OpenAI platform under Traces, letting you correlate a Temporal workflow execution ID with its corresponding LLM calls — invaluable for debugging production agents.
This is the pattern used in Exercise 4 where the workflow receives an arbitrary string and wraps it into a properly typed message list before handing it to the runner.