Pydantic AI v2: Build and Ship Production Python Agents

Pydantic AI v2: type-safe Python agents with structured outputs, DI, and Logfire. Covers v2.0.0 Capabilities, deterministic evals, and LangChain comparison.

Updated 13 min read
Pydantic AI homepage — type-safe Python agent framework

Pydantic AI is a production-grade, open-source Python agent framework that brings type-safe structured outputs, dependency injection, and model-agnostic LLM orchestration to Python automation workflows. Built by the team behind Pydantic, the validation library inside nearly every major Python AI SDK, it crossed 17,969 GitHub stars and 30 million monthly downloads as of June 2026.

The latest release, v2.0.0, shipped June 23, 2026, and introduces the Capabilities API: composable bundles of instructions, tools, hooks, and model settings you attach to any agent.

This guide covers Pydantic AI from first install through production observability, including where it breaks (local models, streaming cancellation) and where it outperforms alternatives (typed outputs, testability, eval pipelines).

Key Takeaways

  • Pydantic AI guarantees typed, Pydantic-validated outputs instead of raw strings, eliminating an entire class of JSON parse errors in production.
  • The dependency injection system (via RunContext) makes agents unit-testable with TestModel without burning API credits or mocking LLM responses.
  • v2.0.0's Capabilities API bundles tools, instructions, lifecycle hooks, and model settings into composable units that load on demand via defer_loading=True.
  • For local or smaller models (Mistral-7B, Qwen 3.6B), structured output via tool calling fails non-gracefully; smolagents handles local inference more reliably.

What Is Pydantic AI?

Pydantic AI is a Python-first framework for building AI agents that return validated, typed outputs rather than unstructured strings. The design philosophy, stated in the official docs, is to bring "the FastAPI feeling to GenAI app and agent development."

Samuel Colvin, the creator of both Pydantic and Pydantic AI, observed that virtually every Python AI framework was already built on Pydantic validation, yet none felt as ergonomic as FastAPI. Pydantic AI fills that gap.

The library is MIT-licensed, model-agnostic, and Python-native (requires Python ≥ 3.10). Sequoia Capital led the $12.5M Series A in 2024, bringing total funding to $17.2M. Enterprise customers include Meta, Microsoft, NVIDIA, JPMorgan Chase, Atlassian, Cisco, Duolingo, and NATO.

Why Pydantic AI Matters in 2026

Interest in Pydantic AI hit its 12-month all-time peak in May 2026 (Google Trends: 100/100) and was still at 89/100 in June 2026, up from a baseline of ~41 in June 2025. That doubled interest tracks a practical shift: teams that shipped LangChain prototypes in 2024-2025 are now refactoring toward production backends that need type guarantees, not prototype chains.

Sebastián Ramírez (@tiangolo) quoted an OpenAI engineer in July 2025: "Pretty much everything operates around FastAPI to create APIs and Pydantic for validation."

If your production stack already runs on FastAPI and Pydantic models, adding Pydantic AI is a pattern extension, not an architecture overhaul.

The v2.0.0 release, published June 23, 2026, adds the Capabilities API, progressive disclosure for large tool libraries, and improved multi-agent ergonomics. The v2.0.0 changelog is the authoritative source for any breaking changes from v1.

How Pydantic AI Works: Core Architecture

Pydantic AI organizes agent behavior around five primitives. Each is a plain Python construct, not a custom DSL.

Agents

The Agent class is the primary developer interface: a stateless container bundling instructions, tools, structured output type, dependency type, and model settings.

Component

Role

Instructions

System prompts, static or dynamic via @agent.system_prompt

Function tools

Python functions the LLM can call, typed via @agent.tool

Structured output

Pydantic model defining the required return type

Dependency type

Typed runtime context for tools and prompts

LLM model

Default model (overridable per run)

Capabilities (v2)

Composable bundles of the above

Agents are stateless: they hold no conversation state between runs. Treat them as global objects. Create one per task type, not one per request.

Instructions vs. system prompts: instructions are the recommended default. When message_history is provided, only the current agent's instructions are sent to the model; prior agents' system prompts are excluded. Use system prompts only when you explicitly want prior context retained across multi-turn workflows.

Structured Outputs

Structured output is Pydantic AI's core capability. You define a Pydantic model; the framework guarantees a typed Python object back, not a string:

Python
from pydantic import BaseModel
from pydantic_ai import Agent

class CityLocation(BaseModel):
    city: str
    country: str

agent = Agent('google:gemini-3-flash-preview', output_type=CityLocation)
result = agent.run_sync('Where were the 2024 Olympics held?')
print(result.output)
# CityLocation(city='Paris', country='France')

The workflow: Pydantic AI builds a JSON Schema from your model, passes it to the LLM, validates the response, and resends validation errors back to the model for correction, all automatically. If the model can't produce a valid response after retries, it raises an exception. You never write a JSON parse loop.

Dependency Injection

Pydantic AI's DI system, inspired by FastAPI, supplies data and services to system prompts, tools, and output validators via typed RunContext:

Python
from dataclasses import dataclass
import httpx
from pydantic_ai import Agent, RunContext

@dataclass
class MyDeps:
    api_key: str
    http_client: httpx.AsyncClient

agent = Agent('openai:gpt-5.2', deps_type=MyDeps)

@agent.tool
async def fetch_data(ctx: RunContext[MyDeps], endpoint: str) -> str:
    response = await ctx.deps.http_client.get(
        endpoint, headers={'Authorization': ctx.deps.api_key}
    )
    return response.text

The testing benefit is direct: swap httpx.AsyncClient for a mock without touching the agent or the LLM. Tests run deterministically and don't burn API credits.

Function Tools

Any typed Python function with a docstring becomes a callable tool for the LLM. Pydantic AI auto-generates the JSON schema from type hints. The docstring tells the model when to invoke the tool; the type hints define the interface.

Tool calls (arguments and return values) are automatically traced in Logfire and any OpenTelemetry-compatible backend.

Capabilities (v2.0.0)

The Capabilities API is the headline feature of v2.0.0 (June 23, 2026). A Capability bundles an agent's instructions, tools, lifecycle hooks, and model settings into one composable unit.

Pydantic described Capabilities on LinkedIn (June 23, 2026): "v2 turns the layer around the agent loop into one thing you compose: the capability."

Progressive disclosure (defer_loading=True) takes this further: a capability's tools, instructions, and hooks load only when the model requests them. For agents with large tool libraries, this keeps context lean and reduces token costs on every run.

Multi-Agent Patterns

Pydantic AI supports five levels of multi-agent complexity, from simplest to most complex:

  • Single agent workflows: one agent, one run. The most common pattern.
  • Agent delegation: one agent calls another as a function tool.
  • Programmatic hand-off: application code routes between agents based on logic.
  • Graph-based control flow: state machines for branching pipelines.
  • Deep Agents: autonomous planning, file operations, task delegation, sandboxed code execution.

Because agents are stateless, they can call each other freely without circular dependency concerns. Logfire traces the full chain: which agent handled which step, delegation decisions, latency per agent, and token usage per agent.

Samuel Colvin, initially skeptical of graph-based orchestration, changed his position after seeing real-world use cases:

We've just released @Pydantic AI v0.0.19. This comes with the biggest new feature since we announced PydanticAI — graph support! I was originally cynical about graphs, but I'm now really excited about their use cases, both with GenAI and in general purpose development. Our https://t.co/UHSoF8lyWG
Samuel Colvin · @samuelcolvinView on X

The MCP integration extends reach further. Pydantic AI acts as an MCP client, connecting to any local or remote MCP server. Colvin also added sandboxed Python execution via an MCP server backed by Pyodide:

Weekend work - I've added an MCP server to @pydantic AI to run Python in a @pyodide sandbox. Should allow us to provide a "coding agent" similar to smolagents, except properly sandboxed and therefore safe. https://t.co/UjbH8SHm3n
Samuel Colvin · @samuelcolvinView on X

AG-UI protocol integration streams live agent activity to frontend applications (built with the CopilotKit team), enabling real-time agent status in web UIs without custom WebSocket wiring.

Observability: Pydantic Logfire

OpenTelemetry tracing is built into Pydantic AI; no extra instrumentation configuration required. Any OTel-compatible backend works. Pydantic Logfire is the tightest integration; a single call instruments the full stack:

Python
import logfire
logfire.instrument_pydantic_ai()

What Logfire captures per run:

  • Messages exchanged with the model (system, user, assistant)
  • Tool calls: arguments and return values
  • Token usage per request and cumulative
  • Latency for each operation
  • Errors with full context
  • Multi-agent delegation traces end-to-end

Logfire pricing (revised January 2026):

Plan

Price

Spans/month

Personal

$0

10 million

Team

$49/mo

Higher limits

Growth

$249/mo

Higher limits

Enterprise Self-hosted

Custom

Unlimited

Overage

$2.00/million spans

N/A

Logfire migrated its backend from Timescale to Apache DataFusion in 2024 for better open-source alignment and query performance. The free tier (10M spans/month) was large enough that teams were running production workloads on it entirely, which prompted the January 2026 pricing revision.

One recurring pain point: the logfire.instrument_pydantic_ai() one-liner is Logfire-specific. Plugging in a custom OTel tracing stack works at the protocol level, but the integration documentation is thinner. Plan for setup friction if your team runs a non-Logfire OTel backend.

Testing and Evaluation with Pydantic Evals

Pydantic Evals is a code-first testing framework for evaluating agent behavior against golden datasets:

Python
from pydantic_evals import Case, Dataset

dataset = Dataset(
    name='agent_eval',
    cases=[
        Case(
            name='capital_question',
            inputs='What is the capital of France?',
            expected_output='Paris'
        ),
    ]
)
report = dataset.evaluate_sync(my_agent_function)

When combined with Logfire, eval results appear in the Logfire UI for visualization and regression tracking. The key design choice is deterministic evaluation against golden datasets, not LLM-as-judge. Colvin at AI Engineer 2026:

"The LLM as a judge is effectively the kind of lunatics running the asylum… if you can have a deterministic eval like this where we're comparing what the result is versus a golden data set, that's much better."

Samuel Colvin in "Agent Optimization with Pydantic AI: GEPA, Evals, Feedback Loops" (AI Engineer, 18:36)

GEPA: Genetic Algorithm Prompt Optimization

GEPA (Genetic Evaluation-based Prompt Adaptation) iterates eval variants, measures each against a golden dataset, and evolves toward higher-scoring prompts, without touching the model or redeploying. Pydantic posted results on LinkedIn (June 2026):

  • Naive prompt: 87% accuracy
  • Hand-crafted prompt: 92%
  • GEPA-optimized: 96.7% (same model, no redeployment)

That 9.7-percentage-point gain on the same model illustrates why systematic evaluation outperforms ad-hoc prompt tweaking. Most teams skip building a golden dataset because the upfront effort feels high.

Start with 20-50 hand-labeled examples from production traces. Colvin's own demo assembled initial labels using Claude Opus, then reviewed them manually; imperfect but immediately useful for GEPA to optimize against.

The clinical RAG deployment built by Vstorm and Schmitt-Thompson Clinical Content illustrates the production ceiling: a four-stage agentic RAG pipeline on Pydantic AI for nurse triage guidelines, validated across 329 clinician-reviewed scenarios with 0% hallucinations. That result required both structured output contracts and Logfire tracing of every step for auditability.

Production Failure Modes

Three failure classes surface repeatedly in production, and none of the top-20 SERP results on Pydantic AI covers them.

Silent Degradation

An agent returns worse answers after a prompt or model change, but no error is raised, no latency spike appears, and monitoring dashboards stay green. The only signal is user complaints.

Pydantic flagged this on LinkedIn (June 16, 2026):

"Your AI was fine last week. New prompt, new model, answers quietly got worse. Nothing errored. Sound familiar?"

Traditional backend observability was built for crashes and latency spikes, not quality degradation in stateful LLM outputs. The only reliable defense is a continuous eval baseline: run your golden dataset against production on every deploy and page when the score drops below threshold.

OOM Overnight Agent Runs

Long-running agent loops accumulate context and tool call history in memory. Without explicit message pruning or history caps, a multi-hour agent run hits OOM, especially in multi-agent delegation chains where each sub-agent appends to a shared history object.

The fix is explicit: set max_messages or prune message_history on a rolling window before passing it to the next agent call. Any OTel trace of token counts per run surfaces the growth pattern before it kills the process.

Multi-Service Timeout Attribution

When an agent calls 14+ downstream services and one times out, the default error is opaque: the agent loop exits without specifying which tool call failed. Logfire's per-tool-call traces make attribution explicit: the failed span names the tool, the arguments, and the elapsed time at failure.

Temporal Technologies said on LinkedIn (June 18, 2026): "Strip away runtime, memory, identity, tool access, and observability, and your agent is just a chat completion."

Pydantic AI handles the model interface; Logfire handles the observability; a durable execution layer (Temporal or similar) handles crash recovery and retries. Without all three, timeout attribution becomes a multi-hour grep exercise.

Pydantic AI vs LangChain and Other Frameworks

The LangChain guide on Pynions covers that framework's LCEL, RAG, and LangGraph patterns in depth. The distinction for production decisions:

Dimension

Pydantic AI v2.0.0

LangChain v0.3.x

Abstraction

Python-native, minimal layers

Chain/Graph (LCEL DSL)

Type safety

First-class (Pydantic v2)

Optional / add-on

Structured output

Built-in, validated by default

Via output parsers

Dependency injection

Typed RunContext

Not native

Async

Native async-first

Supported, not default

Observability

Logfire + any OTel backend

LangSmith (paid SaaS)

Ecosystem

Growing (focused)

Massive (600+ integrations)

Learning curve

Low (plain Python)

Medium-High (custom DSL)

Best for

Production backends, typed services

Rapid prototyping, broad integrations

Practitioner verdict from r/LangChain:

"Refactored everything and went with every project to PydanticAI. (And never touched LC/LG since over a year.)"

u/Charming_Support726 in r/LangChain (2026)

Kunal Ganglani's 2026 comparison: "Pydantic AI wins for production systems that need validated, structured outputs; LangChain wins when you need to integrate quickly with a wide ecosystem and prototype fast."

The migration from LangChain to Pydantic AI is a significant rewrite, not a drop-in swap. Different abstractions, different DI model, different observability story. Budget the refactor accordingly.

Framework Landscape Overview

Framework

Paradigm

Best for

Pydantic AI

Type-safe Python

Production backends, typed services

LangChain / LangGraph

Chain/graph composition

Broad integrations, rapid prototyping

LlamaIndex

RAG pipelines

Retrieval-heavy use cases

CrewAI

Role-based multi-agent

Team-of-agent simulations

smolagents

Code-first, minimal

Lightweight tasks, local models

OpenAI Agents SDK

Provider-specific

OpenAI-first workflows

Pydantic AI vs Instructor

Instructor patches the OpenAI client for single-step structured extraction. It is simpler and faster to start with for straightforward extraction tasks.

The friction appears when you add multi-step workflows, tool calls, and dependency injection; that's where Pydantic AI's abstractions earn their weight. Practitioners on Reddit describe an organic migration path: start with Instructor, hit its tool-call ceiling, graduate to Pydantic AI when multi-step agent workflows are needed.

Common Pydantic AI Mistakes to Avoid

Using Structured Output with Local Models Without Testing First

Pydantic AI's structured output relies on tool calling (function calling). Smaller models, including Mistral-7B and Qwen 3.6B, fail at this non-gracefully: function calls cascade into malformed JSON that the Pydantic validator rejects, and the framework has no graceful fallback mode.

One r/LocalLLaMA practitioner described the experience directly:

"I really wanted to like it, but their way to create structured output by 'abusing' tool calling didn't really work with most 'local' models or custom APIs. In the end I stayed with DSPy which is much more flexible."

u/nore_se_kra in r/LocalLLaMA (2025)

Community benchmarks on r/LocalLLaMA show DeepSeek-R1 hitting 100% task success on smolagents vs 40-55% on structured-output-first frameworks. If local inference is your constraint, test your specific model against Pydantic AI's tool calling before committing to the framework.

Confusing Pydantic and Pydantic AI

The Pydantic validation library has ~500 million monthly PyPI downloads. Pydantic AI has ~30 million.

These are separate products. pip install pydantic does not install the agent framework. Endorsements of the validation library (near-universal in Python) are not endorsements of the agent framework.

Skipping Evals Until Something Goes Wrong

Building a golden dataset upfront feels expensive. Running one after a silent degradation incident in production costs more.

Start with 20-50 hand-labeled examples from production traces. GEPA can optimize against a small dataset immediately, and a baseline eval catches quality regressions before users surface them.

Treating Logfire as Optional in Production

The logfire.instrument_pydantic_ai() one-liner adds per-tool-call tracing with zero application code changes. Without it, debugging tool call failures, timeout attribution, and token accumulation requires reconstructing context from unstructured logs. Add it before shipping to production, not after the first incident.

Letting Multi-Agent History Grow Unbounded

Agents are stateless, but message_history passed between multi-agent runs is not. Without explicit pruning or a max_messages cap, delegation chains in long-running workflows accumulate history that grows with every call.

OOM failures in overnight agent runs almost always trace back to unbounded history objects. Set the limit before you ship.

Frequently Asked Questions

Related Articles