Pydantic-AI

Typed, validated LLM calls with RunContext, TestModel, and provider-neutral agents.

Built by the team behind Pydantic — the validation library already running inside FastAPI and most other Python AI tools. The core idea: treat an LLM call like a typed function call, not a string-in-string-out black box.

Core concepts

  1. Typed, validated output: Pass Agent() an output_type and get back a validated Pydantic model instead of a raw string, with automatic retries if the model returns something that doesn't fit. Pydantic-AI Docs
  2. @agent.tool and @agent.tool_plain: Register tools two ways — tool_plain for stateless functions, tool when a tool needs RunContext for dependency injection.
  3. RunContext dependency injection: Pass a database connection, an authenticated user, or an HTTP client into every tool call without reaching for global state.
  4. TestModel: A substitute for a real LLM in unit tests — deterministic, fast, offline test runs without burning API credits on every CI run.
  5. Provider-neutral: Supports OpenAI, Anthropic, Google, Groq, Mistral, Bedrock, and any OpenAI-compatible endpoint — swapping providers is usually one string.

What Is It?

Pydantic AI wraps LLM calls with schema validation and dependency injection via RunContext.

TestModel lets you simulate model responses in pytest.

Works across providers while keeping Python types central.

Why Should I Care?

Production agents need predictable structures for downstream APIs and UI.

Testing without burning tokens speeds CI for agent features.

Real World Analogy

Pydantic AI is a bouncer at the club door — every model reply must match the outfit code (schema) before it enters your app.

Visual Mental Model

text
model output -> validate -> typed object -> app logic

Beginner Explanation

Built by the Pydantic team: provider-neutral agents with validated outputs, RunContext for dependencies, and TestModel for unit tests without hitting APIs.

Smallest Possible Example

python
from pydantic import BaseModel

class Answer(BaseModel):
    summary: str
    score: int

Common Mistakes

❌ Loose schemas with dozens of optional fields.

Models fill noise; tighten fields to what you actually use.

❌ Skipping TestModel in CI.

You regress tool routing silently when prompts change.

❌ Mixing validation and business rules in one giant model class.

Split DTO validation from domain logic.

Real Project Example

FastAPI shops already use Pydantic — Pydantic AI fits the same mental model.

Teams building typed internal copilots adopt it for guardrailed JSON.

Build This Mini Project

Define a Pydantic model for a tool result, write a TestModel test that asserts parsing, and run pytest in CI.

Interview Question

Why validate LLM outputs with Pydantic?

Models hallucinate structure; validation fails fast before bad data hits databases, payments, or user-visible actions — and gives clear errors for retries.

Key Takeaways

  • Schema-first agent outputs.
  • RunContext for deps.
  • TestModel for cheap CI.
  • Provider-neutral typing.

Resources

YouTube learning

Core concepts from video walkthroughs:

The 60-second story

A model will happily write you a charming paragraph when you needed a form with three boxes. Pydantic-AI is the counter that says “the answer is this shape, or you try again.” You pass an output_type. You get a validated model. If the text does not fit, the framework can nudge a retry instead of handing your app a string to split with hope and split(",").

Tools come in two coats. @agent.tool_plain is a pure helper: give it inputs, get an output, no secret backpack. @agent.tool is for when the tool needs the backpack — a database handle, the signed-in user, an HTTP client. That backpack is RunContext. You pass it in when the run starts. Tools pull from it. You do not hide the database in a global because globals are socks on the floor and every request wears the wrong pair.

TestModel is a stand-in who never calls a real lab. Tests stay fast, offline, and free. If your CI needs a credit card to prove a function returns a name, the test is not a test. It is a weather report.

The provider string is a swappable sign on the door. OpenAI, Anthropic, Google, Groq, an OpenAI-compatible endpoint. The form and the tools stay. The brain behind the counter can change without a rewrite of the lobby.

Map the counter.

  • output_type is the form the answer must match.
  • A retry is “that was not a form, fill it again.”
  • tool_plain is a helper with empty pockets.
  • RunContext is the backpack of real dependencies.
  • TestModel is the stand-in who does not spend money.
  • The provider name is a sign you can change.
python
from pydantic import BaseModel

class Reply(BaseModel):
    answer: str
    confident: bool

That class is the contract. The rest of the agent is how you reach an instance of it without scraping prose.

This library exists because agent demos die at the edge where a string becomes a decision. Typed output makes the edge boring. Dependency injection exists so tests can hand the tool a fake backpack. Provider neutrality exists so a pricing change is not a rewrite.

Mental model: a form, a backpack, and a stand-in for tests. The model is not allowed to freestyle the result type. The tools are not allowed to smuggle secrets through globals.

If you can explain why tool and tool_plain both exist, and why TestModel saves the credit card, you understand why people pick this stack when correctness is the feature.

Threads in the same domain as this chapter — go deeper on iHateReading without leaving the roadmap.

Python AI agent SDKs in 2026: OpenAI vs Pydantic-AI vs smolagents vs Strands cover

Python AI agent SDKs in 2026: OpenAI vs Pydantic-AI vs smolagents vs Strands

Same three-tool agent in four frameworks — pick by execution model and testing needs.

Agent harnessing: the part of building AI agents nobody talks about cover

Agent harnessing: the part of building AI agents nobody talks about

Loop, tools, memory, sandbox, and tracing live in your code — not the model weights.

Smallest AI Agent cover

Smallest AI Agent

Minimal file-reading agent to learn LLM tool loops without framework magic.