Pydantic AI is a GenAI agent framework "the Pydantic way" — Python-first, model-agnostic, and integrates natively with the Pydantic validation library and the Logfire observability platform. Strong fit if you already use Pydantic heavily and want validated, typed agent outputs.
pip install pydantic-ai
# For provider integrations you care about:
pip install pydantic-ai[openai,anthropic,google]
# API keys
export ANTHROPIC_API_KEY=sk-ant-...
# or
export OPENAI_API_KEY=sk-...Python 3.10+ required.
@agent.toollogfireA typed extraction agent:
from pydantic import BaseModel
from pydantic_ai import Agent
class Article(BaseModel):
title: str
author: str
summary: str
score: int # 1-10
agent = Agent(
'claude-sonnet-4-6',
output_type=Article,
system_prompt="Extract title, author, summary (2 sentences), and score (1-10) from the text.",
)
result = agent.run_sync("""
By Jane Doe: Anthropic ships background agents for Claude Code, enabling
multi-hour autonomous runs with full tool access...
""")
print(result.output.title) # "Anthropic ships background agents for Claude Code"
print(result.output.score) # 8No manual schema, no JSON parsing, no prompt engineering for output format — the Pydantic BaseModel is the schema and the contract.
from pydantic_ai import Agent, RunContext
agent = Agent('claude-sonnet-4-6', system_prompt="You are a weather agent.")
@agent.tool
async def get_weather(ctx: RunContext, city: str) -> dict:
"""Get current weather for a city."""
# ...
return {"temp_f": 72, "conditions": "sunny"}
result = await agent.run("What's the weather in Tokyo?")When a single agent isn't enough — branching, looping, persistence:
from pydantic_graph import Graph, BaseNode, End
class ResearchNode(BaseNode):
async def run(self, ctx) -> 'SummarizeNode':
# ... research logic
return SummarizeNode()
class SummarizeNode(BaseNode):
async def run(self, ctx) -> End[str]:
# ... summarize
return End("final answer")
graph = Graph(nodes=[ResearchNode, SummarizeNode])
result = await graph.run(ResearchNode(), state=my_state)Graphs are appropriate when a typed control flow beats prompt-driven handoffs.
Bring your own provider — Pydantic AI is deliberately model-agnostic:
Switch providers by changing the string: Agent('claude-opus-4-7') → Agent('openai:gpt-5') → Agent('google-gla:gemini-3-1-pro').
Install logfire, set your token, get automatic tracing:
import logfire
logfire.configure()
logfire.instrument_pydantic_ai()
# Every agent.run now appears in Logfire with full traces.Search for a command to run...