Skip to Content

How do I see which step was slow in an agent built with the OpenAI Agents SDK?

Rius shows which step of an OpenAI Agents SDK run was slow as the span with the longest duration in the trace waterfall. Rius captures the model calls the framework makes on its own, and you add observe wrappers around the entrypoint and the tool bodies so the run and each tool get spans with their own timings. Open the trace to read each span’s duration, or sort the Spans tab by Duration to put the slowest steps first.

How it works

The OpenAI Agents SDK drives the OpenAI client underneath, so the openai instrumentation captures its model calls without framework-specific code. Each model call arrives as an LLM span with its own duration. Tokens and cost appear when the call reports usage. Streamed runs need include_usage enabled on the underlying client to carry token counts.

The framework keeps two things to itself, so they need a line of your own:

  • The run structure. The agent loop and tool executions run inside the framework. Wrapping the entrypoint and each tool body with observe adds an AGENT root span and TOOL spans, each with its own duration.
  • Handoffs. A handoff produces no span of its own. It shows only as consecutive model calls that belong to different agents.

A run that crosses a handoff reads like this in the trace:

handle-ticket AGENT 9.8s ├─ Response LLM 2.3s triage decides to hand off ├─ Response LLM 2.8s billing agent decides to call the tool ├─ execute_tool account_status TOOL 0ms └─ Response LLM 4.6s billing agent answers

The slow step here is the last model call, 4.6s of the 9.8s run. Model calls from the Responses API are all named Response, so you tell them apart by position and by the Input / Output tab, not by name.

Set it up

  1. Install the SDK with the OpenAI extra and the framework:
pip install "glassflow-rius[openai]" openai-agents
  1. Wrap the entrypoint as an AGENT span and each tool body as a TOOL span. Put @function_tool outermost and observe on the function body, because the framework reads the function signature for its tool schema. Use underscores in agent names, since hyphens are rewritten in the generated handoff tool name.
import rius from agents import Agent, Runner, function_tool, set_tracing_disabled from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") set_tracing_disabled(True) def lookup(email: str) -> str: return "active" # replace with your own account lookup @function_tool @rius.observe(kind=SpanKind.TOOL) def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) support_agent = Agent( name="support_agent", instructions="Answer support questions; check accounts with the tool.", tools=[account_status], model="gpt-5-mini", ) @rius.observe(name="handle-ticket", kind=SpanKind.AGENT) def handle_ticket(ticket: str) -> str: result = Runner.run_sync(support_agent, ticket) return str(result.final_output)
  1. Run one request that calls a tool, then open the trace in the console. The root AGENT span, the LLM spans and your named TOOL spans should all be there.

  2. Find the slow step. In the waterfall, compare span durations along the timeline. On the Spans tab, filter with the All kinds menu to Tool or LLM and click the Duration header to sort. In the Map tab, pick the latency lens to see the hot spot as a graph, then click the node to land on its spans in the tree. Exploring traces covers each view.

  3. If handoff boundaries matter, add an observe wrapper per agent entry, or use the framework’s RunHooks to open spans at agent boundaries. That gives each agent’s share of the run its own duration.

What you get

  • A duration for every span you can see: model calls, your tools and the whole run.
  • A waterfall that shows where the time went inside one run, and a map with a latency lens for deep traces.
  • A sortable Spans tab that ranks the slowest tool calls or model calls across many runs.
  • Tokens and cost on model calls that report usage, next to their timing, so you can tell a slow call from an expensive one.
  • Named TOOL spans, so you see which tool was slow rather than only that a model call waited on one.

For how this fits into watching agents beyond a single trace, see Monitor AI agents in production.

When something else fits

  • If handoffs are your main question, the automatic capture alone is not enough, since a handoff has no span. Add a wrapper per agent entry as described above.
  • If your agent uses another client library or framework, the Integrations page lists what each one records on its own. The OpenAI Agents SDK integration page has the full list of blind spots for this framework.

Still stuck? Get help

Last updated on