Pydantic AI: A typed agent loop that treats model output as data to validate
AI Agent Framework, the Pydantic way. Yet despite virtually every Python agent framework and LLM library using Pydantic Validation, when we began to use LLMs in Pydantic Logfire, we couldn't find anything that gave us the same feeling.
At a glance
- What is it?
- Pydantic AI wraps LLM calls in Pydantic models, so every agent run returns a validated, typed object. The framework covers extraction, voice, image generation, and embeddings, with a separate Harness package for long-running coding agents.
- Who is it for?
- Adopt Pydantic AI if you already build on Pydantic and want each agent run to return a validated type, especially for data extraction or multi-interface deployments. Skip it if you need a lightweight callback loop with no schema overhead, or if you plan to use a model provider that is not in the supported list.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
Why Pydantic built its own agent framework
The README states that the team at Pydantic Logfire could not find an existing Python agent framework that gave them the same feeling as Pydantic itself. That feeling is typed validation. Most LLM libraries use Pydantic internally for schema validation, but none exposed that validation as the core loop of an agent. Pydantic AI makes the output type the contract: you declare a Pydantic model, and every run is guaranteed to return that model. The target user is a Python developer who already trusts Pydantic and wants the same guarantees applied to LLM responses, from a one-shot extraction to a long-running multi-agent session. It is not aimed at someone who wants a minimal, untyped prompt loop.
The typed run loop and how output validation works
The core abstraction is the Agent class. You give it a model string like 'openai:gpt-5.6-sol' and an output_type, which is a Pydantic BaseModel. When you call run_sync, the agent sends the prompt and tool schemas to the model, receives the raw response, and validates it against the output type. If validation fails, the agent retries or raises, depending on configuration. The README's Sentiment example shows a model with a Literal label and a float score constrained between -1 and 1. The framework guarantees that result.output is a Sentiment instance, so your IDE, type checker, and the LLM all agree on the shape. This is a different contract from most agent libraries, which return raw strings or dictionaries. The trade-off is that the model must be capable of producing JSON that matches your schema, which can fail on complex nested types. The README does not describe what happens on repeated validation failure, so you should check the error handling docs before relying on it in production.
Tools with RunContext: dependencies in, schemas out
Tools are plain Python functions decorated with @agent.tool. The function receives a RunContext that carries your dependencies, and the rest of the signature and docstring become the tool schema. Arguments are validated before your code runs, which means a malformed tool call never reaches your function body. The README shows a tool called recent_reviews that takes a product string and returns a list of strings. The framework derives the JSON schema from the type hints, so you do not write a separate schema file. This is convenient, but it also means your tool signatures must be fully typed, including return annotations, or the schema generation will fail. For tools that need no context, there is @agent.tool_plain, as shown in the voice example. The design keeps tool definitions close to the agent, which works well for small numbers of tools but could get unwieldy for a large toolset.
One agent, many interfaces: CLI, web, voice, and background queues
The same agent can run in different environments without changing its core logic. The README lists a web frontend, a terminal CLI, a voice call, a durable background queue, and a plain object you call run() on. For the terminal, agent.to_cli_sync() starts an interactive session. For voice, you install the openai-realtime extra and use the agent with audio streaming. The framework also supports image generation and embeddings in the same package. This is a broad surface area for one project, and the documentation is organized by interface. The practical benefit is that you can prototype in the terminal and later deploy the same agent behind a web API without rewriting the prompt or tools. The risk is that each interface has its own setup and configuration, and the README does not show how to switch between them in code. You should verify that the interface you need is documented for your model provider.
Pydantic AI Harness: a separate package for long-running coding agents
The Harness repository is a companion package that bundles capabilities for complex work. It includes memory, sub-agents, context management, and a complete coding agent. The Coder capability combines FileSystem, Shell, RepoContext, Planning, SubAgents, and tool output limits. You can use Coder as a single capability or compose the blocks yourself, and the README says the two are equivalent. The shell capability is allowlisted, which means you control which commands the agent can run, but it still executes arbitrary commands within that allowlist. This is a powerful feature and a security boundary you must understand before deploying. The Harness also includes an Advisor capability that calls a second model for a second opinion when the agent is stuck. This is a concrete pattern for improving reliability, but it doubles the model cost for those situations. The README does not specify how the advisor is triggered or how often it runs.
Getting started: commands and configuration you will actually run
Installation uses uv. For the base framework, run 'uv add pydantic-ai'. For voice support, run 'uv add "pydantic-ai[openai-realtime]"'. For the coding agent, run 'uv add pydantic-ai pydantic-ai-harness'. The model string is passed as the first argument to the Agent constructor, for example 'anthropic:claude-fable-5' or 'openai:gpt-5.6-sol'. You can also run a prebuilt agent from the CLI without writing code: 'uvx --with pydantic-ai-harness clai -a pydantic_ai_harness.coder:coder_agent -m anthropic:claude-fable-5'. This command uses the clai CLI, which is part of the Pydantic AI integrations. The README does not show how to set API keys, so you must check the model provider docs for environment variables or config files. The framework expects a model string that maps to a provider, and the list of supported providers is in the models overview page, which is not included in the README.
Limitations and cases where this is the wrong tool
The most obvious limitation is the dependency on Pydantic itself. If your team does not already use Pydantic, this framework forces you to adopt it as a core dependency. The validation guarantee also assumes the model can produce output that matches your schema. For highly nested or constrained types, you may spend more time adjusting your schema than writing agent logic. The README does not mention streaming token-by-token output, which is a common need for chat interfaces. It also does not describe how to handle rate limits or retries on the model API side. The Harness shell capability is a genuine risk: even with an allowlist, a coding agent that can run shell commands can delete files or make network requests. If your use case is a simple chatbot that does not need tools or typed output, this framework is overkill. A plain HTTP call to the model API would be simpler and lighter.
Alternatives and how they differ
The main alternative is LangChain, which also provides agents, tools, and model abstractions for Python. LangChain uses a more modular design with chains, memory, and callbacks, but it does not require you to declare a Pydantic output type for every run. Instead, you typically parse the model output yourself or use its output parsers. This means LangChain gives you more flexibility at the cost of fewer compile-time guarantees. Another alternative is the OpenAI Python SDK directly, which lets you call chat completions and parse JSON responses yourself. That is the lightest option, but you lose the agent loop, tool schema generation, and retry logic. Pydantic AI sits between those two: it provides a structured loop and validation, but it is tied to Pydantic models. If you want to avoid that coupling, LangChain or a raw SDK gives you more freedom, though you give up the typed guarantee.
Maintenance, licensing, and upgrade path
The project is under the MIT license, which allows commercial use and modification with attribution. The repository is active, with releases on consecutive days (v2.35.1, v2.35.3, v2.36.0) and a last push on 2026-08-29. The version number is at 2.x, which suggests a stable API, but the rapid release cadence means you should expect frequent updates. The README points to a separate Harness repository, so the maintenance burden is split across two packages. Upgrading may require checking both packages for compatibility, especially if you use capabilities from Harness. The documentation is extensive, with guides for extensibility, models, and capabilities, but the README itself is a marketing overview rather than a technical reference. For a production deployment, you will need to read the full docs to understand configuration options like model-specific settings and error handling. The MIT license is permissive, but you should review the dependency licenses for the model provider SDKs you choose to use.
Editorial conclusion
Adopt Pydantic AI if you already build on Pydantic and want each agent run to return a validated type, especially for data extraction or multi-interface deployments. Skip it if you need a lightweight callback loop with no schema overhead, or if you plan to use a model provider that is not in the supported list. Before committing, verify that your exact model name string (for example 'anthropic:claude-fable-5') is documented as supported, and check whether the Harness package's shell and filesystem capabilities match your security constraints, since those tools execute arbitrary commands by design.
Community notes