Introducing PydanticAI: A Cleaner Way to Build AI Agents
As a long-time engineer, I’ve spent years integrating libraries, wrangling APIs, and wrestling with tools that promised the world but delivered messy, brittle code. When it comes to Generative AI, the problem compounds—structured responses, validation, and testing are often an afterthought.
Enter PydanticAI: a lightweight, type-safe Agent Framework designed to make building AI-powered applications in Python feel like regular, well-structured Python development.
If you’re familiar with Pydantic (a cornerstone of tools like FastAPI, LangChain, and OpenAI SDK), you’ll feel right at home.
Why PydanticAI Stands Out
PydanticAI was built with the same philosophy that made Pydantic itself so valuable: clean validation, structured responses, and ease of integration. Here’s why it matters:
- Model Agnostic: Supports OpenAI, Google Gemini, and Groq, with Anthropic coming soon.
- Type-Safe by Default: Type hints are integral, not optional, ensuring cleaner code and fewer runtime surprises.
- Structured Responses: Responses are validated using Pydantic models, not loosely formatted JSON.
- Dependency Injection: Inject dependencies (e.g., DB connections, user context) cleanly using a simple, type-safe system.
- Simple Control Flow: No proprietary DSLs or black-box abstractions—just Python best practices.
- Logfire Integration: Debug, monitor, and understand your agent’s behavior effortlessly.
- Streamed Responses: Validate and process outputs in real time with confidence.
The bottom line? You can build production-ready AI applications without sacrificing clean code or predictability.
Example: Building a Support Agent
Here’s a practical example. Imagine building a bank support agent that:
- Fetches a customer’s balance,
- Assesses risk based on their query, and
- Returns a structured response validated with Pydantic.
from dataclasses import dataclass
from pydantic import BaseModel, Field
from pydantic_ai import Agent, RunContext
@dataclass
class SupportDependencies:
customer_id: int
db: DatabaseConn # Your database connection
class SupportResult(BaseModel):
support_advice: str = Field(description="Advice for the customer")
block_card: bool = Field(description="Block the customer's card?")
risk: int = Field(description="Risk level", ge=0, le=10)
support_agent = Agent(
"openai:gpt-4o",
deps_type=SupportDependencies,
result_type=SupportResult,
system_prompt="Provide support and assess risk level for the customer's query.",
)
@support_agent.tool
async def check_balance(ctx: RunContext[SupportDependencies]) -> float:
"""Fetch the customer's current balance."""
return await ctx.deps.db.customer_balance(ctx.deps.customer_id)
# Running the agent
async def main():
deps = SupportDependencies(customer_id=123, db=DatabaseConn())
result = await support_agent.run("What is my balance?", deps=deps)
print(result.data)
#> support_advice="Your balance is $123.45." block_card=False risk=1
With minimal boilerplate, PydanticAI gives you structured results, dependency injection, and robust control—all while sticking to clean, type-safe Python patterns.
A Developer-First AI Framework
PydanticAI is still in beta, but its foundation is solid. It brings together everything that senior engineers value:
- Explicit over implicit: No magic strings or confusing DSLs.
- Testable and Extensible: Dependency injection makes it straightforward to test and iterate.
- Familiarity: If you know Pydantic, this will feel natural.
It’s a framework built for developers who care about clean, maintainable code—even when working with the unpredictable nature of LLMs.
Get Started with PydanticAI
If you’re building with Generative AI, this is worth exploring. It’s type-safe, structured, and built with Python best practices in mind.
Start small, test it out, and let me know what you think:
Explore PydanticAI →