解锁 AI 的隐藏技能:让它思考、搜网页、执行代码、看图片、连外部服务。
你有没有遇到过 AI 胡说八道的情况?让它做数学题、写复杂逻辑时,经常翻车。
思考模式就是让 AI 在回答之前先"打个草稿" —— 它会把推理过程写出来,然后再给你最终答案。就像考试时先在草稿纸上演算,再把答案抄到答题卡上。
Claude 的思考模式最成熟,通过 anthropic_thinking 参数开启:
from pydantic_ai import Agent
from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings
model = AnthropicModel('claude-sonnet-4-5')
settings = AnthropicModelSettings(
anthropic_thinking={
'type': 'enabled',
'budget_tokens': 1024, # 给思考过程分配的 token 预算
},
)
agent = Agent(model, model_settings=settings)
result = agent.run_sync('15 的阶乘是多少?')
print(result.output)
budget_tokens 是什么? 就是你给 AI "打草稿"分配的额度。设大了思考得更充分但更贵更慢,设小了可能想不明白。通常 1024~10000 够用。
从 Claude Opus 4.6 开始,支持让 AI 自己决定要不要思考、思考多久:
model = AnthropicModel('claude-opus-4-6')
settings = AnthropicModelSettings(
anthropic_thinking={'type': 'adaptive'}, # AI 自己决定
anthropic_effort='high', # 高努力 = 思考更多
)
agent = Agent(model, model_settings=settings)
'low'(简单问题快速回答)、'medium'(默认)、'high'(复杂问题深度思考)
OpenAI 的推理功能需要用 Responses API(注意不是普通的 Chat API):
from pydantic_ai import Agent
from pydantic_ai.models.openai import (
OpenAIResponsesModel,
OpenAIResponsesModelSettings,
)
model = OpenAIResponsesModel('gpt-5.2')
settings = OpenAIResponsesModelSettings(
openai_reasoning_effort='low', # low / medium / high
openai_reasoning_summary='detailed', # 思考摘要
)
agent = Agent(model, model_settings=settings)
result = agent.run_sync('解释量子纠缠')
print(result.output)
from pydantic_ai import Agent
from pydantic_ai.models.google import GoogleModel, GoogleModelSettings
model = GoogleModel('gemini-3-pro-preview')
settings = GoogleModelSettings(
google_thinking_config={'include_thoughts': True}
)
agent = Agent(model, model_settings=settings)
Groq 上的推理模型(如 QwQ):
from pydantic_ai import Agent
from pydantic_ai.models.groq import GroqModel, GroqModelSettings
model = GroqModel('qwen-qwq-32b')
settings = GroqModelSettings(
groq_reasoning_format='parsed', # 'raw' | 'hidden' | 'parsed'
)
agent = Agent(model, model_settings=settings)
| 提供商 | 模型示例 | 关键设置 |
|---|---|---|
| Anthropic | claude-sonnet-4-5 | anthropic_thinking |
| OpenAI | gpt-5.2(Responses) | openai_reasoning_effort |
gemini-3-pro-preview | google_thinking_config | |
| Groq | qwen-qwq-32b | groq_reasoning_format |
| OpenRouter | 各种模型 | openrouter_reasoning |
| xAI | grok-4-fast-reasoning | xai_include_encrypted_content |
之前我们写的工具都是自己实现的(@agent.tool)。但有些能力是 AI 提供商原生自带的 —— 搜网页、跑代码、生图片等。这些不需要你写代码,直接开启就行。
用法很简单,通过 builtin_tools 参数传给 Agent:
from pydantic_ai import Agent, WebSearchTool
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[WebSearchTool()], # 直接传进去
)
让 AI 能上网搜索最新信息,不再局限于训练数据的截止日期。
from pydantic_ai import Agent, WebSearchTool
# Anthropic
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[WebSearchTool()],
)
result = agent.run_sync('本周 AI 领域最大的新闻是什么?')
print(result.output)
# OpenAI 需要用 Responses 模型
agent = Agent(
'openai-responses:gpt-5.2',
builtin_tools=[WebSearchTool()],
)
from pydantic_ai import Agent, WebSearchTool, WebSearchUserLocation
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[
WebSearchTool(
user_location=WebSearchUserLocation(
city='Beijing',
country='CN',
),
blocked_domains=['spam-site.net'], # 屏蔽的网站
allowed_domains=None, # 只允许的网站(与 blocked 二选一)
max_uses=5, # 最多搜索几次(仅 Anthropic)
)
],
)
search_context_size 和 allowed_domains;Anthropic 支持 blocked_domains 和 max_uses;Google 不支持任何参数。
让 AI 写完代码后直接在沙箱里运行,特别适合数学计算、数据处理:
from pydantic_ai import Agent, CodeExecutionTool
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[CodeExecutionTool()],
)
result = agent.run_sync('计算 15 的阶乘')
print(result.output)
# 15 的阶乘是 1,307,674,368,000
让 AI 直接生成图片:
from pydantic_ai import Agent, BinaryImage, ImageGenerationTool
agent = Agent(
'openai-responses:gpt-5.2',
builtin_tools=[ImageGenerationTool()],
)
result = agent.run_sync('画一只穿西装的猫')
print(result.output) # 文字描述
# 图片在这里
image = result.response.images[0] # BinaryImage 对象
# image.data 就是图片的二进制数据,可以保存为文件
agent = Agent(
'openai-responses:gpt-5.2',
builtin_tools=[
ImageGenerationTool(
size='1024x1024', # 尺寸
quality='high', # 质量
output_format='png', # 格式
background='transparent', # 透明背景
)
],
output_type=BinaryImage, # 直接输出图片
)
让 AI 直接访问指定 URL 获取内容:
from pydantic_ai import Agent, WebFetchTool
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[WebFetchTool()],
)
result = agent.run_sync('总结一下 https://ai.pydantic.dev 的内容')
print(result.output)
不用自己搭 MCP 客户端,直接让提供商帮你连接:
from pydantic_ai import Agent, MCPServerTool
agent = Agent(
'anthropic:claude-sonnet-4-5',
builtin_tools=[
MCPServerTool(
id='deepwiki',
url='https://mcp.deepwiki.com/mcp',
)
],
)
result = agent.run_sync('介绍一下 pydantic/pydantic-ai 这个仓库')
print(result.output)
提供商托管的 RAG 系统,自动处理文件上传、分块、嵌入、搜索:
from pydantic_ai import Agent, FileSearchTool
from pydantic_ai.models.openai import OpenAIResponsesModel
model = OpenAIResponsesModel('gpt-5.2')
# 先上传文件到 OpenAI(只需做一次)
# file = await model.client.files.create(file=open('doc.txt','rb'), purpose='assistants')
# vector_store = await model.client.vector_stores.create(name='my-docs')
# await model.client.vector_stores.files.create(vector_store_id=vector_store.id, file_id=file.id)
agent = Agent(
model,
builtin_tools=[
FileSearchTool(file_store_ids=['vs_xxx']), # 向量存储 ID
],
)
result = agent.run_sync('文档里关于 Pydantic 说了什么?')
有时候需要根据运行时条件决定是否启用某个工具:
from pydantic_ai import Agent, RunContext, WebSearchTool
async def maybe_search(ctx: RunContext[dict]) -> WebSearchTool | None:
"""只有传了位置信息时才启用搜索"""
if not ctx.deps.get('location'):
return None
return WebSearchTool(
user_location={'city': ctx.deps['location']},
)
agent = Agent(
'openai-responses:gpt-5.2',
builtin_tools=[maybe_search], # 传函数而不是实例
deps_type=dict,
)
# 有位置 → 启用搜索
result = agent.run_sync('今天天气怎么样?', deps={'location': 'Beijing'})
# 没位置 → 不启用搜索
result = agent.run_sync('法国的首都是哪里?', deps={'location': None})
| 工具 | OpenAI | Anthropic | xAI | Groq | |
|---|---|---|---|---|---|
| WebSearchTool | Responses | 完整 | 无参数 | 部分 | 混合模型 |
| CodeExecutionTool | 完整 | 完整 | 完整 | 完整 | 不支持 |
| ImageGenerationTool | Responses | 不支持 | 图片模型 | 不支持 | 不支持 |
| WebFetchTool | 不支持 | 完整 | 无参数 | 不支持 | 不支持 |
| MCPServerTool | Responses | 完整 | 不支持 | 完整 | 不支持 |
| FileSearchTool | Responses | 不支持 | Gemini | 不支持 | 不支持 |
MCP(Model Context Protocol) 是一个标准化协议,让 AI 应用能连接到外部工具和服务。就像 USB 是电脑连接外设的标准,MCP 是 AI 连接工具的标准。
有了 MCP,你的 AI Agent 可以:
适合远程 MCP 服务器:
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStreamableHTTP
server = MCPServerStreamableHTTP('http://localhost:8000/mcp')
agent = Agent('openai:gpt-4o', toolsets=[server])
async def main():
result = await agent.run('7 加 5 等于多少?')
print(result.output) # 答案是 12
MCP 服务器作为子进程运行,通过标准输入/输出通信:
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
server = MCPServerStdio(
'python', args=['mcp_server.py'],
timeout=10,
)
agent = Agent('openai:gpt-4o', toolsets=[server])
from pydantic_ai.mcp import MCPServerSSE
server = MCPServerSSE('http://localhost:3001/sse')
用 FastMCP 几行代码就能写一个:
from mcp.server.fastmcp import FastMCP
app = FastMCP('我的工具服务器')
@app.tool()
def add(a: int, b: int) -> int:
"""两数相加"""
return a + b
@app.tool()
def multiply(a: int, b: int) -> int:
"""两数相乘"""
return a * b
if __name__ == '__main__':
app.run(transport='streamable-http')
然后客户端连过去:
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStreamableHTTP
server = MCPServerStreamableHTTP('http://localhost:8000/mcp')
agent = Agent('openai:gpt-4o', toolsets=[server])
async def main():
result = await agent.run('3 乘以 7 再加 5 等于多少?')
print(result.output) # 26
对于多个 MCP 服务器,可以用 JSON 配置:
{
"mcpServers": {
"calculator": {
"url": "http://localhost:8000/mcp"
},
"python-runner": {
"command": "uv",
"args": ["run", "mcp-run-python", "stdio"]
},
"weather": {
"command": "python",
"args": ["weather_server.py"],
"env": {
"API_KEY": "${WEATHER_API_KEY}"
}
}
}
}
${WEATHER_API_KEY} —— 支持环境变量替换,敏感信息不用写死在配置里。
加载使用:
from pydantic_ai import Agent
from pydantic_ai.mcp import load_mcp_servers
servers = load_mcp_servers('mcp_config.json')
agent = Agent('openai:gpt-4o', toolsets=servers)
连接多个 MCP 服务器时,工具名可能冲突。加前缀解决:
weather_server = MCPServerStreamableHTTP(
'http://localhost:3001/mcp',
tool_prefix='weather', # 工具名变成 weather_xxx
)
calc_server = MCPServerStreamableHTTP(
'http://localhost:3002/mcp',
tool_prefix='calc', # 工具名变成 calc_xxx
)
agent = Agent('openai:gpt-4o', toolsets=[weather_server, calc_server])
有时候 MCP 服务器自己也需要调用 AI(但它没有 API Key)。采样(Sampling) 让服务器可以借用客户端的 AI 模型:
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
server = MCPServerStdio('python', args=['generate_svg.py'])
agent = Agent('openai:gpt-4o', toolsets=[server])
async def main():
# 告诉所有 MCP 服务器可以借用 Agent 的模型
agent.set_mcp_sampling_model()
result = await agent.run('生成一个机器人的 SVG 图片')
print(result.output)
让 AI 看懂图片:
from pydantic_ai import Agent, ImageUrl
agent = Agent('openai:gpt-4o')
# 方式一:传 URL
result = agent.run_sync([
'这个 logo 是什么公司的?',
ImageUrl(url='https://iili.io/3Hs4FMg.png'),
])
print(result.output)
# 这是 Pydantic 的 logo
# 方式二:传本地文件
from pydantic_ai import BinaryContent
with open('photo.png', 'rb') as f:
image_data = f.read()
result = agent.run_sync([
'描述这张图片',
BinaryContent(data=image_data, media_type='image/png'),
])
run_sync() 的第一个参数变成了一个列表,里面混合文字和媒体内容。
from pydantic_ai import Agent, AudioUrl, VideoUrl
agent = Agent('google-gla:gemini-2.0-flash')
# 音频
result = agent.run_sync([
'这段音频说了什么?',
AudioUrl(url='https://example.com/audio.mp3'),
])
# 视频
result = agent.run_sync([
'这个视频讲的是什么?',
VideoUrl(url='https://example.com/video.mp4'),
])
from pydantic_ai import Agent, DocumentUrl
agent = Agent('anthropic:claude-sonnet-4-5')
# 从 URL 读取 PDF
result = agent.run_sync([
'总结这篇论文的主要内容',
DocumentUrl(url='https://example.com/paper.pdf'),
])
# 从本地文件读取
from pathlib import Path
from pydantic_ai import BinaryContent
pdf_data = Path('report.pdf').read_bytes()
result = agent.run_sync([
'这份报告的关键数据是什么?',
BinaryContent(data=pdf_data, media_type='application/pdf'),
])
| 模型 | 图片 | 音频 | 视频 | |
|---|---|---|---|---|
| OpenAI Chat | URL 直发 | 需下载 | 不支持 | 需下载 |
| OpenAI Responses | URL 直发 | URL 直发 | 不支持 | URL 直发 |
| Anthropic | URL 直发 | 不支持 | 不支持 | URL 直发 |
| Google (Vertex) | 全部 URL | 全部 URL | 全部 URL | 全部 URL |
| Google (GLA) | 需下载 | 需下载 | YouTube 直发 | 需下载 |
force_download=True 强制先下载。
某些场景下你想确保由 Pydantic AI 来下载(比如 URL 需要认证):
from pydantic_ai import ImageUrl
ImageUrl(
url='https://internal.company.com/image.png',
force_download=True, # 不管模型支不支持 URL,都先下载
)
Agent 是个全能管家,但有时候你只是想简单调一次模型,不需要工具、不需要重试、不需要结构化输出。这时候用 Direct API 更轻量。
from pydantic_ai import ModelRequest
from pydantic_ai.direct import model_request_sync
# 一句话搞定
response = model_request_sync(
'anthropic:claude-haiku-4-5',
[ModelRequest.user_text_prompt('法国的首都是哪里?')],
)
print(response.parts[0].content)
# 法国的首都是巴黎。
print(response.usage)
# RequestUsage(input_tokens=56, output_tokens=7)
from pydantic_ai.direct import (
model_request, # 异步
model_request_sync, # 同步
model_request_stream, # 异步流式
model_request_stream_sync, # 同步流式
)
Direct API 也能传工具定义,但需要你自己处理工具调用:
from pydantic import BaseModel
from pydantic_ai import ModelRequest, ToolDefinition
from pydantic_ai.direct import model_request
from pydantic_ai.models import ModelRequestParameters
class Divide(BaseModel):
"""两数相除"""
numerator: float
denominator: float
async def main():
response = await model_request(
'openai:gpt-4o',
[ModelRequest.user_text_prompt('123 除以 456 等于多少?')],
model_request_parameters=ModelRequestParameters(
function_tools=[
ToolDefinition(
name='divide',
description='两数相除',
parameters_json_schema=Divide.model_json_schema(),
)
],
allow_text_output=True,
),
)
# response 可能是文本回复,也可能是工具调用
print(response)
import logfire
from pydantic_ai import ModelRequest
from pydantic_ai.direct import model_request_sync
logfire.configure()
# 方式一:全局启用
logfire.instrument_pydantic_ai()
# 方式二:单次请求启用
response = model_request_sync(
'anthropic:claude-haiku-4-5',
[ModelRequest.user_text_prompt('你好')],
instrument=True, # 只监控这一次
)
| 需求 | 选择 |
|---|---|
| 需要工具调用 | Agent |
| 需要结构化输出 | Agent |
| 需要重试和验证 | Agent |
| 需要多轮对话 | Agent |
| 只是简单问答 | Direct |
| 想自己控制一切 | Direct |
| 构建自定义抽象 | Direct |
| 特性 | 一句话总结 | 典型场景 |
|---|---|---|
| 思考模式 | 让 AI 先想再答 | 数学、逻辑、复杂推理 |
| 内置工具 | 提供商原生能力 | 搜网页、跑代码、生图片 |
| MCP 集成 | 连接外部服务 | 数据库、文件系统、API |
| 多模态输入 | 看图听声读文档 | 图片识别、PDF 分析 |
| Direct API | 轻量级调用 | 简单问答、自定义封装 |
from pydantic_ai import Agent
from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings
model = AnthropicModel('claude-sonnet-4-5')
settings = AnthropicModelSettings(
anthropic_thinking={
'type': 'enabled',
'budget_tokens': 2048,
},
)
math_agent = Agent(
model,
model_settings=settings,
instructions='你是一个数学老师,解题时要展示详细的推理过程。',
)
result = math_agent.run_sync('一个水池有两个进水管和一个排水管...')
print(result.output)
from pydantic_ai import Agent, ImageUrl
from pydantic import BaseModel
class ImageAnalysis(BaseModel):
description: str
objects: list[str]
mood: str
agent = Agent(
'openai:gpt-4o',
output_type=ImageAnalysis,
)
result = agent.run_sync([
'分析这张图片',
ImageUrl(url='https://example.com/photo.jpg'),
])
print(f'描述: {result.output.description}')
print(f'物体: {result.output.objects}')
print(f'氛围: {result.output.mood}')
服务端(calc_server.py):
from mcp.server.fastmcp import FastMCP
app = FastMCP('Calculator')
@app.tool()
def calculate(expression: str) -> str:
"""安全地计算数学表达式。"""
try:
result = eval(expression, {"__builtins__": {}})
return str(result)
except Exception as e:
return f'计算错误: {e}'
if __name__ == '__main__':
app.run()
客户端:
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
server = MCPServerStdio('python', args=['calc_server.py'])
agent = Agent('openai:gpt-4o', toolsets=[server])
async def main():
result = await agent.run('(123 + 456) * 789 等于多少?')
print(result.output)