读完这篇,你就能用 Pydantic AI 写出自己的第一个 AI 代理程序。
Pydantic AI 是一个 Python 框架,帮你用几行代码就能调用各种大语言模型(ChatGPT、Claude、Gemini 等),而且还能让 AI 返回结构化的数据,而不是一大坨文本。
你可以把 Pydantic AI 想象成一个翻译官:
| 直接调 API | 用 Pydantic AI |
|---|---|
| 要自己拼请求、解析返回 | 框架帮你搞定 |
| 换个模型要改一堆代码 | 换模型只改一个字符串 |
| 返回的都是纯文本,自己解析 | 直接返回 Python 对象 |
| 出错了自己处理 | 自动重试、自动纠错 |
| 想让 AI 调函数?自己写一堆 JSON Schema | 加个装饰器就行 |
Pydantic AI 里最重要的就 4 个概念,先混个脸熟,后面会一个个讲:
# 推荐用 uv(速度快)
uv add pydantic-ai
# 或者用老朋友 pip
pip install pydantic-ai
这条命令会把 Pydantic AI 和所有主流模型的依赖一起装好。
uv add "pydantic-ai-slim[openai]"
Pydantic AI 支持几乎所有主流模型,你至少需要配一个。最常用的三个:
export OPENAI_API_KEY="sk-你的密钥"
export ANTHROPIC_API_KEY="你的密钥"
export GEMINI_API_KEY="你的密钥"
~/.bashrc 或 ~/.zshrc 里,这样每次打开终端就自动生效了。
新建一个 test.py,复制粘贴:
from pydantic_ai import Agent
agent = Agent('openai:gpt-4o') # 换成你有 API Key 的模型
result = agent.run_sync('说一句你好')
print(result.output)
运行:
python test.py
如果看到 AI 跟你打招呼了,恭喜,环境搭好了!
格式统一是 提供商:模型名,常用的:
| 写法 | 说明 |
|---|---|
openai:gpt-4o | OpenAI GPT-4o |
openai:gpt-4o-mini | OpenAI GPT-4o Mini(便宜) |
anthropic:claude-sonnet-4-5 | Anthropic Claude Sonnet 4.5 |
google-gla:gemini-2.0-flash | Google Gemini 2.0 Flash |
groq:llama-3.3-70b-versatile | Groq 上的 Llama(免费额度) |
上面那些模型都要花钱调 API。但实际工作中,你可能会遇到这些情况:
直接改 OPENAI_BASE_URL,代码一行不用动:
# 指向你的自定义服务地址
export OPENAI_BASE_URL="https://api.deepseek.com/v1"
export OPENAI_API_KEY="你的密钥"
from pydantic_ai import Agent
# 代码完全不变!框架会自动读环境变量
agent = Agent('openai:deepseek-chat')
result = agent.run_sync('你好')
print(result.output)
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider
model = OpenAIChatModel(
'deepseek-chat', # 模型名称
provider=OpenAIProvider(
base_url='https://api.deepseek.com/v1', # 自定义地址
api_key='你的密钥',
),
)
agent = Agent(model)
result = agent.run_sync('用 Python 写一个快速排序')
print(result.output)
Pydantic AI 为很多第三方服务内置了专门的 Provider,用起来更方便:
from pydantic_ai import Agent
# DeepSeek —— 设好环境变量就行
# export DEEPSEEK_API_KEY="你的密钥"
agent = Agent('deepseek:deepseek-chat')
# Ollama 本地模型
# export OLLAMA_BASE_URL="http://localhost:11434/v1"
agent = Agent('ollama:llama3.2')
# Together AI
# export TOGETHER_API_KEY="你的密钥"
agent = Agent('together:meta-llama/Llama-3.3-70B-Instruct-Turbo-Free')
# OpenRouter(聚合了几百个模型)
# export OPENROUTER_API_KEY="你的密钥"
agent = Agent('openrouter:anthropic/claude-sonnet-4')
# Groq(免费额度,速度快)
# export GROQ_API_KEY="你的密钥"
agent = Agent('groq:llama-3.3-70b-versatile')
如果你需要精细控制(比如超时时间、重试次数、代理设置),可以自己创建 OpenAI 客户端:
from openai import AsyncOpenAI
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider
# 完全自定义的客户端
client = AsyncOpenAI(
base_url='http://localhost:8000/v1', # 比如本地 vLLM 服务
api_key='not-needed', # 本地服务通常不需要密钥
timeout=60.0, # 超时时间
max_retries=3, # 重试次数
)
model = OpenAIChatModel(
'Qwen/Qwen2.5-72B-Instruct',
provider=OpenAIProvider(openai_client=client),
)
agent = Agent(model)
| 场景 | 配置方式 |
|---|---|
| 本地 Ollama | Agent('ollama:llama3.2') + OLLAMA_BASE_URL |
| DeepSeek API | Agent('deepseek:deepseek-chat') + DEEPSEEK_API_KEY |
| 本地 vLLM | OpenAIProvider(base_url='http://localhost:8000/v1') |
| 硅基流动 / 零一万物等 | OpenAIProvider(base_url='https://api.xxx.com/v1', api_key='...') |
| Azure OpenAI | Agent('azure:gpt-4o') + AZURE_OPENAI_ENDPOINT |
| OpenRouter | Agent('openrouter:模型名') + OPENROUTER_API_KEY |
| Together AI | Agent('together:模型名') + TOGETHER_API_KEY |
| LiteLLM 代理 | LiteLLMProvider(api_base='http://localhost:4000') |
base_url 但没传 api_key,框架会自动设一个占位符,这样连本地不需要认证的模型服务也能直接用,不会报错。
先看最简单的用法——跟 AI 聊天:
from pydantic_ai import Agent
# 创建一个代理
agent = Agent(
'openai:gpt-4o',
instructions='你是一个友好的助手,用中文回答。'
)
# 同步运行
result = agent.run_sync('Python 是什么?一句话解释')
print(result.output)
# 输出类似:Python 是一种简洁易读的高级编程语言,广泛用于 Web 开发、数据分析和人工智能等领域。
这跟直接调 API 差不多,没啥特别的。接下来才是 Pydantic AI 的亮点。
想象一个场景:你给 AI 一段文本,让它提取出城市和国家信息。
如果用普通 API,AI 会返回类似 "城市是芝加哥,国家是美国" 这样的文本,你还得自己写正则去解析。
用 Pydantic AI,你只需要定义一个数据模型:
from pydantic import BaseModel
from pydantic_ai import Agent
# 第一步:定义你想要的数据结构
class CityInfo(BaseModel):
city: str # 城市名
country: str # 国家名
# 第二步:创建代理,指定输出类型
agent = Agent(
'openai:gpt-4o',
output_type=CityInfo # 告诉 AI:你必须返回这个格式
)
# 第三步:运行
result = agent.run_sync('美国的风城是哪里?')
# result.output 直接就是一个 CityInfo 对象!
print(result.output)
# 输出:city='Chicago' country='United States'
# 可以直接用点号访问属性
print(f'城市:{result.output.city}')
print(f'国家:{result.output.country}')
CityInfo 模型,告诉框架"我要城市和国家"from pydantic import BaseModel, Field
from pydantic_ai import Agent
class BookInfo(BaseModel):
title: str = Field(description='书名')
author: str = Field(description='作者')
year: int = Field(description='出版年份')
summary: str = Field(description='一句话简介')
agent = Agent(
'openai:gpt-4o',
output_type=BookInfo,
instructions='你是一个图书信息助手。'
)
result = agent.run_sync('介绍一下《三体》')
book = result.output
print(f'书名:{book.title}')
print(f'作者:{book.author}')
print(f'年份:{book.year}')
print(f'简介:{book.summary}')
这意味着你可以:
# 用在 if 判断里
if book.year > 2000:
print('这是一本21世纪的书')
# 放进列表
books = []
books.append(book)
# 转成字典
print(book.model_dump())
# {'title': '三体', 'author': '刘慈欣', 'year': 2008, 'summary': '...'}
# 转成 JSON
print(book.model_dump_json())
AI 模型有两个天生的短板:
工具(Tool) 就是解决这个问题的:你写一个 Python 函数,AI 在需要的时候会自动去调用它,拿到真实数据后再回答你。
from pydantic_ai import Agent
agent = Agent(
'openai:gpt-4o',
instructions='你是一个数学助手。需要计算时请使用工具。'
)
@agent.tool_plain
def add(a: float, b: float) -> float:
"""两个数相加。
Args:
a: 第一个数
b: 第二个数
"""
return a + b
@agent.tool_plain
def multiply(a: float, b: float) -> float:
"""两个数相乘。
Args:
a: 第一个数
b: 第二个数
"""
return a * b
result = agent.run_sync('请计算 (3 + 5) * 2')
print(result.output)
# 输出:(3 + 5) * 2 = 16
add(3, 5) → 返回 8multiply(8, 2) → 返回 16AI 可以自动决定调用哪个工具、调用几次、传什么参数。你只负责把函数写好就行。
@agent.tool_plain —— 简单工具,不需要上下文@agent.tool_plain
def get_current_time() -> str:
"""获取当前时间。"""
from datetime import datetime
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@agent.tool —— 需要访问上下文的工具有时候工具需要访问外部传入的数据(比如数据库连接、用户 ID 等),这就要用 RunContext:
from dataclasses import dataclass
from pydantic_ai import Agent, RunContext
# 定义依赖:你想传给工具的数据
@dataclass
class GameDeps:
winning_number: int # 中奖号码
agent = Agent(
'openai:gpt-4o',
deps_type=GameDeps, # 声明依赖类型
output_type=bool, # 输出是 True/False
instructions='用 check_number 工具检查用户猜的数字是否正确。'
)
@agent.tool
def check_number(ctx: RunContext[GameDeps], guess: int) -> str:
"""检查猜测的数字是否是中奖号码。
Args:
guess: 用户猜测的数字
"""
if guess == ctx.deps.winning_number:
return '恭喜,猜对了!'
else:
return f'没猜对,不是 {guess}'
# 运行时传入依赖
deps = GameDeps(winning_number=42)
result = agent.run_sync('我猜是 42', deps=deps)
print(result.output) # True
result = agent.run_sync('我猜是 7', deps=deps)
print(result.output) # False
ctx.deps 就是你传进去的 GameDeps 对象ctx 参数,只看到 guess 参数@agent.tool_plain
def search_product(name: str, max_price: float = 100.0) -> str:
"""在商品库中搜索商品。
Args:
name: 商品名称关键词
max_price: 最高价格,默认 100
"""
# 你的搜索逻辑
return f'找到了 {name},价格在 {max_price} 以内'
框架会自动提取:
search_product)恭喜!你已经掌握了 Pydantic AI 的三大核心用法:
agent.run_sync('...')output_type=你的模型@agent.tool你现在能做的事:
openai:gpt-4o 换成 anthropic:claude-sonnet-4-5 或 google-gla:gemini-2.0-flash,看看效果有什么不同CityInfo 里加个 population: int 字段,让 AI 顺便返回人口