Skip to main content

Hooks or OpenTelemetry?

A Pydantic AI agent can be traced with TraceAgent in two ways: the Pydantic AI capability (hooks) or OpenTelemetry. Both end up in the same place: a run with its model calls, tools and tokens.

Choose in ten seconds
  • Already on OpenTelemetry, or you can't touch the agent's code? Use OpenTelemetry.
  • Want fine control over what is recorded, or no OpenTelemetry in your stack? Use the capability.

Side by Side​

Capability (hooks)OpenTelemetry
What you installtrace-agent-sdk and trace-agent-pydantic-ai in the agent's environmentOnly the OpenTelemetry SDK and OTLP exporter. Nothing from TraceAgent in the agent
What changes in the agentstart_run(...), capabilities=[run.as_pydantic_ai_capability()] and run.finish() / run.fail()A tracer provider with the OTLP exporter, Pydantic AI's Instrumentation, and provider.shutdown() in short scripts. No run to manage
Who creates the runYou, with start_run: you choose its name and goalThe server, one run per trace: named after the agent, with the first user message as its goal when the content is exported
Control over what is sentredact_fields and the record_*_events optionsinclude_content=False on the agent side to keep prompts and outputs out; TRACE_AGENT_CAPTURE_FULL_PAYLOADS on the server
Works withPydantic AI 2.x onlyPydantic AI 2.x verified. Other frameworks that emit GenAI spans may work, unverified

Choose It When​

Use the capability if you want per-agent control (redaction, what is recorded), you don't use OpenTelemetry, or you want to manage runs yourself.

Use OpenTelemetry if you already use OpenTelemetry (or Logfire), you can't or don't want to change the agent's code, or the agent runs in another service.

One Route per Agent​

Use one, never both

For a given agent, use either the capability or OpenTelemetry. Both record every model call and tool, and they don't know about each other, so the run would appear twice.

There is one combination that is not "using both": create the run with the SDK and let OpenTelemetry supply the spans. Pass the run id in the trace_agent.run_id resource attribute (see Attach to a Run Created with the SDK). In that case, don't add the capability.

What Differs in the Run​

With structured output (output_type=SomeModel), both routes record exactly the same run.

There is one known, intentional difference. If the agent's output goes through an output function (output_type=my_function), Pydantic AI emits a tool span for it (final_result by default):

  • OpenTelemetry records it as one more tool, so the tool count goes up by one and a final_result decision appears.
  • The capability only wraps the agent's regular tools, so it doesn't record it.

What's Next?​

💬 Comments