PydanticAI 是一个 Python 代理框架,旨在让构建生产级别的应用程序使用生成式人工智能变得更加简单。
FastAPI 通过提供创新而符合人体工学的设计,革新了 web 开发,该设计是基于 Pydantic 构建的。
同样,几乎每一个Python中的代理框架和LLM库都使用Pydantic,然而当我们开始在Pydantic Logfire中使用LLM时,我们却找不到任何能给我们同样感觉的东西。
PydanticAI 的设计有一个简单的宗旨:让开发 GenAI 应用拥有 FastAPI 的感觉。
要为什么用PydanticAI由 Pydantic 团队开发
由 Pydantic(OpenAI SDK、Anthropic SDK、LangChain、LlamaIndex、AutoGPT、Transformers、CrewAI、Instructor 等项目的验证层)团队开发。
模型无关性
支持OpenAI、Anthropic、Gemini、Ollama、Groq和Mistral等,有一个简单的接口来实现对其他模型(如此处所示)的支持。
Pydantic Logfire 集成方案
可无缝地与 Pydantic Logfire 集成,用于实时调试、性能监控以及由 LLM 驱动的应用程序的行为追踪。
类型安全
旨在让你的类型检查尽可能有用,因此它能很好地与静态类型检查器如 mypy 和 pyright 配合。
基于Python的设计
利用您熟悉的Python控制结构和代理组合来构建您的AI驱动项目,使其能够轻松应用您在其他任何项目(除了AI项目)中使用的标准Python最佳实践。
结构化响应(注:确保模型输出的一致性和规范性)
利用Pydantic来验证和结构化模型输出,确保响应在每次运行中保持一致。
依赖注入系统功能
提供一个可选的依赖注入功能,用于将数据和服务提供给您的代理的系统提示消息、工具和结果验证器。这对于测试和基于评估的迭代开发很有帮助。
连续流式响应
提供连续流式传输大型语言模型输出的能力,实现即时验证,确保快速且准确的结果。
PydanticAI 不特定于任何模型,并支持内置以下模型提供商:包括以下模型提供商:
你也可以添加对其他模型的支持。(https://ai.pydantic.dev/models/#implementing-custom-models)
PydanticAI 还包括了 [测试模型](https://ai.pydantic.dev/api/models/test/)
和 [功能模型](https://ai.pydantic.dev/api/models/function/)
用于测试以及开发目的。
使用模型提供商之前,您需要先配置好本地环境并确保安装了所需的软件包,以便顺利运行模型提供商的服务。
*一些代码例子:*让我来解释这段演示 PydanticAI 基本用法的代码,它展示了用于构建 LLM 驱动应用程序的框架的基本用法:
例子 — 1:- 导入及设置配置:
# --------------------------------------------------------------
# 1. PydanticAI 的一个最简单的示例,包含一个简单的智能代理
# --------------------------------------------------------------
from pydantic import BaseModel, Field
from pydantic_ai import Agent, ModelRetry, 运行上下文, 工具
from pydantic_ai.models.openai import OpenAIModel
-
从 Pydantic 和 PydanticAI 导入所需的组件
-
nest_asyncio.apply()
让 Jupyter 笔记本支持异步操作 load_dotenv()
加载环境变量(可能包含 API 密钥等环境变量)
2. 模型初始化:
模型定义如下:model = OpenAIModel("迷你版GPT-4o")
创建一个OpenAI模型的实例
3. 创建基本代理:
agent = Agent(
model,
system_prompt='用一句话简洁回答。',
)
创建一个简单的代理程序,使用以下组件。
- 指定的OpenAI模型
-
- 简洁回答的系统提示
4. 代理执行:
result = agent.run_sync("“你好,世界”这个说法是从哪里来的?")
打印 result.data 的内容
- 同步运行代理并提出问题,然后打印响应内容。
输出:
主要特点:
- 类型安全:使用Pydantic进行类型验证,确保类型安全
- 结构化响应:通过Pydantic模型实现结构化输出
- 生产就绪:设计用于生产环境,提供适当的错误处理
- 异步支持:支持同步和异步两种操作方式
以下是一个最小示例,展示了如何进行PydanticAI的基本设置和使用,演示了如何创建一个能够处理查询并返回结构化响应的简单代理程序。该框架特别适合用来构建稳健的AI应用程序,具有类型安全和结构化数据处理功能。
例子 2: # --------------------------------------------------------------
# 2. 简单代理 - Hello World 示例
# --------------------------------------------------------------
"""
本示例演示了 PydanticAI 代理的基本用法。
关键概念:
- 使用系统提示创建基本代理
- 运行同步查询
- 访问响应数据、消息历史记录和成本
"""
agent1 = Agent(
model=model,
system_prompt="你是一个乐于助人的客服代理。请简洁而友好。",
)
# 基本代理的示例
response = agent1.run_sync("如何追踪我的订单号为#12345的订单?")
print(response.data)
输出结果如下:
例子 3: # --------------------------------------------------------------
# 3. 具有结构化响应的代理(Agent)
# --------------------------------------------------------------
"""
本示例展示了如何从代理处获取结构化和类型安全的响应。
关键概念:
- 使用Pydantic模型定义响应的结构
- 类型验证和安全性保障
- 字段描述以便更好地理解模型
"""
class ResponseModel(BaseModel):
"""带有元数据的结构化响应。"""
response: str
needs_escalation: bool
follow_up_required: bool
sentiment: str = Field(description="客户情绪分析:表示客户的情绪分析结果")
agent2 = Agent(
model=model,
result_type=ResponseModel,
system_prompt=(
"你是一个智能的客户支持代理,"
"仔细分析查询,并提供结构化的响应。"
),
)
response = agent2.run_sync("如何追踪我的订单#12345?")
print(response.data.model_dump_json(indent=2))
- Pydantic 模型的定义
使用 Pydantic 的“BaseModel”创建一个结构化的响应模型
定义了四个具有特定类型的字段,分别是:
response
: 包含回答内容的字符串needs_escalation
: 是否需要升级的布尔标志follow_up_required
: 是否需要跟进的布尔标志sentiment
: 情感分析结果
2. 高级代理的创建 :
这里我们创建了agent2
3. 处理响应:
我们在这里创建了回复。
- 执行查询并将响应格式化为 JSON 格式
- 输出格式如下:
{
"response": "你可以通过追踪你的订单#12345来获取更多信息。",
"needs_escalation": false,
"follow_up_required": true,
"sentiment": "中性"
}
4: 输出为:
例子4: # --------------------------------------------------------------
# 4. 带结构化响应和依赖的代理
# --------------------------------------------------------------
"""
本示例演示了如何在代理中使用依赖项和上下文。
关键概念:
- 使用 Pydantic 定义复杂的数据模型
- 注入运行时依赖项
- 使用动态系统提示
情绪分析:客户情绪分析
"""
# 定义订单模式
class Order(BaseModel):
"""订单详情的结构。"""
order_id: str
status: str
items: List[str]
# 定义客户模式
class CustomerDetails(BaseModel):
"""传入客户查询的结构。"""
customer_id: str
name: str
email: str
orders: Optional[List[Order]] = None
class ResponseModel(BaseModel):
"""带有元数据的结构化响应。"""
response: str
needs_escalation: bool
follow_up_required: bool
sentiment: str = Field(description="客户情绪分析")
# 带有结构化输出和依赖的代理
agent5 = Agent(
model=model,
result_type=ResponseModel,
deps_type=CustomerDetails,
retries=3,
system_prompt=(
"你是一个智能客服代表。"
"仔细分析查询并提供结构化的响应。"
"请始终友好地问候客户,并提供有用的响应。"
), # 这些在编写代码时已确定
)
# 基于依赖项添加动态系统提示
@agent5.system_prompt
async def add_customer_name(ctx: RunContext[CustomerDetails]) -> str:
return f"客户详情:{to_markdown(ctx.deps)}" # 这些依赖于运行时的上下文
customer = CustomerDetails(
customer_id="1",
name="John Doe",
email="john.doe@example.com",
orders=[
Order(order_id="12345", status="已发货", items=["蓝色牛仔裤", "T恤"]),
],
)
response = agent5.run_sync(user_prompt="我订了什么?", deps=customer)
print(response.data.model_dump_json(indent=2))
print(
"客户详情:\n"
f"姓名:{customer.name}\n"
f"邮箱:{customer.email}\n\n"
"响应详情:\n"
f"{response.data.response}\n\n"
"处理状态:\n"
f"是否需要后续跟进:{response.data.follow_up_required}\n"
f"是否需要升级处理:{response.data.needs_escalation}"
)
- 数据模型的定义:
- 定义三个 Pydantic 模型来处理结构化的输入数据
- 创建了包含 Orders 的 CustomerDetails 层次模型——类(如 Order, CustomerDetails, ResponseModel)
2. 高级代理设置
- 同时规定了响应类型和依赖类型
- 包含重试机制(最多尝试三次)
- 设定系统基本提示
3. 动态提示:
- 在系统提示中添加运行时上下文
- 使用装饰器模式实现动态提示
- 将客户信息转为 Markdown 格式
4. 响应管理 :
- 打印格式化的 JSON 回应
- 显示客户信息和回应状态
5. 输出:
一些主要的特点:
- 依赖注入:通过依赖注入提供运行时上下文
- 复杂数据建模:带有关系的嵌套模型
- 动态提示:上下文感知的动态提示
- 类型安全:全程类型安全检查
- 错误处理:为了提高可靠性而设计的重试机制
# --------------------------------------------------------------
# 5. 带有工具的代理
# --------------------------------------------------------------
"""
本示例展示了如何通过自定义工具增强代理。
关键概念:
- 创建和注册工具
- 在工具中访问上下文
"""
shipping_info_db: Dict[str, str] = {
"12345": "2024年12月1日已发货",
"67890": "正在派送",
}
# 定义订单结构
class Order(BaseModel):
"""订单详情结构"""
order_id: str
status: str
items: List[str]
# 定义客户结构
class CustomerDetails(BaseModel):
"""传入的客户查询结构"""
customer_id: str
name: str
email: str
orders: Optional[List[Order]] = None
class ResponseModel(BaseModel):
"""带元数据的结构化响应"""
response: str
follow_up_required: bool
needs_escalation: bool
sentiment: str = Field(description="客户情绪分析")
customer = CustomerDetails(
customer_id="1",
name="John Doe",
email="john.doe@example.com",
orders=[
Order(order_id="12345", status="shipped", items=["蓝色牛仔裤", "T恤"]),
],
)
def get_shipping_info(ctx: RunContext[CustomerDetails]) -> str:
"""获取发货信息"""
return shipping_info_db[ctx.deps.orders[0].order_id]
# 带有结构化输出和依赖的代理
agent5 = Agent(
model=model,
result_type=ResponseModel,
deps_type=CustomerDetails,
retries=3,
system_prompt=(
"你是一个智能客服代理。"
"仔细分析查询,并提供结构化的响应。"
"使用工具查找相关信息。"
"始终礼貌地迎接客户,并提供帮助。"
), # 这些信息在编写代码时是已知的
tools=[Tool(get_shipping_info, takes_ctx=True)], # 通过参数添加工具
)
@agent5.system_prompt
async def add_customer_name(ctx: RunContext[CustomerDetails]) -> str:
return f"客户详情:{to_markdown(ctx.deps)}"
response = agent5.run_sync(
user_prompt="我最近的订单现在是什么状态?", deps=customer
)
response.all_messages()
print(response.data.model_dump_json(indent=2))
print(
"客户信息:\n"
f"姓名:{customer.name}\n"
f"邮箱:{customer.email}\n\n"
"响应详情:\n"
f"{response.data.response}\n\n"
"状态:\n"
f"是否需要后续跟进:{response.data.follow_up_required}\n"
f"是否需要转接:{response.data.needs_escalation}"
)
- 数据库仿真
- 模拟一个简单的发货信息的数据库系统
2. 数据模型: (同前例):
3. 自定义工具 (这里 — get_shipping_info)
- 创建一个查询物流的工具
- 通过上下文参数来获取客户详情
- 返回物流状态
4. 优化的代理设置
- 通过
tools
参数来添加工具 - 指定该工具需要用到上下文(即
takes_ctx=True
)
5. 动态系统提示语:
这个 add_customer_name 方法在处理动态系统信息。
6. 结果:
示例 6 # --------------------------------------------------------------
# 6. 带有反射和自我修正的代理
# --------------------------------------------------------------
"""
本示例展示了具有自我修正功能的高级代理能力。
关键概念:
- 实现自我反思
- 优雅地处理错误并重试
- 使用ModelRetry进行自动重试
- 通过装饰器注册工具
"""
# 模拟的货运信息数据库
shipping_info_db: Dict[str, str] = {
"#12345": "2024年12月1日已发货",
"#67890": "正在派送",
}
# 定义订单结构
class Order(BaseModel):
"""订单结构。"""
order_id: str
status: str
items: List[str]
class ResponseModel(BaseModel):
"""带有元数据的结构化响应。"""
response: str
needs_escalation: bool
follow_up_required: bool
sentiment: str = Field(description="客户情感分析")
# 定义客户信息结构
class CustomerDetails(BaseModel):
"""客户信息结构。"""
customer_id: str
name: str
email: str
orders: Optional[List[Order]] = None
customer = CustomerDetails(
customer_id="1",
name="John Doe",
email="john.doe@example.com",
orders=[
Order(order_id="12345", status="已发货", items=["蓝色牛仔裤", "T恤"]),
],
)
# 带有反射和自我修正的代理
agent5 = Agent(
model=model,
result_type=ResponseModel,
deps_type=CustomerDetails,
retries=3,
system_prompt=(
"你是一位智能客服。"
"请仔细分析查询并提供结构化的响应。"
"使用工具查找相关信息。"
"始终向客户问候并提供帮助。"
),
)
@agent5.tool_plain() # 通过装饰器添加普通工具
def get_shipping_status(order_id: str) -> str:
"""根据给定的订单ID获取货运状态。"""
shipping_status = shipping_info_db.get(order_id)
if shipping_status is None:
raise ModelRetry(
f"找不到订单ID {order_id} 的货运信息。"
"请确保订单ID以#开头,例如#624743"
"如有需要,请自我修正后重试。"
)
return shipping_info_db[order_id]
# 示例用法
response = agent5.run_sync(
user_prompt="我的订单12345的状态如何?", deps=customer
)
response.all_messages()
print(response.data.model_dump_json(indent=2))
主要特点:
- 自我修正机制:
- 使用
ModelRetry
实现自动重试功能 - 提供帮助用户自我修正的错误消息
- 验证订单号格式
2. 使用装饰器的工具
- 使用
@agent5.tool_plain()
装饰器 - 让工具注册变得更简单
- 提供简洁明了的工具定义语法
3. 错误处理:
- 优雅地处理缺失数据
- 自动重试功能
- 详细的错误信息
4. 输入校验:
- 检查订单ID格式是否正确
- 提供格式修正的建议
- 确保数据的完整性
5. 输出 :
在这里,我们尝试了用PydanticAI框架的不同方式来使用代理。特别感谢(daveebbelaar)。无论如何,它确实有很大的潜力,作为一款新框架,你可以用非常简单的抽象来选择不同的大型语言模型,并轻松设置和随时调整系统提示。还能轻松地引入不同内容,并设置历史记录,让系统具有记忆功能。这完全符合Python的风格。很多方面比像Langchain、LangGraph、LlamaIndex等框架更容易上手。我们可以尝试看它与检索增强生成(RAG)系统的配合效果。我可能会在未来进一步研究这个方向,同时我也想比较不同框架,看看它们之间的区别。敬请关注!
请帮忙鼓掌一下👏觉得有用就留言 ❤️🙏
参考内容:- https://ai.pydantic.dev/ (人工智能Pydantic开发页面)
- https://github.com/daveebbelaar/pydantic-ai-tutorial/blob/main/src/introduction.py (Pydantic-人工智能教程的introduction.py文件)