Document running a Pydantic AI agent inside a reasoner with Logfire - #1065
Merged
Merged
Conversation
A Pydantic AI Agent runs inside an AgentField reasoner with no adapter, but wiring the observability so one Logfire trace covers both the Pydantic AI run and the app.ai completion is not obvious. This example does it: logfire.configure() once per process, instrument_pydantic_ai() + instrument_litellm() on that provider, and instrument_fastapi() on the Agent itself (it is a FastAPI subclass) so the inbound reasoner request is the root span. The AgentField run identifiers ride along as OpenTelemetry baggage, which Logfire copies onto every descendant span, so a trace joins back to a run without threading anything through either library's API. Pydantic AI's own token usage and cost are folded into the per-execution cost tracker so they reach AgentField's usage accounting alongside app.ai's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Issue #997 asked for Pydantic AI and Logfire integration. The Logfire half of it needs no AgentField code — what was missing is a written-down recipe for the combination, and the honest boundary around it. This documents running a Pydantic AI agent inside a reasoner with one Logfire trace per execution covering both the Pydantic AI spans and the app.ai completions, correlated to the AgentField run through OpenTelemetry baggage; how to fold Pydantic AI's tokens into AgentField's per-execution usage; how the recipe differs from AGENTFIELD_LITELLM_CALLBACKS=logfire; and what it does not give you — Pydantic AI's durable-execution adapters are not wired into AgentField's run DAG, pause/resume or replay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
AbirAbbas
force-pushed
the
docs/997-pydantic-ai-logfire
branch
from
September 21, 2026 17:26
1cbebb8 to
2c8b800
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue #997 asked for Pydantic AI + Logfire integration. Working through it, the Logfire half turns out to need no AgentField code at all — a Pydantic AI
Agentruns inside a reasoner as ordinary Python, andlogfire.configure()+instrument_pydantic_ai()+instrument_litellm()+instrument_fastapi(app)already put the Pydantic AI spans and theapp.aicompletions in one trace, becauseagentfield.Agentis aFastAPIsubclass and the reasoner request becomes the root span. What was missing was the recipe and its boundaries.So this is docs + a runnable example, not new SDK surface:
docs/pydantic-ai.md— the wiring, what the resulting trace looks like, how the AgentField run id gets onto every span (OpenTelemetry baggage, which Logfire copies into span attributes), how to fold Pydantic AI's tokens and cost into AgentField's per-execution usage, how this differs from the existingAGENTFIELD_LITELLM_CALLBACKS=logfirepath, and what it deliberately does not cover.examples/python_agent_nodes/pydantic_ai_logfire/— the same thing as a running agent node.docs/llm-observability.mdandexamples/README.md.The page is explicit that Pydantic AI's durable-execution adapters are not integrated: their checkpointing and replay sit on top of AgentField's own run DAG,
X-AgentField-Replay-*and pause/resume rather than plugging into them. That part of #997 is still an open design question, so the issue should stay open.Validation
Ran the example as a real agent node against a control plane built from this branch, in an isolated
HOME/AGENTFIELD_HOMEon a random port, with a real OpenRouter-backed model on both sides and Logfire in local mode (LOGFIRE_SEND_TO_LOGFIRE=false, console exporter plus an extra span processor dumping spans to JSONL for assertions).Each reasoner execution produced exactly one trace, for both
POST /api/v1/execute/...andPOST /api/v1/execute/async/...:Every non-root span carried
agentfield.run_id,agentfield.execution_id,agentfield.node_idandagentfield.reasonermatching the ids the control plane returned for that execution.The reasoner's usage envelope carried both calls, the Pydantic AI leg included:
{"total_cost_usd": 5.1e-05, "total_input_tokens": 112, "total_output_tokens": 57, "entries": [ {"provider": "openrouter", "model": "openrouter/openai/gpt-4o-mini", "total_tokens": 117, "cost_usd": 3.42e-05, "cost_source": "genai-prices"}, {"provider": "openai", "model": "openai/gpt-4o-mini", "total_tokens": 52, "cost_usd": 1.68e-05, "cost_source": "provider"}]}Also verified the comparison table's claims directly: with
AGENTFIELD_LITELLM_CALLBACKS=logfireandLOGFIRE_BASE_URLpointed at a local OTLP receiver, LiteLLM joined the active Logfire trace (same trace id) and emitted a singleraw_gen_ai_requestchild through its own exporter; withoutLOGFIRE_TOKENit logs a non-blocking init error and the callback does nothing.The example is
ruff check/ruff formatclean. Docs and examples only, so no SDK or control-plane gates apply.🤖 Generated with Claude Code