Skip to Content

How do I see one whole conversation in an agent built with Pydantic AI?

Rius groups every run of a Pydantic AI agent into one conversation when you wrap each run in rius.session() with your conversation id. Pydantic AI records the run, the model requests and the tool calls itself, and the session ties the runs together. You then open the conversation from the Session link in any trace header, or by pasting the id into the Spans tab. This is part of how you monitor AI agents in production.

How it works

Pydantic AI is OpenTelemetry-native, so the Pydantic AI integration needs no extra and no wrappers. rius.init() installs the global OpenTelemetry tracer provider, and Agent.instrument_all(True) tells Pydantic AI to emit its spans through it.

What Pydantic AI records on its own:

In the frameworkIn the trace
An agent runThe root span, named invoke_agent <agent name>
A model requestA generation named chat <model>, with tokens and cost
A tool callA span named execute_tool <tool name>

A run that calls one tool looks like this:

invoke_agent support_agent 6.0s ├─ chat gpt-5-mini 3.3s decides to call the tool ├─ execute_tool account_status 0ms └─ chat gpt-5-mini 2.7s answers

Rius computes cost on its side from the model and token counts. Time to first token and reasoning tokens show up for Pydantic AI runs too.

What needs something of your own: the conversation itself. Each call to the agent is a separate run, and each run is a separate trace. The one thing that joins them is a session id, which you set with rius.session(), reusing your own conversation id. The framework’s spans inherit the scope like any other span. Without a session, a trace is its own session, so a multi-turn chat shows up as unrelated traces.

Set it up

  1. Install the SDK with pip install glassflow-rius pydantic-ai. No extra is needed for Pydantic AI. The installation and integrations overview covers the shared setup in full.
  2. Initialize Rius, turn on Pydantic AI’s instrumentation, and wrap every run of the same conversation in rius.session() with the same id. Here conversation_id, ticket and lookup are your own names:
import rius from pydantic_ai import Agent rius.init(api_key="ri_...", service_name="my-agent") Agent.instrument_all(True) support_agent = Agent( "openai:gpt-5-mini", instructions="Answer support questions; check accounts with the tool.", ) @support_agent.tool_plain def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email) with rius.session(conversation_id): result = support_agent.run_sync(ticket)
  1. On every later turn of the same conversation, run the agent inside rius.session() with the same conversation_id. A new conversation gets a new id.
  2. Run one request that calls a tool, then open the trace in the console. You should see the invoke_agent root, the chat generations with model, tokens and cost, and the execute_tool spans.

Agent.instrument_all(True) switches instrumentation on for every agent. Per-agent control and content settings live on the framework’s InstrumentationSettings.

What you get

  • The whole conversation in one place. In a trace’s header, the Session link opens the Spans tab filtered to that session, so every span from every turn is in one list. You can also paste the session id into the Spans search box, which matches span names, span IDs, trace IDs and session IDs. See Exploring traces for the full walkthrough.
  • One turn as a tree. Open any trace to see the run in the waterfall: the invoke_agent root, each chat generation with tokens inline, and each execute_tool span. Failed spans are highlighted along the path from the root to the error.
  • What each step added to the prompt. On a chat span with captured messages, Since previous llm call on the Input / Output tab shows what changed since the trace’s previous model call. In an agent loop that appends to one conversation, you see what each step added, and a dropped turn or a rewritten system prompt stands out.
  • Context growth. For a trace with several model calls, a strip above the tree plots input tokens per call in order, which is where an unbounded history shows up first.
  • Cost and tokens per call. Cost is a list-price estimate in US dollars.

Two things to know. Successful spans from Pydantic AI arrive with an UNSET status rather than OK, and the trace status still reads Ok. And what the spans carry, such as prompts, completions and tool arguments, is controlled first by Pydantic AI’s InstrumentationSettings (for example include_content), on top of the SDK’s own privacy controls.

When something else fits

  • If you only need to understand a single run, the trace waterfall already shows it and you can skip the session.
  • If you cannot use the Rius SDK, Pydantic AI also works with any OpenTelemetry setup pointed at the ingest endpoint, but you then lose the SDK’s session helper and exporter wiring.
  • If your agent uses a different framework, the integrations overview lists how each one is covered.

Still stuck? Get help

Last updated on