Skip to Content

How do I see token counts for each call in an agent built with Pydantic AI?

Rius records tokens for every model request in a Pydantic AI agent once you call rius.init() and Agent.instrument_all(True), with no extra spans or attributes. Each model request arrives as its own span with input and output tokens and a computed cost. You read the counts inline in the trace tree, in the span’s Model section, and in the totals on the trace list. Nothing of your own is needed for tokens.

How it works

Pydantic AI is OpenTelemetry-native and emits its own spans for agent runs, model requests and tool calls. rius.init() installs the global OpenTelemetry tracer provider, and Agent.instrument_all(True) tells Pydantic AI to send its spans through it. No auto-instrumentation extra is involved.

The framework provides the structure, and Rius reads its OpenTelemetry GenAI attributes directly:

  • An agent run becomes the root span, named invoke_agent followed by your agent’s name.
  • A model request becomes a generation named chat followed by the model name. This is the span that carries the token counts, and Rius computes its cost from the model and those counts.
  • A tool call becomes a span named execute_tool followed by the tool name. It carries no tokens, because it is not a model call.

A run that calls one tool shows two chat generations, one that decides to call the tool and one that answers, each with its own tokens. Reasoning tokens and time to first token also show up for Pydantic AI runs, with glassflow-rius 1.0.2 or later and 1.0.1 or later respectively.

There is nothing to add yourself. The framework already creates the generations, so a manual generation around the same call is not needed.

Set it up

  1. Install the SDK. Pydantic AI needs no extra, so the base package is enough:
pip install glassflow-rius pydantic-ai
  1. Call rius.init() before you build your agents, then switch Pydantic AI instrumentation on for every agent:
import rius from pydantic_ai import Agent rius.init(api_key="ri_...", service_name="my-agent") Agent.instrument_all(True) def lookup(email: str) -> str: return "active" # replace with your own account lookup 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) conversation_id = "conv-123" ticket = "Is the account for ana@example.com in good standing?" with rius.session(conversation_id): result = support_agent.run_sync(ticket)

Replace lookup, conversation_id and ticket with your own. The rius.session() scope groups the run’s spans under your conversation id.

  1. Run one request that calls a tool, then open Traces in the console. You should see the invoke_agent root, the chat generations with model, tokens and cost, and the execute_tool spans.

  2. Read the counts where they appear, as described in the next section. For per-agent control, use the framework’s own InstrumentationSettings. The full setup is on the Pydantic AI integration page, and the other frameworks and libraries are listed under Integrations.

What you get

Token counts show up in several places in Exploring traces:

  • Trace list. Each row shows a token total and a computed cost for the run. The strip above the list sums tokens and cost for the traces that match your filters.
  • Waterfall view. Open a trace and the chat spans show their token counts inline in the tree. The header gives total tokens and cost for the whole trace.
  • Span detail. Select a chat span and its Model section lists provider, requested and response model, input and output tokens, and cost.
  • Spans tab. Filter with the All kinds menu to LLM and sort by the Tokens header to find the heaviest calls across all runs.
  • Context growth. For a trace with several model calls, a strip above the tree plots input tokens per call in order. Click a bar to select that call. This is where a growing history shows up first.
  • Map view. The tokens lens colors each span by its token use.

Cost is a list-price estimate in US dollars. A call that reported no token usage shows a blank cost rather than $0, so it does not look free. If you strip prompt and completion content with the privacy controls, or the framework’s include_content setting leaves it out, the span still carries its tokens and cost. Content capture on Pydantic AI spans is set by the framework’s InstrumentationSettings.

One quirk to know: successful Pydantic AI spans arrive with an unset status rather than OK, and the trace status still reads Ok. The integration notes were checked against pydantic-ai-slim 2.36.0.

For how this fits a wider monitoring setup, see Monitor AI agents in production.

When something else fits

  • If your agent calls a model outside Pydantic AI, for example with a provider client of your own, that call needs its own integration or a manual generation, which must set its own usage to carry tokens.
  • If you want counts without any framework, trace the model calls through a client-library integration listed under Integrations, or use any OpenTelemetry SDK that follows the GenAI conventions.

Still stuck? Get help

Last updated on