agent-builder-pydantic-ai
π―Skillfrom guaderrama/cabo-health-ai
Generates AI agent configurations with automatic Pydantic validation, streamlining complex agent design and ensuring robust data modeling for intelligent systems.
Installation
npx skills add https://github.com/guaderrama/cabo-health-ai --skill agent-builder-pydantic-aiSkill Details
Build conversational AI agents using Pydantic AI + OpenRouter. Use when creating type-safe Python agents with tool calling, validation, and streaming.
Overview
# Pydantic AI Agent Builder
Purpose
Create production-ready AI agents with type safety, automatic validation, and minimal boilerplate using Pydantic AI framework.
When to Use
- Building FastAPI backend with AI capabilities
- Need strict type checking and validation
- Want auto-retry on malformed LLM responses
- Creating agents with custom tools
Architecture Pattern
Project Structure
```
backend/
βββ agents/
β βββ __init__.py
β βββ base_agent.py # Base agent class
β βββ [feature]_agent.py # Feature-specific agents
βββ tools/
β βββ __init__.py
β βββ [tool_name].py # Tool definitions
βββ config/
βββ agent_config.py # Agent configurations
```
Installation
```bash
pip install pydantic-ai httpx pydantic python-dotenv
```
Base Agent Pattern
```python
from pydantic_ai import Agent
from pydantic import BaseModel
import os
class AgentResponse(BaseModel):
result: str
confidence: float
agent = Agent(
model='openrouter:openai/gpt-4o',
output_type=AgentResponse,
tools=[tool1, tool2],
system_prompt="You are a helpful AI assistant."
)
# Usage
result = await agent.run("user message")
```
Integration with OpenRouter
Setup
```python
import os
from pydantic_ai.models import OpenRouterModel
model = OpenRouterModel(
name='openai/gpt-4o',
api_key=os.getenv('OPENROUTER_API_KEY'),
http_referer=os.getenv('FRONTEND_URL')
)
```
Environment Variables
```bash
OPENROUTER_API_KEY=sk-or-v1-...
FRONTEND_URL=http://localhost:3000
```
Tool Definition Pattern
```python
from pydantic import BaseModel, Field
from pydantic_ai import Agent, Tool
class GenerateImageArgs(BaseModel):
prompt: str = Field(description="Image description")
num_images: int = Field(ge=1, le=10, default=1)
async def generate_image_tool(args: GenerateImageArgs) -> dict:
# Your implementation
return {"images": [...]}
# Register tool
agent.add_tool(
Tool(
name="generate_image",
description="Generate images using AI",
parameters=GenerateImageArgs,
execute=generate_image_tool
)
)
```
Streaming Pattern
```python
async def stream_response(agent, message):
async for chunk in agent.stream(message):
yield {
"type": "text" if isinstance(chunk, str) else "tool_call",
"content": chunk
}
```
Error Handling & Retry
```python
from pydantic_ai import Agent, RetryConfig
agent = Agent(
model='openrouter:openai/gpt-4o',
retry_config=RetryConfig(
max_retries=3,
retry_on=[ValidationError, TimeoutError]
)
)
# Auto-retry on validation errors
try:
result = await agent.run("user message")
except ValidationError as e:
# Will retry automatically
logger.error(f"Validation failed after retries: {e}")
```
FastAPI Integration
```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class ChatRequest(BaseModel):
message: str
history: list = []
@app.post("/chat")
async def chat_endpoint(request: ChatRequest):
try:
result = await agent.run(
request.message,
context={"history": request.history}
)
return {"response": result.result}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
```
Testing Pattern
```python
import pytest
from pydantic_ai import Agent
@pytest.mark.asyncio
async def test_agent_response():
agent = Agent(
model='openrouter:openai/gpt-4o',
system_prompt="You are a test assistant"
)
result = await agent.run("Say hello")
assert "hello" in result.lower()
```
Best Practices
- Type Safety: Always define Pydantic models for inputs/outputs
- Dependency Injection: Use FastAPI-style DI for tools
- Auto-Retry: Configure retry logic for robustness
- Logging: Add structured logging for debugging
- Testing: Write pytest tests for agent behaviors
- Validation: Let Pydantic handle validation automatically
- Context: Pass context dict for stateful conversations
Example: Complete Agent
```python
from pydantic_ai import Agent, Tool
from pydantic import BaseModel, Field
import os
# Output type
class ChatResponse(BaseModel):
message: str
tool_used: str | None = None
confidence: float = Field(ge=0, le=1)
# Tool definition
class WeatherArgs(BaseModel):
city: str
async def get_weather(args: WeatherArgs) -> dict:
# Your API call here
return {"temp": 72, "condition": "sunny"}
# Create agent
agent = Agent(
model='openrouter:openai/gpt-4o',
output_type=ChatResponse,
system_prompt="You are a helpful weather assistant."
)
# Register tool
agent.add_tool(
Tool(
name="get_weather",
description="Get current weather for a city",
parameters=WeatherArgs,
execute=get_weather
)
)
# Usage
if __name__ == "__main__":
result = await agent.run("What's the weather in SF?")
print(result.message)
```
Common Pitfalls
β Don't: Use any type
β Do: Define strict Pydantic models
β Don't: Handle retries manually
β Do: Configure RetryConfig
β Don't: Parse LLM output manually
β Do: Let Pydantic AI handle it
Resources
- [Pydantic AI Docs](https://ai.pydantic.dev)
- [OpenRouter Docs](https://openrouter.ai/docs)
- [FastAPI Docs](https://fastapi.tiangolo.com)