# PydanticAI: Guia Definitivo — Agentes Type-Safe em Python

> Guia completo sobre PydanticAI: o framework da equipe Pydantic para criar agentes IA type-safe com dependency injection, durable execution e validação...

Source: https://agentify.ia.br/blog/pydantic-ai/

## TL;DR

PydanticAI é o framework de agentes IA criado pela mesma equipe por trás do Pydantic — a biblioteca de validação usada internamente pela OpenAI, Google e Anthropic. A proposta é trazer a experiência “FastAPI” para o mundo dos agentes: type hints definem o contrato, o framework cuida da validação, e você foca na lógica de negócio. Com v2 lançada em junho de 2026, o framework agora inclui **capabilities** (bundles composáveis de tools + hooks + instruções), **Harness** (baterias para produção), suporte nativo a streaming, multi-agent via `pydantic-graph`, e integrações com Temporal/DBOS para durable execution. Se você é dev Python e quer agentes que respeitem tipos, sejam testáveis e rodem em produção sem gambiarras — PydanticAI é a resposta.

```
┌─────────────────────────────────────────────────┐
│ SPIDER CHART — PydanticAI v2 │
├─────────────────────────────────────────────────┤
│ │
│ Type Safety ★★★★★ │
│ ╱╲ │
│ DX/Ergon. ★★★★★ ╲ Observabilidade ★★★★☆ │
│ ╱ ╲ │
│ Streaming ★★★★☆ Multi-Agent ★★★☆☆ │
│ ╲ ╱ │
│ Ecosystem ★★★☆☆ ╱ Durable Exec ★★★★☆ │
│ ╲╱ │
│ Produção-Ready ★★★★☆ │
│ │
│ Escala: ★ = básico → ★★★★★ = referência │
└─────────────────────────────────────────────────┘
```

**8 Eixos avaliados:**

 Eixo
 Score
 Justificativa

 Type Safety
 5/5
 Validação Pydantic nativa, output_type , deps_type tipados

 Developer Experience
 5/5
 5 linhas para um agente funcional; DX score 8/10 no benchmark Nextbuild

 Streaming
 4/5
 Streaming nativo com validação parcial de schema; AG-UI e Vercel protocol

 Multi-Agent
 3/5
 Via pydantic-graph e agent-as-tool; sem delegação autônoma tipo CrewAI

 Ecosistema
 3/5
 ~15x menor que LangChain; crescendo com Harness e comunidade

 Durable Execution
 4/5
 Temporal, DBOS, Kitaru integrados; capability layer em progresso

 Observabilidade
 4/5
 OpenTelemetry nativo via Logfire; sem vendor lock-in

 Production-Ready
 4/5
 MIT, model-agnostic (20+ providers), UsageLimits, 100% test coverage

---

## Overview — O Que É PydanticAI

Pense no PydanticAI como o FastAPI dos agentes de IA. Se FastAPI pegou type hints do Python e transformou em documentação automática + validação + DX incrível para APIs web, PydanticAI faz a mesma coisa para interações com LLMs.

O framework foi criado por Samuel Colvin e a equipe da Pydantic — sim, a mesma biblioteca que a OpenAI, Anthropic e Google usam internamente para validação de dados nos seus SDKs. Isso não é coincidência. O insight fundamental é: se LLMs produzem dados estruturados, esses dados precisam de validação. E ninguém faz validação em Python melhor que o Pydantic.

### Pilares Fundamentais

**1. Type Safety em Tudo**
Não é um detalhe de implementação — é a filosofia central. Seu IDE te dá autocomplete, type checkers pegam bugs antes do runtime, e o framework garante que outputs do LLM estejam no formato que você definiu.

**2. Dependency Injection de Verdade**
Tools sem acesso a dependências são inúteis. O PydanticAI tem um sistema completo de DI via `RunContext[T]` que mantém seus agentes testáveis e desacoplados.

**3. Model-Agnostic**
Suporte a 20+ providers: OpenAI, Anthropic, Google Gemini, Groq, Mistral, AWS Bedrock, Ollama (modelos locais), e mais. Troque o modelo sem mudar uma linha de lógica.

**4. Observabilidade Aberta**
Emissão de dados via OpenTelemetry — funciona com Logfire (da própria Pydantic), mas também com qualquer stack OTel. Sem vendor lock-in.

**5. Durable Execution**
Integração documentada com Temporal, DBOS e Kitaru para agentes que sobrevivem a crashes, fazem retry inteligente e mantêm estado entre execuções.

### Evolução: v1 → v2

A **v1** (setembro 2025) trouxe estabilidade de API, human-in-the-loop tool approval e durable execution com Temporal. Foram 100+ releases sem breaking changes.

A **v2** (junho 2026) introduziu o conceito de **capabilities** — o primitivo fundamental que unifica tools, hooks, instruções e settings em um bundle composável. Pense em capabilities como plugins inteligentes que podem ler e reescrever o que o modelo vê a cada step do loop.

---

## Tutorial Prático — Seu Primeiro Agente

Vamos do zero ao agente funcional em poucos minutos. Se você já trabalhou com FastAPI ou Pydantic, vai se sentir em casa.

### Instalação

```
# Com uv (recomendado)
uv add pydantic-ai

# Ou com pip
pip install pydantic-ai
```

Para instalação mínima com um provider específico:

```
pip install "pydantic-ai-slim[google]"
```

### Configuração do Provider

```
# Google Gemini (free tier disponível)
export GOOGLE_API_KEY="sua-chave"

# OpenAI
export OPENAI_API_KEY="sua-chave"

# Anthropic
export ANTHROPIC_API_KEY="sua-chave"
```

### Agente Básico — 5 Linhas

```
from pydantic_ai import Agent

agent = Agent(
 "google:gemini-2.5-flash",
 instructions="Você é um especialista em Python. Responda em uma frase.",
)

result = agent.run_sync("O que é PydanticAI?")
print(result.output)
```

O formato do modelo é `"provider:modelo"`. O `instructions` define o system prompt para este agente. O `.run_sync()` executa de forma síncrona — para produção, use `await agent.run()` com async/await.

### Agente com Output Estruturado

Aqui o PydanticAI brilha de verdade. Em vez de parsear strings, você define um schema e o framework garante que o LLM retorne dados naquele formato:

```
from pydantic import BaseModel
from pydantic_ai import Agent

class AnaliseRepositorio(BaseModel):
 nome: str
 linguagem_principal: str
 stars: int
 pontos_fortes: list[str]
 pontos_fracos: list[str]

agent = Agent(
 "anthropic:claude-sonnet-4-20250514",
 output_type=AnaliseRepositorio,
 instructions="Analise repositórios open-source com base nas informações fornecidas."
)

result = agent.run_sync("Analise o repositório FastAPI")
repo = result.output # AnaliseRepositorio tipado!

print(f"{repo.nome} ({repo.linguagem_principal})")
print(f"Stars: {repo.stars:,}")
for ponto in repo.pontos_fortes:
 print(f" ✓ {ponto}")
```

O que acontece por baixo: PydanticAI converte `AnaliseRepositorio` em um JSON Schema, envia ao LLM, valida a resposta com Pydantic, e retorna um objeto tipado. Se a validação falhar, faz retry automático (configurável via `output_retries`).

---

## Deep Dive — Conceitos Fundamentais

### Agent: O Coração do Framework

O `Agent` é a interface principal. Ele encapsula modelo, instruções, tools, dependencies e output type:

```
from pydantic_ai import Agent

agent = Agent(
 "openai:gpt-4o",
 instructions="Assistente de análise de dados financeiros.",
 output_type=RelatorioFinanceiro,
 deps_type=DatabaseConnection,
 retries=,
 output_retries=,
)
```

**Parâmetros-chave:**

- `instructions` — System prompt isolado para este agente (não herda de agentes anteriores)

- `system_prompt` — System prompt que persiste no histórico entre agentes

- `output_type` — Schema Pydantic para validação do output

- `deps_type` — Tipo das dependências injetadas

- `retries` — Retries globais para o agente

- `output_retries` — Retries específicos para validação de output

**Modos de execução:**

```
# Síncrono (scripts, testes)
result = agent.run_sync("prompt")

# Assíncrono (produção)
result = await agent.run("prompt")

# Streaming (UIs em tempo real)
async with agent.run_stream("prompt") as stream:
 async for chunk in stream:
 print(chunk, end="")
```

### Tools: Function Calling com Type Safety

Tools são funções Python que o LLM pode invocar. O PydanticAI usa decorators para registrá-las:

```
import httpx
from pydantic_ai import Agent, RunContext

agent = Agent(
 "google:gemini-2.5-flash",
 instructions="Ajude com informações sobre o clima.",
)

@agent.tool_plain
def buscar_clima(cidade: str) -> dict:
 """Busca a previsão do tempo para uma cidade."""
 response = httpx.get(
 f"https://api.weatherapi.com/v1/current.json",
 params={"key": "API_KEY", "q": cidade}
 )
 return response.json()
```

**Dois decorators disponíveis:**

- `@agent.tool_plain` — Tool sem acesso ao contexto de execução

- `@agent.tool` — Tool com acesso ao `RunContext` (dependências, retry info, etc.)

A **docstring é crucial**: o LLM lê para decidir quando e como chamar a tool. Type hints nos parâmetros ajudam o modelo a passar os tipos corretos.

**Passando tools no construtor:**

```
agent = Agent(
 "openai:gpt-4o",
 tools=[buscar_clima, converter_moeda, calcular_juros]
)
```

### Dependencies: Injeção de Dependência Elegante

O padrão de DI do PydanticAI é inspirado no FastAPI e resolve um problema real: como dar acesso a banco de dados, APIs e config para suas tools sem usar globals ou hardcoding?

```
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext

@dataclass
class AppDeps:
 db_connection: AsyncSession
 redis_client: Redis
 api_key: str

agent = Agent(
 "anthropic:claude-sonnet-4-20250514",
 deps_type=AppDeps,
 instructions="Consulte o banco de dados para responder perguntas dos clientes.",
)

@agent.tool
async def buscar_pedido(ctx: RunContext[AppDeps], pedido_id: int) -> str:
 """Busca detalhes de um pedido no banco de dados."""
 async with ctx.deps.db_connection as session:
 pedido = await session.get(Pedido, pedido_id)
 return pedido.to_json() if pedido else "Pedido não encontrado"

# Em produção
deps = AppDeps(
 db_connection=async_session,
 redis_client=redis,
 api_key=os.environ["API_KEY"]
)
result = await agent.run("Qual o status do pedido #4521?", deps=deps)

# Em testes — swap de dependências trivial
with agent.override(deps=MockAppDeps()):
 result = await agent.run("Qual o status do pedido #4521?")
```

O `RunContext[AppDeps]` dá type safety completo. Seu IDE sabe exatamente o que `ctx.deps` contém. E trocar dependências para testes é uma linha.

### Result Types: Validação Automática

O PydanticAI suporta múltiplos tipos de output:

```
# String simples (padrão)
agent = Agent("openai:gpt-4o")

# Modelo Pydantic
agent = Agent("openai:gpt-4o", output_type=MeuModelo)

# Union de tipos (o LLM escolhe qual retornar)
agent = Agent("openai:gpt-4o", output_type=MeuModelo | OutroModelo | str)

# Tipos primitivos
agent = Agent("openai:gpt-4o", output_type=bool)
agent = Agent("openai:gpt-4o", output_type=int)
agent = Agent("openai:gpt-4o", output_type=list[str])
```

Quando a validação falha, o PydanticAI envia o erro de volta ao LLM com o contexto do que deu errado, dando chance para corrigir. Isso funciona surpreendentemente bem na prática — mas cada retry é uma chamada de API adicional (custo + latência).

### Streaming: Respostas em Tempo Real

Streaming é suportado nativamente com validação parcial de schema:

```
from pydantic_ai import Agent

agent = Agent("openai:gpt-4o", output_type=Artigo)

async with agent.run_stream("Escreva sobre observabilidade") as stream:
 # Stream de texto bruto
 async for text in stream.stream_text():
 print(text, end="", flush=True)

 # Ou stream com validação parcial
 async for partial in stream.stream_structured():
 # partial é um objeto parcialmente preenchido
 if partial.titulo:
 render_titulo(partial.titulo)
```

O PydanticAI também suporta protocolos de UI stream:

- **AG-UI Protocol** (CopilotKit) — para frontends com shared state

- **Vercel AI Data Stream Protocol** — para integração com Next.js

### Multi-Agent: Coordenação entre Agentes

PydanticAI oferece três padrões para multi-agent:

**1. Agent como Tool (delegação simples):**

```
pesquisador = Agent("openai:gpt-4o", instructions="Pesquise informações na web.")
redator = Agent(
 "anthropic:claude-sonnet-4-20250514",
 instructions="Escreva artigos baseados em pesquisas.",
)

@redator.tool_plain
async def pesquisar(query: str) -> str:
 """Pesquisa informações sobre um tópico."""
 result = await pesquisador.run(query)
 return result.output
```

**2. pydantic-graph (workflows complexos):**

```
from pydantic_graph import Graph, Node, Edge

class PesquisaNode(Node):
 async def run(self, state):
 # Executa pesquisa
 ...

class AnaliseNode(Node):
 async def run(self, state):
 # Analisa resultados
 ...

graph = Graph(nodes=[PesquisaNode, AnaliseNode])
```

**3. Capabilities v2 (composição avançada):**

```
from pydantic_ai import Agent
from pydantic_ai.capabilities import Capability, ToolSearch, WebSearch

agent = Agent(
 "anthropic:claude-opus-4-7",
 capabilities=[
 WebSearch(),
 ToolSearch(), # Descobre tools on-demand
 Capability(
 id="analytics",
 description="Consulta métricas de analytics.",
 toolset=MCPToolset("https://mcp.exemplo.com/analytics"),
 defer_loading=True, # Carrega só quando necessário
 ),
 ],
)
```

---

## Capabilities v2 — O Novo Primitivo

O lançamento do PydanticAI v2 em junho de 2026 introduziu **capabilities** como o conceito central de extensibilidade. Uma capability é um bundle composável que pode incluir:

- **Instructions** específicas

- **Tools** e toolsets

- **Lifecycle hooks** (lêem e reescrevem o que o modelo vê)

- **Model settings**

Isso significa que uma extensão inteira — um sistema de memória, um guardrail, um toolkit de coding — alcança todas as camadas do agente através de um único conceito.

```
from pydantic_ai import Agent
from pydantic_ai.capabilities import Thinking, WebSearch, CodeMode
from pydantic_ai_harness import Memory, Guardrails

agent = Agent(
 "anthropic:claude-opus-4-7",
 capabilities=[
 Thinking(effort="high"), # Extended thinking unificado entre providers
 CodeMode(), # Execução de código sandboxed via Monty
 WebSearch(), # Nativo onde o provider suporta, fallback local
 Memory(backend="postgres"), # Do Harness — memória persistente
 Guardrails(block_pii=True), # Do Harness — proteção automática
 ],
)
```

O **Harness** é o pacote first-party de “baterias” — capabilities prontas para produção como memória, guardrails, context management, file system access e code mode. O split é deliberado: core permanece pequeno e estável; Harness move rápido.

---

## PydanticAI vs. Outros Frameworks

Como o PydanticAI se posiciona no ecossistema de 2026? Aqui vai um comparativo honesto baseado em benchmarks reais:

 Critério
 PydanticAI
 LangGraph
 CrewAI
 Mastra

 Linguagem
 Python
 Python
 Python
 TypeScript

 DX Score (Nextbuild)
 8/10
 6/10
 7/10
 8/10

 Type Safety
 Nativo
 TypedDict
 Limitado
 Zod

 Multi-Agent
 Via tools/graph
 Nativo (grafos)
 Nativo (crews)
 Agent Networks

 Durable Execution
 Temporal/DBOS
 Checkpointing
 Nenhum
 Inngest

 Streaming
 Nativo + AG-UI
 Nativo
 Limitado
 Nativo

 Memória
 Manual (UsageLimits)
 State + checkpoint
 Unified Memory
 Observational Memory

 Custo Infraestrutura
 ~$390/90dias
 ~$670/90dias
 ~$1,088/90dias
 N/A

 Licença
 MIT
 MIT
 MIT
 Apache 2.0

 Observabilidade
 OTel nativo
 LangSmith
 Limitado
 Custom

**Dado importante do benchmark Nextbuild:** O type system do PydanticAI capturou 23 bugs durante desenvolvimento que teriam chegado em produção no LangChain. Isso é o tipo de vantagem que compound ao longo do tempo em projetos reais.

---

## Prós e Contras

### ✅ Prós

- **Type safety genuíno** — Não é cosmético. IDE, linter e runtime trabalham juntos para prevenir bugs.

- **DX excepcional** — Agente funcional em 5 linhas. Curva de aprendizado mínima se você conhece Python.

- **Dependency injection de verdade** — Testes limpos, desacoplamento real, swap de mocks trivial.

- **Model-agnostic** — 20+ providers, troque sem reescrever lógica. MCP nativo.

- **Observabilidade open-source** — OTel/Logfire sem vendor lock-in.

- **Custo-eficiente** — UsageLimits nativo (cap de tokens, requests, tool calls). Benchmarkado a $390/90 dias vs $1,088 do CrewAI.

- **100% test coverage** — Exemplos da docs são unit-testados. Raridade no ecossistema.

- **Validation retries inteligentes** — Envia erro de validação de volta ao LLM para autocorreção.

### ❌ Contras

- **Ecossistema menor** — ~15x menos integrações que LangChain. Você vai encontrar edges não documentados.

- **Multi-agent não é first-class** — Sem roles, goals, delegação autônoma. Precisa wiring manual.

- **Sem memória built-in** — Estado é manual. Sem compressão automática como Mastra.

- **Sem managed hosting** — Roda como lib Python pura. Deploy é por sua conta.

- **Retries custam dinheiro** — Cada retry de validação é uma chamada de API adicional.

- **Nem todo provider suporta structured outputs igualmente** — Gemini, OpenAI e Anthropic são os melhores; outros variam.

- **pydantic-graph é avançado** — Usa generics pesados, não é beginner-friendly.

---

## Quando Usar PydanticAI

### Use PydanticAI quando:

- **Você quer outputs validados do LLM** — O caso de uso #1. Definir schemas e obter objetos tipados é incomparável.

- **Já usa Pydantic ou FastAPI** — A experiência é idêntica. Você literalmente já sabe usar.

- **Type safety importa** — Para produção, para coding agents que trabalham no seu código, para times que valorizam correctness.

- **Precisa de testabilidade** — DI nativo + `agent.override()` tornam testes de agentes triviais.

- **Budget é preocupação** — UsageLimits controlam custos; benchmark mostrou menor custo de infra.

- **Quer observabilidade sem lock-in** — OTel funciona com qualquer stack de monitoring.

### Não use PydanticAI quando:

- **Precisa de multi-agent robusto com delegação autônoma** — Use CrewAI.

- **Precisa de workflows cíclicos complexos com checkpointing** — Use LangGraph.

- **Precisa de centenas de integrações prontas** — Use LangChain (breadth) ou n8n (visual).

- **Seu time é TypeScript** — Use Mastra ou Vercel AI SDK.

- **Precisa de hosting gerenciado** — Use LangGraph Platform ou CrewAI AMP.

---

## Próximos Passos

Se este guia te convenceu a experimentar PydanticAI, aqui está um caminho estruturado:

- **Instale e rode o exemplo básico** — `uv add pydantic-ai` → agente de 5 linhas

- **Adicione output_type** — Defina um `BaseModel` e veja a mágica da validação

- **Implemente uma tool** — Conecte a uma API real com `@agent.tool_plain`

- **Injete dependências** — Use `deps_type` e `RunContext` para desacoplar

- **Explore capabilities (v2)** — `Thinking`, `WebSearch`, `ToolSearch`

- **Configure Logfire** — Observabilidade em 2 linhas de código

- **Integre durable execution** — Temporal ou DBOS para produção

---

## Leitura Complementar

Se você está explorando o ecossistema de agentes IA, esses recursos complementam este guia:

- [Agent Frameworks vs. Coding Agents: Entenda a Diferença](/blog/agent-frameworks-vs-coding-agents) — Quando um framework é overengineering e quando é essencial.

- [Harness e Loop: A Arquitetura por Trás dos Agentes](/blog/harness-e-loop-arquitetura-agentes) — Deep dive no modelo mental “agent = loop + harness” que o PydanticAI v2 formalizou.

- [Documentação oficial PydanticAI](https://pydantic.dev/docs/ai/overview/) — Referência completa com exemplos testados.

- [PydanticAI v2: Capabilities, Harness e um core mais enxuto](https://pydantic.dev/articles/pydantic-ai-v2) — Blog post oficial do lançamento.

---

## Conclusão

PydanticAI é para quem leva Python a sério. Não é o framework com mais integrações, nem o mais visual, nem o que abstrai multi-agent em roles bonitos. É o que trata agentes IA como engenharia de software — com tipos, testes, injeção de dependência e validação.

A aposta da equipe Pydantic é clara: o caos atual dos agentes vai convergir para padrões de engenharia. E quando convergir, quem já está rodando type-safe, observável e testável vai estar muito à frente.

Se isso ressoa com o jeito que você pensa sobre software — vale cada minuto investido.

---

*Quer se manter atualizado sobre frameworks de agentes, arquitetura e AI engineering em Português? Acompanhe o [ft.ia.br](https://ft.ia.br) para conteúdo técnico sem enrolação.*

-->
