PydanticAI:构建生产级 AI 应用程序的综合指南
PydanticAI 是一个**强大的 Python 框架**,旨在简化使用生成式 AI 开发生产级应用程序的过程。它由广泛使用的数据验证库 Pydantic 背后的同一团队构建,旨在将 FastAPI 的创新和符合人体工程学的设计引入 AI 应用程序开发领域。PydanticAI 专注于**类型安全、模块化以及与其他 Python 工具的无缝集成**。
核心概念
PydanticAI 围绕几个关键概念:
代理
代理是与大型语言模型 (LLM) 交互的**主要接口**。代理充当各种组件的容器,包括:
代理专为可重用性而设计,通常实例化一次并在整个应用程序中重复使用。
系统提示
系统提示是开发人员向 LLM 提供的指令。它们可以是:
单个代理可以同时使用静态和动态系统提示,这些提示按照运行时定义的顺序附加。
from pydantic_ai import Agent, RunContext from datetime import date agent = Agent( 'openai:gpt-4o', deps_type=str, system_prompt="Use the customer's name while replying to them.", ) @agent.system_prompt def add_the_users_name(ctx: RunContext[str]) -> str: return f"The user's name is {ctx.deps}." @agent.system_prompt def add_the_date() -> str: return f'The date is {date.today()}.' result = agent.run_sync('What is the date?', deps='Frank') print(result.data) #> Hello Frank, the date today is 2032-01-02.
功能工具
函数工具使 LLM 能够访问外部信息或执行系统提示本身无法执行的操作。工具可以通过多种方式注册:
import random from pydantic_ai import Agent, RunContext agent = Agent( 'gemini-1.5-flash', deps_type=str, system_prompt=( "You're a dice game, you should roll the die and see if the number " "you get back matches the user's guess. If so, tell them they're a winner. " "Use the player's name in the response." ), ) @agent.tool_plain def roll_die() -> str: """Roll a six-sided die and return the result.""" return str(random.randint(1, 6)) @agent.tool def get_player_name(ctx: RunContext[str]) -> str: """Get the player's name.""" return ctx.deps dice_result = agent.run_sync('My guess is 4', deps='Anne') print(dice_result.data) #> Congratulations Anne, you guessed correctly! You're a winner!
工具参数从函数签名中提取,用于构建工具的 JSON 模式。函数的文档字符串用于生成工具的描述和模式中的参数描述。
依赖项
依赖项通过依赖项注入系统向代理的系统提示、工具和结果验证器提供数据和服务。依赖项可通过 `RunContext` 对象访问。它们可以是任何 Python 类型,但 `dataclasses` 是管理多个依赖项的便捷方式。
from dataclasses import dataclass import httpx from pydantic_ai import Agent, RunContext @dataclass class MyDeps: api_key: str http_client: httpx.AsyncClient agent = Agent( 'openai:gpt-4o', deps_type=MyDeps, ) @agent.system_prompt async def get_system_prompt(ctx: RunContext[MyDeps]) -> str: response = await ctx.deps.http_client.get( 'https://example.com', headers={'Authorization': f'Bearer {ctx.deps.api_key}'}, ) response.raise_for_status() return f'Prompt: {response.text}' async def main(): async with httpx.AsyncClient() as client: deps = MyDeps('foobar', client) result = await agent.run('Tell me a joke.', deps=deps) print(result.data) #> Did you hear about the toothpaste scandal? They called it Colgate.
结果
结果是代理运行返回的最终值。它们被包装在 `RunResult`(用于同步和异步运行)或 `StreamedRunResult`(用于流式运行)中,提供对使用数据和消息历史记录的访问。结果可以是纯文本或结构化数据,并使用 Pydantic 进行验证。
from pydantic import BaseModel from pydantic_ai import Agent class CityLocation(BaseModel): city: str country: str agent = Agent('gemini-1.5-flash', result_type=CityLocation) result = agent.run_sync('Where were the olympics held in 2012?') print(result.data) #> city='London' country='United Kingdom'
通过 `@agent.result_validator` 装饰器添加的结果验证器提供了一种添加进一步验证逻辑的方法,特别是当验证需要 IO 并且是异步的时候。
主要特点
PydanticAI 拥有几个关键功能,使其成为 AI 应用程序开发的绝佳选择:
与代理商合作
运行代理
代理可以通过多种方式运行:
from pydantic_ai import Agent agent = Agent('openai:gpt-4o') # Synchronous run result_sync = agent.run_sync('What is the capital of Italy?') print(result_sync.data) #> Rome # Asynchronous run async def main(): result = await agent.run('What is the capital of France?') print(result.data) #> Paris async with agent.run_stream('What is the capital of the UK?') as response: print(await response.get_data()) #> London
对话
代理运行可能代表整个对话,但对话也可以由多个运行组成,尤其是在保持交互之间的状态时。您可以使用“message_history”参数传递先前运行的消息以继续对话。
from pydantic_ai import Agent agent = Agent('openai:gpt-4o', system_prompt='Be a helpful assistant.') result1 = agent.run_sync('Tell me a joke.') print(result1.data) #> Did you hear about the toothpaste scandal? They called it Colgate. result2 = agent.run_sync('Explain?', message_history=result1.new_messages()) print(result2.data) #> This is an excellent joke invent by Samuel Colvin, it needs no explanation.
使用限制
PydanticAI 提供了一个 `settings.UsageLimits` 结构来限制令牌和请求的数量。您可以通过 `usage_limits` 参数将这些设置应用于 `run` 函数。
from pydantic_ai import Agent from pydantic_ai.settings import UsageLimits from pydantic_ai.exceptions import UsageLimitExceeded agent = Agent('claude-3-5-sonnet-latest') try: result_sync = agent.run_sync( 'What is the capital of Italy? Answer with a paragraph.', usage_limits=UsageLimits(response_tokens_limit=10), ) except UsageLimitExceeded as e: print(e) #> Exceeded the response_tokens_limit of 10 (response_tokens=32)
模型设置
`settings.ModelSettings` 结构允许您通过 `temperature`、`max_tokens` 和 `timeout` 等参数微调模型行为。您可以通过 `run` 函数中的 `model_settings` 参数应用这些参数。
from pydantic_ai import Agent agent = Agent('openai:gpt-4o') result_sync = agent.run_sync( 'What is the capital of Italy?', model_settings={'temperature': 0.0}, ) print(result_sync.data) #> Rome
功能工具详细信息
工具注册
可以使用 `@agent.tool` 装饰器(用于需要上下文的工具)、`@agent.tool_plain` 装饰器(用于没有上下文的工具)或通过 `Agent` 构造函数中的 `tools` 参数来注册工具。
from pydantic_ai import Agent, RunContext agent_a = Agent( 'gemini-1.5-flash', deps_type=str, tools=[ lambda: str(random.randint(1, 6)), lambda ctx: ctx.deps ], )
工具架构
参数描述从文档字符串中提取并添加到工具的 JSON 架构中。如果工具有一个参数可以在 JSON 架构中表示为对象,则架构将简化为该对象。
from pydantic_ai import Agent from pydantic_ai.messages import ModelMessage, ModelResponse from pydantic_ai.models.function import AgentInfo, FunctionModel agent = Agent() @agent.tool_plain def foobar(a: int, b: str, c: dict[str, list[float]]) -> str: """Get me foobar. Args: a: apple pie b: banana cake c: carrot smoothie """ return f'{a} {b} {c}'
动态工具
可以使用“prepare”函数定制工具,该函数在每个步骤中被调用来修改工具定义或从该步骤中省略该工具。
from typing import Union from pydantic_ai import Agent, RunContext from pydantic_ai.tools import ToolDefinition agent = Agent('test') async def only_if_42( ctx: RunContext[int], tool_def: ToolDefinition ) -> Union[ToolDefinition, None]: if ctx.deps == 42: return tool_def @agent.tool(prepare=only_if_42) def hitchhiker(ctx: RunContext[int], answer: str) -> str: return f'{ctx.deps} {answer}' result = agent.run_sync('testing...', deps=41) print(result.data) #> success (no tool calls) result = agent.run_sync('testing...', deps=42) print(result.data) #> {"hitchhiker":"42 a"}
信息和聊天记录
访问消息
可以通过 `RunResult` 和 `StreamedRunResult` 对象上的 `all_messages()` 和 `new_messages()` 方法访问代理运行期间交换的消息。
from pydantic_ai import Agent agent = Agent('openai:gpt-4o', system_prompt='Be a helpful assistant.') result = agent.run_sync('Tell me a joke.') print(result.data) #> Did you hear about the toothpaste scandal? They called it Colgate. print(result.all_messages())
消息重用
可以将消息传递给 `message_history` 参数,以继续跨多个代理运行的对话。当 `message_history` 已设置且不为空时,不会生成新的系统提示。
消息格式
消息格式与模型无关,允许在不同的代理或使用不同模型的同一代理中使用消息。
调试和监控
Pydantic Logfire
PydanticAI 与 **Pydantic Logfire** 集成,后者是一个可观察性平台,可让您监控和调试整个应用程序。Logfire 可用于:
要将 PydanticAI 与 Logfire 一起使用,请使用 `logfire` 可选组进行安装:`pip install 'pydantic-ai[logfire]'`。然后,您需要配置一个 Logfire 项目并验证您的环境。
安装和设置
安装
可以使用 pip 安装 PydanticAI:
pip install pydantic-ai
还可以使用精简安装来使用特定型号,例如:
pip install 'pydantic-ai-slim[openai]'
Logfire 集成
要将 PydanticAI 与 Logfire 一起使用,请使用 `logfire` 可选组进行安装:
pip install 'pydantic-ai[logfire]'
示例
示例可作为单独的包使用:
pip install 'pydantic-ai[examples]'
测试与评估
单元测试
单元测试验证您的应用程序代码是否按预期运行。对于 PydanticAI,请遵循以下策略:
import pytest import anyio from pydantic_ai import Agent, RunContext from pydantic_ai.models.test import TestModel from pydantic_ai.messages import ModelRequest, UserPromptPart from pydantic_ai.tools import ToolDefinition from datetime import datetime @pytest.mark.anyio async def test_weather(): model = TestModel() class WeatherResult(dict): temperature: int location: str time: datetime weather_agent = Agent( model=model, result_type=WeatherResult, system_prompt='Return a valid WeatherResult object.', ) @weather_agent.tool def get_current_time(ctx: RunContext) -> datetime: return datetime.now() @weather_agent.tool def get_location(ctx: RunContext) -> str: return "london" with weather_agent.override(model=model): result = await weather_agent.run('What is the weather?') assert result.data["temperature"] == 0 assert result.data["location"] == 'london' assert isinstance(result.data["time"], datetime) messages = result.all_messages() assert len(messages) == 3 assert messages.kind == "request" assert messages.kind == "response" assert messages.kind == "request" assert isinstance(messages.parts, UserPromptPart) assert messages.parts.tool_name == "get_location" assert isinstance(messages.parts.tool_name , str) assert messages.parts.tool_name == 'get_current_time'
评估
评估用于衡量 LLM 的性能,它更像是基准测试而非单元测试。评估侧重于衡量 LLM 在特定应用中的表现。这可以通过端到端测试、综合自包含测试、使用 LLM 评估 LLM 或通过衡量生产中的代理性能来实现。
示例用例
PydanticAI 可用于多种用例:
结论
PydanticAI 提供了一个**强大而灵活的框架**,用于开发 AI 应用程序,重点强调类型安全性和模块化。使用 Pydantic 进行数据验证和结构化,再加上其依赖项注入系统,使其成为构建**可靠且可维护的 AI 应用程序**的理想工具。凭借其广泛的 LLM 支持以及与 Pydantic Logfire 等工具的无缝集成,PydanticAI 使开发人员能够高效地构建功能强大、可用于生产的 AI 驱动项目。