How can I see which step was slow for my AI agent?
Rius shows which step was slow in the waterfall of a trace, where each step is a span on a timeline, and in the Spans tab, where you can sort every step by Duration. Each step needs to be its own span, and Rius takes its timing from the span’s start and end.
How it works
Rius records each step of an agent run as a span, and a trace is the tree of those spans. The root span’s duration is the run’s latency, so a slow run and a slow step are two different readings of the same data. See Concepts for the model.
What has to be on the spans:
- One span per step. A slow step only shows if it has a span of its own. Model calls get a span from an installed integration. Other steps get one when you wrap the function with
observe, and a tool function getsobserve(kind=SpanKind.TOOL)so it is a tool span. - A kind. Each span carries a kind (
AGENT,LLM,TOOL,RETRIEVER,EMBEDDINGorCHAIN). The kind badges the span in the waterfall and drives the kind filter on the Spans tab. The SDK sets it for you, and Rius derives it when a third-party span leaves it out. - A name. Spans are named after their operation and what it acted on, such as
execute_tool get_weather, unless you name them yourself. A readable name is what you spot when scanning for the slow row. - Nothing more for timing. Timings are metadata, so they flow even when you strip prompt and response content. A span with stripped content still shows its timing.
Where it appears in the trace view:
- Waterfall. Open a trace from the Traces page to see its spans as a tree on a timeline, badged by kind. The header gives the duration of the whole trace. LLM spans show their token counts inline, and failed spans are highlighted along the path from the root to the error.
- Map. The Map tab draws one node per span with selectable lenses for latency, cost, tokens and errors. Use the latency lens when the tree is deep. Clicking a node lands you on the tree filtered to that node’s spans.
- Span details. Select a span to open it. LLM spans get a Model section with provider, models, tokens and cost. Raw shows the span exactly as ingested. For a streamed call, the span carries
gen_ai.response.time_to_first_chunk, the seconds from its start to the first chunk, and Rius derives time to first token from it.
Exploring traces covers each view in full.
Set it up
- Give each step its own span. In this example,
observewraps the function that handles a request, and the model call inside it appears as a child span. Wrap your own tool functions withobserve(kind=SpanKind.TOOL)so they get tool spans, namedexecute_toolfollowed by the function name.
import anthropic
import rius
rius.init(api_key="ri_...", service_name="my-agent")
claude = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
@rius.observe
def handle(query: str) -> str:
response = claude.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=200,
messages=[{"role": "user", "content": query}],
)
return response.content[0].text
handle("What should I check when a collector drops spans?")- Run the agent, then open Traces in the console and click a trace. The waterfall lays out its spans on a timeline. Look for the longest span in the tree.
- Open the Map tab and pick the latency lens if the tree is deep. Click the hot node to return to the tree at that step.
- Select the slow span. Read the Model section for an LLM step, or Raw for any span.
- To find slow steps across many runs, open the Spans tab. Pick a kind in the All kinds menu, such as Tool, and click the Duration header to sort.
- When a step repeats, back-to-back calls of the same tool collapse into one row such as
fetch_article · 3 attempts · recovered. Expand it to see which attempt took the time. You can also compare the open trace with another run of the same agent to see where latency moved.
What you get
- The slow step identified by name, kind and position in the run, instead of only a slow total.
- A choice of views: the waterfall for one run, the map for a deep tree, and the Spans tab for sorting steps across runs.
- Keyboard stepping through spans, with
]land[ljumping between LLM spans and]eand[ebetween failed ones. - A context growth strip above the tree for traces with several LLM calls. It plots input tokens per call, so a slow call with a swollen prompt stands out.
- Visibility of a step that is still running. With partial spans enabled, a started span is exported as a snapshot, so a trace shows as running… until it finishes. A step that never finishes stays visible.
When something else fits
The trace view answers questions about one run or one kind of step. For latency trends across all runs, use the usage and cost view, which reports time to first token at p50 and p95, and see Monitor AI agents in production. Heartbeats show that a process is alive, not that it is making progress, so a hung process that still sends heartbeats shows as running.