Skip to main content

Install

Supported: pydantic-ai-slim 2.0 to 3.0. 2.0 removed Agent(instrument=...) and introduced the capability protocol this adapter is built on, so 1.x cannot be instrumented this way.

Instrument

instrument() must run before you construct an Agent. The capability is appended at construction, so an agent built earlier carries none and records nothing, with no error because nothing went wrong. This is the most common cause of an empty trace with this adapter.
Module-scope agents are where this bites:
Confirm it took:
Pydantic AI merges the list you pass into a single root_capability, so there is no agent.capabilities attribute to read. Agents built while instrumented keep the capability, so you can uninstrument() and re-instrument without rebuilding them.

What gets recorded

There is no hook pair and no human-in-the-loop pair here. Pydantic AI has no node or step boundary to bracket and no built-in human pause, so there is nothing to map. If you build either, emit the events yourself — see Custom agents. output_type makes no difference to the trace. A typed run and a string run produce the same events.

Example

In the trace, restock_eta appears as a tool_result carrying an error, followed by another model call where the agent works around it, and the run still ends success. Both facts are kept.

Errors, retries, and control flow

Pydantic AI raises exceptions for three different things, and the adapter separates them: ModelRetry is in the first group deliberately. It means an attempt genuinely failed and the model was asked to try again, which is what a tool span’s error field is for. Classifying it as control flow would hide real tool failures behind a green run.

Name your spans

Pydantic AI’s own run span is named agent. Wrap the call to give it a label you chose:
The framework’s span then nests under inventory, and that is where the model and tool events hang. Keep agent_id low cardinality. It is the primary facet on every dashboard surface, so use a role name, never a UUID or per-run string.

Control the session

Resolved in this order, first match winning:
  1. instrument("pydantic_ai", session_id=...)
  2. The enclosing failproofai_sdk.session() scope
  3. The run’s conversation_id, then its run_id
  4. A generated uuid4().hex

Options

Common problems

The Agent was constructed before instrument() ran. See the warning above, and check agent.root_capability.capabilities.
A bare raise propagates; that is Pydantic AI’s design. To let the model work around it, raise ModelRetry with a message it can act on. The failure is recorded either way.
That child is Pydantic AI’s own run span, and it is where the model and tool events hang. Drop your own scope if you want a single span, at the cost of the custom name.
Pydantic AI’s async graph stack is longer than the payload field limit, and a traceback’s last line is the exception itself. This field is trimmed from the front rather than the back, so the line you need survives.

Next

How it works

Pairs, ids, session lifecycle, and delivery.

Read a trace

Follow causality through the session you just captured.

Other frameworks

LangGraph, CrewAI, LlamaIndex, and custom agents.