Pydantic AI
Auto-instrument Pydantic AI for type-safe agents.
Risicare automatically instruments Pydantic AI for type-safe agent development.
Python only
Installation
pip install risicare[pydantic-ai]
# or
pip install risicare pydantic-aiVersion Compatibility
Requires pydantic-ai >= 0.1.0.
Auto-Instrumentation
import risicare
from pydantic_ai import Agent
risicare.init()
agent = Agent(
"openai:gpt-4o",
system_prompt="You are a helpful assistant."
)
# Automatically traced
result = agent.run_sync("Hello!")What's Captured
| Feature | Description |
|---|---|
| Agent Runs | Full run/run_sync/run_stream calls |
| Model Calls | Underlying LLM API calls |
Only the model is captured on current Pydantic AI
The agent span reliably carries one framework attribute,
framework.pydantic_ai.model. Three others the integration tries to set —
framework.pydantic_ai.result_type, .tools and .system_prompt_length —
read attribute names (result_type, tools/_tools, system_prompt) that
Pydantic AI no longer exposes on the Agent object. On a current release
(measured against pydantic-ai-slim 2.31) all three are silently absent: the
reads are defensive, so nothing errors and nothing is recorded.
Tool executions and result validation are not captured as framework attributes or as child spans. You still get the underlying LLM calls as provider spans.
Span Hierarchy
pydantic_ai.agent.run/{name} (AGENT kind)
├── openai.chat.completions.create (provider span, natural child)
└── openai.chat.completions.create (provider span, natural child)
Provider Spans
Pydantic AI instrumentation creates agent/framework-level spans. Underlying LLM calls (e.g., OpenAI, Anthropic) are traced separately by provider instrumentation, giving you both framework-level and LLM-level visibility.
Structured Outputs
Type-safe outputs are captured:
from pydantic import BaseModel
class CityInfo(BaseModel):
name: str
country: str
population: int
agent = Agent(
"openai:gpt-4o",
result_type=CityInfo
)
result = agent.run_sync("Tell me about Paris")
# result.output is CityInfo, schema captured in spanTools
Tool executions are traced:
from pydantic_ai import Agent, RunContext
agent = Agent("openai:gpt-4o")
@agent.tool
def get_weather(ctx: RunContext, location: str) -> str:
"""Get weather for a location."""
return f"Sunny in {location}"
# Tool executions are not traced: no per-tool child spans are emitted, and on
# current Pydantic AI the framework.pydantic_ai.tools attribute is not set
# either (see "What's Captured" above).
result = agent.run_sync("What's the weather in Paris?")Dependencies
Dependency injection works normally with Risicare — but nothing about your dependencies is recorded:
from dataclasses import dataclass
@dataclass
class Deps:
user_id: str
api_key: str
agent = Agent("openai:gpt-4o", deps_type=Deps)
@agent.tool
def get_user_data(ctx: RunContext[Deps]) -> str:
return f"Data for {ctx.deps.user_id}"
result = agent.run_sync(
"Get my data",
deps=Deps(user_id="123", api_key="secret")
)
# No dependency is recorded on the span — not the values, not the field names,
# not the type. There is no deps capture anywhere in the SDK, so there is also
# no secret-filtering step to rely on.Streaming
async with agent.run_stream("Write a story") as response:
async for chunk in response.stream():
print(chunk, end="")Multiple Models
# OpenAI
agent = Agent("openai:gpt-4o")
# Anthropic
agent = Agent("anthropic:claude-3-sonnet-20240229")
# Gemini
agent = Agent("gemini-1.5-pro")
# Each model is traced with correct provider