> Pydantic AI 2.55 gives Python agents typed dependencies, validated output and OpenTelemetry tracing. What 2.0 changed, what Logfire costs and who should pick it.
>
> Web page: https://balazscsorba.com/blog/pydantic-ai · Language: English · Also available in: [Deutsch](https://balazscsorba.com/de/blog/pydantic-ai.md) · [Magyar](https://balazscsorba.com/hu/blog/pydantic-ai.md)
> Author: Balázs Csorba · Published: 2026-10-08 · Keywords: pydantic ai, pydantic ai review, pydantic ai vs langgraph, pydantic ai vs openai agents sdk, typed python agent framework, pydantic ai logfire pricing, pydantic ai 2.0 upgrade, python llm agent framework

[Blog](https://balazscsorba.com/blog)/AI agents

# Pydantic AI review: typed Python agents with validated output

Pydantic AI 2.55 gives Python agents typed dependencies, validated output and OpenTelemetry tracing. What 2.0 changed, what Logfire costs and who should pick it.

[Balázs Csorba](https://balazscsorba.com/about)·October 8, 2026·8 min read

-   Agent framework
-   Typed Python
-   Structured output
-   Dependency injection
-   OpenTelemetry

![A square, triangle and circle entering a sorting frame, equal small squares coming out below.](https://balazscsorba.com/images/blog/pydantic-ai/cover.webp?v=81da9cec4f)

## Key takeaways

-   Pydantic AI 2.55.0, released on 9 October 2026, is MIT-licensed and free to run. Your costs are model tokens and, if you use it, Logfire records.
-   The 2.0 line became stable on 23 June 2026 after seven betas and moved configuration onto capabilities, so pin the version and follow the upgrade path.
-   Dependencies reach your tools through a typed RunContext, and output\_type validates every answer, sending a failed check back to the model before your code sees it.
-   Tracing is opt-in and follows OpenTelemetry, so spans can go to Logfire or to any OpenTelemetry backend. Durable runs need Temporal, DBOS, Prefect, Restate or AWS Lambda.
-   Pick it for typed Python services. Pick the OpenAI Agents SDK for a small OpenAI-first stack, and LangGraph when explicit graphs, checkpoints and interrupts are the product.

On this page

1.  [What it is](https://balazscsorba.com/#what-it-is)
2.  [How it works](https://balazscsorba.com/#how-it-works)
3.  [Getting started](https://balazscsorba.com/#getting-started)
4.  [Typed dependencies and validated output](https://balazscsorba.com/#typed-agents-and-validation)
5.  [Tracing and durable runs](https://balazscsorba.com/#tracing-and-durable-runs)
6.  [Cost, hosting and data protection](https://balazscsorba.com/#cost-and-deployment)
7.  [Where it falls short](https://balazscsorba.com/#where-it-falls-short)
8.  [Verdict](https://balazscsorba.com/#verdict)
9.  [Sources](https://balazscsorba.com/#sources)

Listen to this article

0:000:00

Pydantic AI is the Python agent framework from the team behind Pydantic, the data validation library. Dependencies, tools and results are ordinary Python types, and every structured answer from the model is checked before your code receives it. The verdict up front – use it for typed agents inside Python services, where the team already thinks in Pydantic models. Skip it if your team builds in TypeScript, wants a visual builder as the main way to design workflows, or cannot absorb API changes between releases.

## What it is

The current release is 2.55.0, published on PyPI on 9 October 2026. It is MIT-licensed, needs Python 3.11 or newer and has about 20,500 stars on GitHub. The project calls itself “how Python does AI”: agents, realtime voice, image generation and embeddings, typed end to end. The 2.0 line became stable on 23 June 2026, so older tutorials may still describe the 1.x API.

-   **Typed dependencies.** \`deps\_type\` declares what an agent needs, and each run receives an instance through \`deps=\`.
-   **Validated output.** \`output\_type\` takes a Pydantic model, a union or a list of types. The model fills it through tool calling by default.
-   **About two dozen providers.** A prefix such as \`openai:\`, \`anthropic:\` or \`google:\` selects the provider. The directory also covers Groq, Mistral, Ollama and OpenRouter, plus any OpenAI-compatible endpoint.
-   **Capabilities and durability.** Capabilities bundle tools, hooks, instructions and model settings into one reusable unit. Durable runs plug in through Temporal, DBOS, Prefect, Restate and AWS Lambda.

## How it works

An agent run is a loop with a check at the end. The agent sends its instructions, the message history and the tool schemas to the model. When the model calls a tool, Pydantic AI runs your Python function with the typed context and returns the result to the model. When the model stops calling tools, its output is validated against \`output\_type\`. A failed check goes back to the model as a retry, and the default budget for output retries is one.

![One agent run in Pydantic AI Your code passes dependencies and input to an agent. The agent sends its instructions and tool schemas to the model. When the model calls a tool, the tool runs with the typed context and its result goes back to the model. When the model finishes, its output is validated against the output type. A failed check goes back to the model as a retry, and a passing answer is returned to your code.](https://balazscsorba.com/images/blog/pydantic-ai/diagram-6.webp?v=8fa352ab8c)

Each run loops between the model and the tools, and every answer passes the validation gate before it leaves the agent.

Dependencies are passed to your functions, never to the model. A database pool or an HTTP session can sit next to the agent without appearing in a prompt. The model only sees the instructions, the tool schemas and the messages, which is what makes the boundary worth designing on purpose.

## Getting started

Install with \`uv add pydantic-ai\` or \`pip install pydantic-ai\`, then set the credentials your provider expects. The example below is a support triage agent. It takes a typed dependency, calls one tool and returns a validated object.

```
from dataclasses import dataclass
from typing import Literal

from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext

from myshop.orders import OrderService

@dataclass
class SupportDeps:
    customer_id: int
    orders: OrderService  # your own client, injected per run

class Triage(BaseModel):
    category: Literal['refund', 'shipping', 'other']
    risk: int = Field(ge=0, le=10, description='How urgently a person should review this')
    reply: str

support = Agent(
    'openai:gpt-6-sol',
    deps_type=SupportDeps,
    output_type=Triage,
    instructions='Triage the message. Check the order before you answer.',
)

@support.tool
async def latest_order(ctx: RunContext[SupportDeps]) -> str:
    '''Return the status of the most recent order.'''
    return await ctx.deps.orders.latest_status(ctx.deps.customer_id)

result = support.run_sync(
    'Where is my parcel?',
    deps=SupportDeps(customer_id=42, orders=OrderService()),
)
print(result.output.category, result.output.risk)
```

Two parts of that code do the work. The \`Triage\` class is both the schema sent to the model and the type your code receives. An answer outside the allowed categories or the 0 to 10 risk range is retried and, if it still fails, raises an error instead of reaching your code. The \`RunContext\[SupportDeps\]\` annotation gives the tool a typed view of your client, so the editor can check every attribute you use.

## Typed dependencies and validated output

Dependencies are the part I would adopt first. \`deps\_type\` declares the type, \`RunContext\[Deps\]\` gives tools, instructions and output validators access to \`ctx.deps\`, and a test can swap the real client for a fake with \`agent.override(deps=...)\`. The wiring stays in the constructor and the run call rather than in module-level globals, which keeps the agent easy to test.

Output is where the framework earns its keep. By default the model returns structured data through its tool-calling interface, and a union of types becomes one output tool per member. The \`TextOutput\` and \`PromptedOutput\` markers switch to plain text for models with unreliable tool calling. \`ToolOutput\` gives one output tool its own retry budget, so a complex type can get more attempts than a simple one.

-   **\`ModelRetry\`** lets a tool or output function reject a value and tell the model what to change.
-   **\`@agent.output\_validator\`** runs your own checks after parsing, for example that an order number in the answer exists.
-   **\`Agent(retries={'output': N})\`** raises the output retry budget for the whole agent. The default is one.
-   **\`ToolOutput(Fruit, max\_retries=2)\`** gives one output type its own retry count.

Testing is where the design pays back. \`TestModel\` calls every tool and returns a structurally valid answer, \`FunctionModel\` lets a test script the model’s reply, and \`ALLOW\_MODEL\_REQUESTS=False\` blocks accidental calls to real providers in CI. A unit test of the support flow then needs no API key and no network.

## Tracing and durable runs

Tracing is opt-in. Call \`logfire.configure()\` and \`logfire.instrument\_pydantic\_ai()\` at start-up, and each run, model response and tool call becomes an OpenTelemetry span that follows the generative AI semantic conventions. The Logfire SDK can send the same data to any OpenTelemetry backend, which matters if the telemetry has to stay in a system the team already runs. For the wider case, read [agent observability with OpenTelemetry](https://balazscsorba.com/blog/agent-observability-opentelemetry).

Durable execution is the second feature to understand. The docs list eight engines. Temporal, DBOS, Prefect, Restate and AWS Lambda are co-maintained with their vendors, and Kitaru, Apache Airflow and Absurd come as external integrations. In 2.x you attach a durability capability to the agent. The README example adds \`TemporalDurability()\` to an agent’s capabilities inside a Temporal workflow.

**Durable is not the same as saved**

A durable engine keeps one run alive across crashes and restarts. It does not store your chat threads. The docs treat saving a conversation and resuming it later as a separate problem, so plan that storage on purpose.

## Cost, hosting and data protection

As of October 2026, the library costs nothing to run. The licence covers the code, so the bills come from three places: model tokens from your provider, Logfire records if you use Logfire, and the infrastructure for a durable engine if you adopt one. The Logfire plans show the shape of the second bill.

Plan

Price

Included

What changes

Personal

Free

10M records a month, hard-capped

3 projects, 30-day retention, 1 seat and 2 read-only guests

Team

$49 a month

10M records, then $2 per million

5 seats (up to 12), 10 guests, 5 projects, 30-day retention, spending cap

Growth

$249 a month

10M records, then $2 per million

Unlimited seats, guests and projects, 90-day retention, priority support and a BAA template

Enterprise

Custom

By contract

Cloud, Dedicated or Self-hosted; SSO, SCIM and an SLA

Logfire bills records: logs, spans and metrics. The included 10 million a month are covered by the plan credit, and above that Team and Growth charge $2 per million. A team that sends 30 million records a month pays $49 plus $40 for the extra 20 million, about $89 before any model tokens. The AI gateway adds a 5 percent markup on built-in providers, while up to three of your own provider keys pass through without markup.

**Set the cap before the first load test**

Personal stops ingesting at 10 million records, and Team offers a spending cap. Switch the cap on before a load test or a bulk eval run, not after the first surprising invoice.

Self-hosting the library is the default, because it is just code in your own environment. Logfire’s Enterprise tier adds a self-hosted option on your own Kubernetes cluster. For data protection, three flows matter. The model provider receives prompts and tool results, so its data processing terms and region come first. Logfire receives every span you export, so exclude prompts and completions at source where you do not need them. Pydantic offers a Data Processing Addendum for GDPR, a SOC 2 Type 2 report on request and a published list of subprocessors.

Region is a setting to check on every plan. The plan matrix ticks EU or US data region for each hosted plan, from Personal to Enterprise Cloud. Enterprise Dedicated offers any Google Cloud region, and self-hosting keeps the data wherever you run it. The pricing page does not say which region a new project gets by default, so check that before you send personal data. [The wider data residency question for model APIs is covered in a separate article.](https://balazscsorba.com/blog/gdpr-llm-api-eu-data-residency)

## Where it falls short

The main risk is churn – and the changelog is open about it. The 2.0 line went through seven betas between 20 May and 10 June 2026 before the stable release on 23 June. Its breaking changes come in two groups: removals that the V1 deprecation warnings could not announce, and changes that V1 did warn about. Removed items include the Outlines integration and its extras, and \`ModelProfile\` changed from a dataclass to a TypedDict. A migration is a real task, not a version bump.

**Upgrade in this order**

Move to the latest V1 release, at least 1.100.0, where most of the removals were first deprecated.

Run the test suite with warnings visible and fix every deprecation warning.

Read the breaking-change list, then move to 2.x and pin the version.

Minor releases are frequent too. Version 2.51.0 came out on 25 September 2026 and 2.55.0 on 9 October, so a loosely pinned project sees several changes in a fortnight. The version policy promises no intentional breaking changes in minor releases, but features in a beta module are explicitly unstable and may change in ways that break existing code. Treat any import from a beta module as a pinned dependency.

Keep an eye on the security notes as well. Release 2.52.0 fixed a CPU and memory problem in the local \`web\_fetch\` tool, where deeply nested HTML could consume excessive resources. Provider-native web fetching was not affected. Finally – it is a Python library. Teams that build agents in TypeScript need a different framework, and durable engines add infrastructure that someone must run or buy.

Tool

Licence

Version, October 2026

Strongest at

Tracing

Pydantic AI

MIT

2.55.0

Typed dependencies and validated output in Python

Opt-in, through Logfire or OpenTelemetry

OpenAI Agents SDK

MIT

0.23.1

Very few primitives: agents, handoffs, guardrails, sessions

On by default, exported to OpenAI unless disabled

LangGraph

MIT

1.2.14

Explicit graphs with checkpoints, interrupts and fault tolerance

LangSmith, a separate platform

## Verdict

Pydantic AI is my default for a Python team that already models its data with Pydantic and wants agents that are typed, testable and easy to run beside the rest of the service. It is the wrong choice for a TypeScript codebase, for a team that wants a visual graph editor as its main design tool, and for any team that cannot absorb API changes between releases. In those cases, the alternatives below fit better.

1.  **Adopt Pydantic AI** when your services are Python, your data is already modelled in Pydantic and you want typed tools and validated output.
2.  **Pick the** [OpenAI Agents SDK](https://balazscsorba.com/blog/openai-agents-sdk) when you are committed to OpenAI and want very few primitives. Turn tracing off or add your own processor before real customer data flows through it.
3.  **Pick** [LangGraph](https://balazscsorba.com/blog/langgraph) when the workflow is the product: explicit state, checkpoints and named approval steps. You write more code, and you control every transition.

## Sources

-   [Pydantic AI documentation](https://ai.pydantic.dev/)
-   [pydantic-ai 2.55.0 on PyPI (released 9 October 2026)](https://pypi.org/project/pydantic-ai/)
-   [pydantic/pydantic-ai on GitHub: licence, stars and README](https://github.com/pydantic/pydantic-ai)
-   [Pydantic AI release notes: 2.51.0 to 2.55.0 and the 2.52.0 security fix](https://github.com/pydantic/pydantic-ai/releases)
-   [Pydantic AI version policy](https://ai.pydantic.dev/version-policy/)
-   [Pydantic AI upgrade guide: the V2 betas and the stable release](https://ai.pydantic.dev/project/changelog/)
-   [Pydantic AI output: tool output, retries and output validators](https://ai.pydantic.dev/output/)
-   [Pydantic AI dependencies and RunContext](https://ai.pydantic.dev/dependencies/)
-   [Pydantic AI models and providers](https://ai.pydantic.dev/models/overview/)
-   [Pydantic AI unit testing with TestModel and FunctionModel](https://ai.pydantic.dev/testing/)
-   [Pydantic AI durable execution overview](https://ai.pydantic.dev/durable_execution/overview/)
-   [Pydantic Logfire: observability for Pydantic AI](https://ai.pydantic.dev/logfire/)
-   [Pydantic Logfire pricing](https://pydantic.dev/pricing)
-   [Pydantic security and compliance](https://pydantic.dev/security)
-   [OpenAI Agents SDK documentation](https://openai.github.io/openai-agents-python/)
-   [OpenAI Agents SDK tracing](https://openai.github.io/openai-agents-python/tracing/)
-   [openai/openai-agents-python on GitHub](https://github.com/openai/openai-agents-python)
-   [openai-agents 0.23.1 on PyPI](https://pypi.org/project/openai-agents/)
-   [langchain-ai/langgraph on GitHub](https://github.com/langchain-ai/langgraph)
-   [langgraph 1.2.14 on PyPI](https://pypi.org/project/langgraph/)
-   [LangGraph overview](https://docs.langchain.com/oss/python/langgraph/overview)
-   [LangGraph interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)

## Frequently asked questions

How much does Pydantic AI cost?

As of October 2026, the library is MIT-licensed and free. The bills come from your model provider and, if you use Logfire, from its records: Personal is free up to 10 million records a month with ingestion paused at the cap, Team is $49 a month, Growth is $249 a month, and Enterprise is quoted.

Is the 2.x line stable enough for production?

Yes, with the usual care. Minor releases are not meant to break public APIs, but features in beta modules can change, and each major version removes what was deprecated before. Security fixes for V1 continue for at least six months after the 2.0 stable release, so plan the move.

How does it compare with the OpenAI Agents SDK and LangGraph?

The OpenAI Agents SDK is smaller and turns tracing on by default. LangGraph is built around explicit graphs with checkpoints and interrupts. Pydantic AI sits between them: typed dependencies and validated output for Python code, with a provider prefix for roughly two dozen providers.

Does Logfire receive my prompts?

Only the spans you export. Instrumentation is opt-in, the docs describe how to exclude prompts and completions from spans, and Pydantic offers a Data Processing Addendum, a SOC 2 Type 2 report on request and a list of subprocessors.

Written by Balázs Csorba

Senior fullstack & AI engineer in Styria, Austria – 10+ years of Vue, Nuxt, Node.js and PHP, now building tooling for AI agents.

[AI engineering & MCP servers →](https://balazscsorba.com/expertise/ai-engineer)[About me →](https://balazscsorba.com/about)

## More articles

-   [Designing tools for AI agents: names, descriptions, schemas and error messages](https://balazscsorba.com/blog/agent-tool-design-descriptions-errors)
-   [Migrating a legacy codebase with coding agents: a strangler fig playbook](https://balazscsorba.com/blog/coding-agents-legacy-codebase-migration)
-   [Background coding agents that open PRs: a practical async workflow](https://balazscsorba.com/blog/background-agents-async-pr-workflow)
-   [Context rot in long-running agents: clearing, compaction, memory and sub-agents](https://balazscsorba.com/blog/context-rot-compaction-long-running-agents)

## Sounds like what you need?

Tell me about your project or role – I’d love to hear from you.

[Get in touch](mailto:contact@balazscsorba.com) [Connect on LinkedIn](https://www.linkedin.com/in/balazs-csorba)
