Skip to Content

Pydantic AI

Trace agents built with Pydantic AI  with Rius: the framework is OpenTelemetry-native and emits its own spans for agent runs, model requests, and tool calls, so the whole structure arrives with no wrappers at all. This guide covers the Python framework; the runnable example behind it lives in agent-observability-examples .

How coverage works

This integration works the other way around from the client-library ones: no auto-instrumentation extra is involved. rius.init() installs the global OpenTelemetry tracer provider, and Agent.instrument_all(True) tells Pydantic AI to emit its spans through it. The framework provides the run root, the generations, and the tool spans itself; Rius reads its OpenTelemetry GenAI attributes natively and computes cost server-side.

Setup

pip install glassflow-rius pydantic-ai

No extra is needed. If your project uses the base SDK only, that is enough.

import rius from pydantic_ai import Agent rius.init(api_key="gf_...", 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)

instrument_all switches instrumentation on for every agent; per-agent control and content settings live on the framework’s InstrumentationSettings.

What lands where

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 a tool looks like this (real trace from the example, pydantic-ai-slim 2.36.0):

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

Compared to frameworks covered through a client-library integration, this is the richer default: spans are named after your agents, models, and tools, and tool calls appear without any wrapping.

Quirks

Verified against pydantic-ai-slim 2.36.0:

  • Span statuses arrive UNSET rather than OK on successful spans; the trace status still reads Ok.
  • Content capture is framework-side. What the spans carry (prompts, completions, tool arguments) is controlled by Pydantic AI’s InstrumentationSettings (for example include_content), on top of the SDK’s own privacy controls at export time.

Sessions

One conversation is one session: scope each run with rius.session(), reusing your conversation id. The framework’s spans inherit the scope like any other span.

Verify

Run one request that calls a tool, then open the trace in the console: the invoke_agent root, chat generations with model, tokens, and cost, and execute_tool spans should all be there.

Using Pydantic AI without the Rius SDK works too: point any OTel setup at the ingest endpoint per vanilla OpenTelemetry SDKs. The SDK path above adds the exporter wiring, sessions, heartbeats, and privacy controls for free.

Last updated on