当前位置: 首页 > article >正文

Pydantic AI:用类型安全与依赖注入构建生产级AI Agent

1. 项目概述当Pydantic遇见AI Agent如果你和我一样在过去一两年里折腾过各种AI Agent框架从LangChain到LlamaIndex再到CrewAI那你大概率经历过这样的场景为了接入一个模型你得写一堆胶水代码想给Agent加个工具得研究半天复杂的装饰器最头疼的是代码跑起来看着没问题但一上线就各种类型错误、运行时异常调试起来像在迷宫里找出口。我们总在期待一个框架能像FastAPI定义Web服务那样用清晰、直观、符合直觉的方式来定义AI Agent。现在这个期待可能被填上了——Pydantic AI来了。简单说Pydantic AI是一个用Python构建生产级GenAI应用和智能体工作流的框架。它的核心口号是“The Pydantic way”这可不是随便说说的。Pydantic团队在Python生态里是什么地位数据验证的绝对标杆。OpenAI SDK、Google AI SDK、Anthropic SDK、LangChain……这些你耳熟能详的库底层的数据验证层都是Pydantic。所以当这个团队决定亲自下场做AI Agent框架时他们带来的不是又一个“跟风者”而是一个从基因里就带着类型安全、开发者体验至上、生产就绪理念的解决方案。我花了一周时间深度试用了Pydantic AI从最简单的“Hello World”到构建一个具备工具调用、依赖注入、结构化输出的复杂客服Agent。我的整体感受是它确实把那种“FastAPI式”的愉悦感带到了AI开发中。你不用再和复杂的抽象层搏斗而是可以专注于定义“你的Agent是什么”、“它需要什么”、“它应该输出什么”。接下来我就结合自己的实操带你拆解这个框架的核心设计、上手步骤以及那些官方文档里不会明说但实际开发中能让你少踩80%坑的细节。2. 核心设计哲学为什么是“Pydantic Way”在深入代码之前我们必须先理解Pydantic AI的设计哲学。这决定了你用它时的思维模式也解释了它为什么在很多地方显得“不一样”。2.1 类型安全不是可选项是基础设施大多数AI框架把类型提示Type Hints当作“锦上添花”的文档。但在Pydantic AI里类型是框架运转的基石。你的Agent、它的依赖Dependencies、工具Tools的参数和返回值、以及最终的输出Output全部通过Pydantic模型和Python类型注解来定义。这意味着什么首先错误从运行时提前到了编写时。如果你的工具函数期望一个int类型的customer_id但你传了个字符串你的IDE比如VSCode或PyCharm会在你写代码的时候就用红色波浪线提醒你而不是等到程序运行到一半才抛出一个晦涩的ValidationError。这种体验有点像写Rust代码时的“如果编译通过基本就能运行”。其次它带来了无与伦比的开发体验和可维护性。当你定义一个返回SupportOutput模型的Agent时在整个代码链路中result.output的属性都是可被IDE自动补全和类型检查的。这对于构建复杂、多人协作的AI应用至关重要大大降低了心智负担。2.2 依赖注入让Agent变得可测试、可组合这是Pydantic AI让我拍案叫绝的设计。传统的Agent框架里工具函数经常需要访问数据库连接、用户会话、配置信息等“上下文”。常见的做法是使用全局变量、或者通过复杂闭包来传递导致代码耦合度高难以单独测试。Pydantic AI引入了明确的依赖注入Dependency Injection系统。你定义一个DepsType比如一个dataclass或Pydantic模型里面包含Agent运行所需的所有外部资源。然后在工具函数或动态指令中通过RunContext[DepsType]参数来安全地访问这些依赖。这样做有几个巨大优势关注点分离Agent的逻辑LLM交互、工具调用和外部资源管理数据库、API客户端被清晰地分开。易于测试你可以轻松地为测试创建一个DepsType的模拟Mock实例注入假数据或模拟服务从而对Agent的逻辑进行单元测试而不需要启动整个数据库或调用真实的外部API。可配置性根据运行环境开发、测试、生产你可以注入不同的依赖实例比如使用内存数据库还是云数据库。2.3 一切皆可组合Capability模式很多框架提供了丰富的功能但它们是“硬编码”进去的。Pydantic AI提出了“Capability”能力的概念。一个Capability是一个可复用的单元它打包了一组相关的工具Tools、钩子Hooks、指令Instructions和模型设置。例如框架内置了WebSearch和Thinking这两个Capability。你只需要在创建Agent时将capabilities[Thinking(), WebSearch()]作为参数传入你的Agent就立刻拥有了联网搜索和“链式思考”CoT的能力。这比手动去配置搜索API的密钥、设计提示词要优雅和高效得多。更重要的是这种设计是面向生态的。你可以构建自己的Capability比如一个专门与内部CRM系统交互的能力包或者安装社区发布的第三方Capability。这意味着功能的复用和共享变得极其简单避免了重复造轮子。3. 从零到一构建你的第一个生产级Agent理论说再多不如动手写一行代码。我们用一个贴近实际的场景来演示构建一个“智能天气旅行顾问”Agent。这个Agent能根据用户提供的城市和日期查询天气并结合一些简单的规则比如下雨天建议带伞高温天建议去室内场所给出旅行建议。我们会逐步加入工具、依赖注入和结构化输出。3.1 环境准备与安装首先确保你的Python版本在3.10以上。然后安装pydantic-ai。我强烈建议使用虚拟环境。# 创建并激活虚拟环境以venv为例 python -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows # 安装pydantic-ai pip install pydantic-ai注意安装过程可能会同时安装pydantic和httpx等依赖。由于Pydantic AI深度集成Pydantic请确保你安装的Pydantic版本是兼容的通常最新版即可。如果你项目中已有Pydantic注意版本冲突。接下来你需要一个LLM的API密钥。Pydantic AI是模型无关的这里我们以OpenAI为例。去OpenAI平台创建一个API Key。# 将你的API Key设置为环境变量更安全的方式 export OPENAI_API_KEYsk-... # Linux/macOS # set OPENAI_API_KEYsk-... # Windows CMD # $env:OPENAI_API_KEYsk-... # Windows PowerShell3.2 定义核心数据模型Pydantic的用武之地在Pydantic AI里先定义模型再写逻辑是一个好习惯。这能帮你理清思路。from pydantic import BaseModel, Field from datetime import date from enum import Enum # 定义一个枚举表示天气状况 class WeatherCondition(str, Enum): SUNNY sunny CLOUDY cloudy RAINY rainy SNOWY snowy STORMY stormy # 定义工具函数的返回模型天气查询结果 class WeatherData(BaseModel): city: str date: date condition: WeatherCondition temperature_high: float Field(description最高温度摄氏度) temperature_low: float Field(description最低温度摄氏度) humidity: int Field(description湿度百分比, ge0, le100) precipitation_prob: int Field(description降水概率百分比, ge0, le100) # 定义Agent的最终输出模型旅行建议 class TravelAdvice(BaseModel): summary: str Field(description对天气的简要总结和总体建议) clothing: str Field(description着装建议) activity_suggestion: str Field(description活动建议) risk_level: int Field(description出行风险等级1-10, ge1, le10) need_umbrella: bool Field(description是否需要带伞) need_sunscreen: bool Field(description是否需要涂防晒霜)为什么要把WeatherCondition定义成Enum因为枚举类型能为LLM提供清晰、有限的选项减少它“胡编乱造”的可能性。Field描述符不仅用于文档在有些模型如OpenAI的JSON模式下这些描述会传递给LLM帮助它更好地理解字段含义。ge和le是Pydantic的验证器确保数据在合理范围内。3.3 创建Agent并添加工具现在创建Agent并为其添加一个“查询天气”的工具。这里我们先模拟一个工具函数实际应用中你会在这里调用真实的天气API如OpenWeatherMap。from pydantic_ai import Agent, RunContext from typing import Any # 首先定义Agent的依赖类型。这里我们先留空用一个简单的字典后续再扩展。 from typing import Dict DepsType Dict[str, Any] # 临时使用后续会替换为更具体的类型 # 创建Agent实例 weather_agent Agent( modelopenai:gpt-4o, # 使用OpenAI的gpt-4o模型 deps_typeDepsType, output_typeTravelAdvice, # 指定Agent输出必须符合TravelAdvice模型 instructions( 你是一个专业的旅行天气顾问。根据用户提供的城市和日期查询天气信息并给出详细、贴心的旅行建议。 建议需考虑温度、湿度、降水概率和天气状况。请确保建议具体、实用。 风险等级根据极端天气暴雨、暴雪、高温等的可能性来评估。 ), ) # 注册一个工具模拟查询天气 weather_agent.tool async def get_weather(ctx: RunContext[DepsType], city: str, target_date: date) - WeatherData: 根据城市和日期查询天气信息。 Args: city: 要查询的城市名称例如“北京”、“New York”。 target_date: 要查询的日期。 Returns: 包含详细天气数据的WeatherData对象。 # 模拟数据 - 实际项目中这里应调用天气API # 注意为了演示我们根据城市名简单生成一些“假数据” print(f[工具调用] 模拟查询 {city} 在 {target_date} 的天气) # 一个简单的模拟逻辑 import random condition random.choice(list(WeatherCondition)) temp_high round(random.uniform(15, 35), 1) temp_low round(temp_high - random.uniform(5, 15), 1) humidity random.randint(30, 90) precip_prob 80 if condition in [WeatherCondition.RAINY, WeatherCondition.SNOWY, WeatherCondition.STORMY] else random.randint(0, 30) return WeatherData( citycity, datetarget_date, conditioncondition, temperature_hightemp_high, temperature_lowtemp_low, humidityhumidity, precipitation_probprecip_prob )几点关键解释agent.tool装饰器这是注册工具的标准方式。被装饰的异步函数会自动暴露给LLM。函数文档字符串Docstring极其重要LLM依靠函数的文档字符串来理解这个工具是做什么的、参数是什么意思。务必清晰、准确地描述。Pydantic AI会自动解析docstring将其作为工具描述和参数描述发送给LLM。参数类型city: str和target_date: date。Pydantic AI会利用这些类型信息为LLM生成一个JSON Schema指导LLM如何调用这个工具。date类型会被正确地处理。返回值类型- WeatherData。这确保了工具返回的数据结构是明确的也方便框架进行后续处理。3.4 运行Agent并查看结果现在让我们运行这个初步的Agent。import asyncio from datetime import date, timedelta async def main(): # 准备依赖目前是空字典 deps {} # 运行Agent tomorrow date.today() timedelta(days1) result await weather_agent.run( f我明天想去上海天气怎么样有什么建议吗今天是{tomorrow}。, depsdeps ) print( Agent运行结果 ) print(f最终输出: {result.output}) print(f使用的消息数: {len(result.all_messages())}) print(f工具调用历史:) for msg in result.all_messages(): if msg.kind tool-call or msg.kind tool-result: print(f - {msg.kind}: {msg.content}) # 运行异步主函数 if __name__ __main__: asyncio.run(main())运行这段代码你会看到类似以下的输出由于天气数据是随机的每次运行结果会不同[工具调用] 模拟查询 上海 在 2024-05-27 的天气 Agent运行结果 最终输出: summary上海明天天气晴朗最高气温28.5°C最低气温18.3°C湿度65%降水概率10%。 clothing建议穿着轻薄透气的衣物如短袖T恤、衬衫搭配薄外套或长裤早晚温差较大注意增减衣物。 activity_suggestion非常适合户外活动如城市观光、公园散步或滨江骑行。 risk_level2 need_umbrellaFalse need_sunscreenTrue 使用的消息数: 5 工具调用历史: - tool-call: {name: get_weather, arguments: {city: 上海, target_date: 2024-05-27}} - tool-result: {city: 上海, date: 2024-05-27, condition: sunny, temperature_high: 28.5, temperature_low: 18.3, humidity: 65, precipitation_prob: 10}发生了什么Agent收到了用户关于上海明天天气的询问。LLM识别出需要调用get_weather工具来获取信息。框架执行了工具函数获得了结构化的WeatherData。LLM根据工具返回的天气数据结合你的指令“给出详细、贴心的旅行建议”生成了最终的回复。最关键的一步框架将LLM的回复按照TravelAdvice模型的格式进行验证和解析。如果LLM返回的JSON不符合TravelAdvice的格式比如缺少字段、类型不对框架会自动要求LLM重试直到得到一个有效的输出。这就是结构化输出的威力。3.5 引入依赖注入让Agent更“智能”上面的Agent能工作但工具里的模拟数据太假了。让我们引入真实的依赖一个天气API客户端。同时我们可能还想根据用户的历史偏好来微调建议。from dataclasses import dataclass from pydantic_ai import Agent, RunContext import httpx from typing import Optional # 1. 定义更具体的依赖类型 dataclass class TravelDependencies: weather_client: httpx.AsyncClient # 用于调用真实天气API的HTTP客户端 user_preference: Optional[dict] None # 可选的用户偏好例如“讨厌下雨”、“喜欢户外” # 2. 更新Agent使用新的依赖类型 weather_agent_v2 Agent( modelopenai:gpt-4o, deps_typeTravelDependencies, # 关键变更指定依赖类型 output_typeTravelAdvice, instructions( 你是一个专业的旅行天气顾问。根据用户提供的城市和日期查询天气信息并给出详细、贴心的旅行建议。 建议需考虑温度、湿度、降水概率和天气状况。请确保建议具体、实用。 如果用户有已知偏好如讨厌下雨请在建议中予以考虑。 风险等级根据极端天气暴雨、暴雪、高温等的可能性来评估。 ), ) # 3. 更新工具函数使用注入的依赖 weather_agent_v2.tool async def get_weather_real(ctx: RunContext[TravelDependencies], city: str, target_date: date) - WeatherData: 根据城市和日期调用真实天气API查询天气信息。 Args: city: 要查询的城市名称。 target_date: 要查询的日期。 Returns: 包含详细天气数据的WeatherData对象。 # 注意这里使用了 ctx.deps.weather_client # 实际API调用代码这里以OpenWeatherMap为例需要注册获取API Key api_key YOUR_OPENWEATHER_API_KEY # 应从环境变量或配置中读取 # 构建请求URL (示例请参考OpenWeatherMap API文档) # url fhttps://api.openweathermap.org/data/2.5/forecast?q{city}appid{api_key}unitsmetric # 为了演示我们仍然模拟但展示了如何使用依赖 print(f[工具调用] 使用注入的client查询 {city} 的天气。用户偏好: {ctx.deps.user_preference}) # 模拟API调用延迟 import asyncio await asyncio.sleep(0.5) # 更“真实”的模拟可以考虑用户偏好来调整模拟结果仅演示逻辑 condition WeatherCondition.SUNNY if ctx.deps.user_preference and ctx.deps.user_preference.get(hates_rain): # 如果用户讨厌下雨我们“模拟”一个晴天结果实际API不会这样 print( - 检测到用户讨厌下雨模拟返回晴天数据。) import random return WeatherData( citycity, datetarget_date, conditioncondition, temperature_highround(random.uniform(20, 30), 1), temperature_lowround(random.uniform(10, 20), 1), humidityrandom.randint(40, 70), precipitation_prob10 if condition WeatherCondition.SUNNY else 60 ) # 4. 还可以添加动态指令根据依赖生成不同的系统提示 weather_agent_v2.instructions async def add_user_preference_context(ctx: RunContext[TravelDependencies]) - str: 根据用户偏好动态添加指令。 if not ctx.deps.user_preference: return prefs [] if ctx.deps.user_preference.get(hates_rain): prefs.append(该用户非常讨厌下雨天请在建议中强烈避免推荐雨天户外活动并强调防雨措施。) if ctx.deps.user_preference.get(likes_outdoor): prefs.append(该用户喜爱户外活动在天气允许的情况下优先推荐户外项目。) if prefs: return 用户已知偏好\n \n.join(prefs) return 现在运行这个升级版的Agentasync def main_v2(): # 创建真实的HTTP客户端这里仍用于模拟 async with httpx.AsyncClient() as client: # 构造依赖注入真实客户端和用户偏好 deps TravelDependencies( weather_clientclient, user_preference{hates_rain: True, likes_outdoor: True} ) result await weather_agent_v2.run( 我下周去杭州玩天气如何给点建议。, depsdeps ) print( 升级版Agent运行结果 ) print(result.output.json(indent2)) # 以格式化的JSON输出 asyncio.run(main_v2())依赖注入带来的好处可测试性在单元测试中你可以创建一个TravelDependencies的模拟对象其中weather_client是一个Mock对象返回预设的天气数据从而在不调用真实API的情况下测试Agent的逻辑。灵活性在生产环境和开发环境你可以注入不同的httpx.AsyncClient实例比如配置不同的超时、重试策略。上下文感知Agent现在能根据user_preference动态调整其行为这是通过agent.instructions装饰器实现的动态指令。这使得Agent的提示词不再是静态的而是可以根据运行时上下文进行定制。4. 高级特性与生产实践基础功能跑通后我们来看看Pydantic AI那些能让你的应用真正达到“生产级”的特性。4.1 可观测性Observability与Logfire集成AI应用的黑盒特性是生产部署的主要挑战之一。你不知道Agent内部做了什么决策、调用了哪些工具、花了多少钱、哪里出了错。Pydantic AI原生集成了Pydantic Logfire这是一个基于OpenTelemetry的可观测性平台。# 首先安装logfire # pip install logfire import logfire from pydantic_ai import Agent # 1. 配置Logfire需要从Logfire网站获取token logfire.configure(tokenyour-logfire-token) # 通常从环境变量读取 logfire.instrument_pydantic_ai() # 关键的一行自动注入遥测 # 2. 像往常一样创建和使用Agent agent Agent(openai:gpt-4o, instructions...) # ... 添加工具等 # 3. 运行Agent。所有交互LLM调用、工具调用、耗时、token消耗都会被自动记录。 result await agent.run(...)完成这些后打开Logfire控制台你会看到一个清晰的追踪Trace视图。它展示了整个Agent运行的流水线接收用户消息、LLM思考、工具调用包括输入参数和返回值、LLM再次思考、生成最终输出。每个步骤的耗时、Token使用量、成本如果配置了都一目了然。这对于调试复杂的工作流、监控性能、进行成本分析以及评估Evals至关重要。如果某个工具调用频繁失败或者某个提示词导致LLM陷入了长循环你都能快速定位。4.2 流式输出Streaming与实时体验对于需要长时间运行或希望提供实时反馈的Agent流式输出是必备功能。Pydantic AI的流式输出不仅支持文本流还支持结构化数据的流式验证。import asyncio from pydantic_ai import Agent from pydantic import BaseModel, Field class StreamedOutput(BaseModel): items: list[str] Field(description生成的条目列表) summary: str Field(description最终总结) agent Agent(openai:gpt-4o, output_typeStreamedOutput) async def main_stream(): prompt 列举5种适合在办公室养的盆栽植物并简要总结它们的共同优点。 # 使用 run_stream 而不是 run async with agent.run_stream(prompt) as result_stream: async for chunk in result_stream: # chunk 可以是多种类型 if chunk.kind output: # 结构化输出流output模型的部分字段可能已经生成并验证 print(f[结构化输出更新] {chunk.data}) elif chunk.kind content: # 原始文本内容流如果模型支持 print(f[文本流] {chunk.text}, end, flushTrue) elif chunk.kind tool-call: print(f[工具调用] {chunk.name}) elif chunk.kind tool-result: print(f[工具结果] {chunk.result}) # 流结束后可以获取完整的结果对象 final_result result_stream.result() print(f\n最终完整输出: {final_result.output}) asyncio.run(main_stream())run_stream返回一个异步上下文管理器它产生一个事件流。你可以在LLM生成内容的同时就收到部分输出content更重要的是一旦LLM开始生成结构化的JSON并满足StreamedOutput模型的部分验证output事件就会触发。这意味着你可以在最终结果完全生成之前就开始处理已验证的部分数据极大地提升了响应速度和应用体验。4.3 持久化执行Durable Execution与可靠性对于长时间运行、涉及多步工具调用或需要人工审批Human-in-the-loop的Agent进程崩溃或网络抖动会导致整个工作流失败需要重头再来。Pydantic AI的持久化执行功能就是为了解决这个问题。其核心思想是将Agent的运行状态对话历史、工具调用上下文、中间结果自动保存到外部存储如数据库、Redis。当执行中断后可以从断点恢复而不是重新开始。from pydantic_ai import Agent from pydantic_ai.durable_execution import DurableExecution, InMemoryDurableExecutionBackend # 1. 选择一个后端存储这里用内存后端演示生产环境需用数据库后端 backend InMemoryDurableExecutionBackend() durable_exec DurableExecution(backendbackend) # 2. 在创建Agent时启用持久化执行 agent Agent( openai:gpt-4o, instructions..., durable_executiondurable_exec, # 关键参数 ) # 3. 运行Agent时提供一个唯一的run_id run_id my_unique_travel_plan_123 try: result await agent.run(为我规划一个为期一周的日本关西旅行详细到每天。, run_idrun_id) except SomeTransientError: # 模拟一个临时错误如网络超时 print(执行中断...) # 一段时间后可以从同一个run_id恢复 recovered_result await agent.run(继续之前的规划。, run_idrun_id) # recovered_result 会从上次中断的地方继续对话历史都在。生产环境中你会使用PostgresDurableExecutionBackend或RedisDurableExecutionBackend。这确保了即使你的应用服务器重启那些运行到一半的、等待用户审批的Agent任务也不会丢失。4.4 评估Evals与性能监控如何知道你的Agent表现得好不好光靠人工测试不行。Pydantic AI内置了评估Evals框架允许你系统化地定义测试用例和评估标准。from pydantic_ai import Agent from pydantic_ai.evals import Eval, EvalResult, run_evals from pydantic import BaseModel class QAPair(BaseModel): question: str expected_keywords: list[str] # 期望回答中包含的关键词 # 定义评估集 eval_dataset [ QAPair(question北京明天天气如何, expected_keywords[北京, 天气, 温度]), QAPair(question下雨天去上海要带什么, expected_keywords[伞, 雨具, 防水]), # ... 更多测试用例 ] # 定义一个评估函数 def contains_keywords_eval(result, qa_pair: QAPair) - EvalResult: 评估Agent的回答是否包含预期关键词。 answer result.output if hasattr(result, output) else result.data score 0 found_keys [] for keyword in qa_pair.expected_keywords: if keyword in answer: score 1 found_keys.append(keyword) return EvalResult( scorescore / len(qa_pair.expected_keywords), # 得分比例 details{found_keywords: found_keys, question: qa_pair.question} ) # 创建要评估的Agent agent_to_eval Agent(openai:gpt-4o, instructions...) # 运行评估 eval_results await run_evals( agentagent_to_eval, dataseteval_dataset, eval_fncontains_keywords_eval, max_concurrency2 # 并发运行评估 ) for res in eval_results: print(f问题: {res.details[question]}) print(f 得分: {res.score:.2%}, 找到的关键词: {res.details[found_keywords]})你可以将评估结果与Logfire集成持续监控Agent在生产环境中的表现。如果某次代码更新导致评估分数下降你能立即收到警报。5. 避坑指南与最佳实践在实际使用Pydantic AI构建了几个项目后我总结了一些关键的经验和容易踩的坑。5.1 工具设计粒度、描述与错误处理1. 工具粒度要适中不要设计一个“巨无霸”工具比如plan_entire_trip(city, dates, budget, interests...)。这会让LLM难以正确使用且工具内部逻辑过于复杂。应该拆分成小工具get_attractions(city),check_weather(city, date),book_hotel(name, dates)。每个工具职责单一。2. 文档字符串是给LLM看的“API文档”务必详细、准确。使用Args:和Returns:部分。LLM对参数描述非常敏感。好的描述能极大提升工具调用的准确率。agent.tool async def search_flights( ctx: RunContext[DepsType], origin: str Field(description出发城市机场代码如PEK), destination: str Field(description到达城市机场代码如SHA), date: date Field(description出发日期格式YYYY-MM-DD), max_price: Optional[float] Field(None, description最高可接受价格人民币) ) - List[FlightInfo]: 根据条件搜索航班信息。 Args: origin: 出发地机场IATA三字码。 destination: 目的地机场IATA三字码。 date: 出发日期。 max_price: 可选价格过滤器。 Returns: 一个航班信息列表按价格从低到高排序。如果没有符合的航班返回空列表。 # ... 实现3. 工具内部必须有坚实的错误处理LLM调用工具时参数可能不合法比如不存在的城市代码。工具函数内部应该进行验证并抛出清晰的异常。Pydantic AI会捕获这些异常将其信息反馈给LLM让LLM有机会调整参数后重试。agent.tool async def get_city_code(ctx: RunContext[DepsType], city_name: str) - str: 根据城市名获取机场IATA代码。 code await ctx.deps.db.get_city_code(city_name) if not code: # 抛出清晰的错误LLM会看到这个信息 raise ValueError(f未找到城市 {city_name} 对应的机场代码。请提供更准确的城市名或检查拼写。) return code5.2 指令Instructions设计静态与动态结合静态指令创建Agent时传入的instructions参数用于定义Agent的固定角色和基础行为准则。动态指令通过agent.instructions装饰器用于注入运行时才能知道的信息比如用户信息、会话上下文、实时数据。这是实现个性化Agent的关键。agent.instructions async def inject_conversation_history(ctx: RunContext[DepsType]) - str: 将会话历史摘要注入指令。 history await ctx.deps.message_store.get_recent_messages(ctx.deps.user_id, limit5) if not history: return summary \n.join([fUser: {m.user} | Assistant: {m.assistant[:50]}... for m in history]) return f最近的对话历史摘要\n{summary}\n请参考以上历史进行回复保持连贯性。避免指令冲突静态指令和动态指令是合并的。确保它们不会互相矛盾。通常静态指令定义“是什么”角色动态指令定义“当前上下文”情境。5.3 模型选择与成本控制Pydantic AI支持众多模型但不同模型在工具调用、JSON模式遵循、成本方面差异巨大。复杂工具调用/结构化输出优先选择对工具调用和JSON模式支持最好的模型如OpenAI的gpt-4o/gpt-4-turbo、Anthropic的claude-3-5-sonnet。虽然贵但成功率高节省调试时间。简单任务/原型验证可以使用更便宜或开源的模型如gemini-flash、claude-haiku或者通过Ollama运行的本地模型如llama3.2。但需要测试其对工具调用的支持度。设置预算和超时在生产中务必在Agent或运行调用时设置max_messages最大交互轮次和timeout防止LLM陷入死循环或产生过高费用。from pydantic_ai.models.openai import OpenAIModel model OpenAIModel( gpt-4o, max_retries2, timeout30.0, ) agent Agent(modelmodel, ...) # 或者在运行时控制 result await agent.run( prompt, depsdeps, max_messages20, # 最多20轮消息交换包括工具调用 )5.4 调试与问题排查当Agent行为不符合预期时按以下步骤排查启用Logfire这是第一选择。查看Trace确认LLM收到了正确的消息、工具调用参数是否正确、工具返回了什么。检查工具描述LLM是否误解了工具功能简化描述确保每个参数的意义明确。简化测试用一个最简单的提示词和单一工具测试排除复杂指令的干扰。查看原始消息result.all_messages()提供了完整的对话历史包括所有LLM的原始请求和响应。这能帮你理解LLM的“思考过程”。结构化输出失败如果LLM始终无法生成符合output_type的JSON尝试在指令中更明确地要求输出格式“你必须返回一个JSON对象包含summary和risk_level字段...”使用更简单的输出模型或者将某些字段设为Optional。考虑使用支持JSON模式JSON Mode的模型并在模型设置中启用它。6. 总结Pydantic AI的定位与未来经过这一番深度探索Pydantic AI给我的感觉非常明确它不是一个试图囊括所有AI应用场景的“万能框架”而是一个为Python开发者打造的、专注于构建可靠、可维护、类型安全的生产级Agent的工具箱。它的优势在于其坚实的工程基础Pydantic、优秀的设计模式依赖注入、Capability、以及对生产环节的深度思考可观测性、持久化执行、评估。它可能不像一些框架那样有海量的预制“链”或“代理”但它提供了更优雅、更可靠的方式来构建属于你自己的、独一无二的智能体。如果你正在用Python构建需要与外部系统交互、有复杂逻辑、并且最终要部署上线的AI应用Pydantic AI值得你投入时间学习。它带来的类型安全和开发体验提升在项目复杂度增长时会变成巨大的生产力优势。从简单的天气顾问到复杂的多智能体协作系统Pydantic AI提供了一套一致且强大的抽象让你能更专注于业务逻辑而不是框架的复杂性。我个人在后续的项目中会继续深入使用它的Graph功能来编排复杂工作流并探索其与MCPModel Context Protocol的集成为Agent连接更丰富的外部工具和数据源。这个框架的生态还在早期但以其背后的团队和设计理念我相信它会成为Python AI工程化领域的一个重要选择。

相关文章:

Pydantic AI:用类型安全与依赖注入构建生产级AI Agent

1. 项目概述:当Pydantic遇见AI Agent如果你和我一样,在过去一两年里折腾过各种AI Agent框架,从LangChain到LlamaIndex,再到CrewAI,那你大概率经历过这样的场景:为了接入一个模型,你得写一堆胶水…...

别再只会用轮询了!STM32CubeMX串口中断接收实战:从HAL_UART_Receive_IT到回调函数详解

STM32CubeMX串口中断实战:从轮询到中断的思维跃迁 当传感器数据以毫秒级频率涌入,或上位机指令需要即时响应时,轮询方式就像用显微镜观察流星雨——既低效又容易丢失关键信息。本文将揭示如何通过STM32CubeMX构建真正的异步通信框架&#xff…...

用Python和PyTorch复现ICRA 2020论文:基于cVAE的机械臂共享控制(附代码)

用Python和PyTorch实现ICRA 2020论文:基于cVAE的机械臂共享控制实战指南 机械臂控制一直是机器人学中的核心挑战,特别是当操作者需要通过低维输入(如游戏手柄)控制高自由度机械臂时。斯坦福大学团队在ICRA 2020提出的基于条件变分…...

3分钟掌握抖音无水印下载:零门槛实现高清视频本地化

3分钟掌握抖音无水印下载:零门槛实现高清视频本地化 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support…...

Navicat重置工具:让数据库管理无限期免费使用的终极指南

Navicat重置工具:让数据库管理无限期免费使用的终极指南 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 作为一名…...

WPS-Zotero插件:3步解决科研写作的文献管理难题,实现跨平台无缝协作

WPS-Zotero插件:3步解决科研写作的文献管理难题,实现跨平台无缝协作 【免费下载链接】WPS-Zotero An add-on for WPS Writer to integrate with Zotero. 项目地址: https://gitcode.com/gh_mirrors/wp/WPS-Zotero 还在为科研写作中的文献引用而烦…...

告别PDF/Word!用这个开源工具把飞书文档变成可编程的Markdown

飞书文档高效转换Markdown的终极方案 每次写完飞书文档后,你是否也经历过这样的痛苦?精心排版的文档导出成PDF后变成无法编辑的"死文件",或是转成Word后格式全乱需要重新调整。作为技术写作者,我们真正需要的是可编程、…...

如何用WechatBot在5分钟内打造你的专属微信智能助手:终极免费指南

如何用WechatBot在5分钟内打造你的专属微信智能助手:终极免费指南 【免费下载链接】WechatBot 项目地址: https://gitcode.com/gh_mirrors/wechatb/WechatBot 还在为重复回复相同的微信消息而烦恼吗?🤔 想不想拥有一个24小时在线、自…...

从DOS到2024:3dMax 30年版本变迁史,聊聊你入坑的那个‘经典’版本

从DOS到2024:3dMax 30年版本变迁与技术演进图谱 当Gary Yost在1988年敲下第一行代码时,他可能不会想到这个代号为THUD的项目会成为三维创作领域的基石。三十余年间,3dMax从DOS时代的简陋模块成长为影视、游戏、建筑可视化领域的标准工具&…...

如何让老旧Mac重获新生:OpenCore Legacy Patcher完全指南

如何让老旧Mac重获新生:OpenCore Legacy Patcher完全指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否有一台被苹果官方抛弃的旧Mac&…...

避坑指南:在Ubuntu 20.04上编译VINS-Fusion时,如何解决Ceres库的C++14编译错误?

深度解析:Ubuntu 20.04下VINS-Fusion与Ceres库的C14兼容性实战 当你在Ubuntu 20.04环境下尝试编译VINS-Fusion这类依赖Ceres Solver的SLAM项目时,是否曾被满屏的integer_sequence等C模板错误搞得焦头烂额?这个看似简单的编译问题背后&#xf…...

避坑指南:MTK平台Widevine L1密钥安装全流程详解(含SP META工具使用与Log分析)

MTK平台Widevine L1密钥部署实战:从密钥切割到TEE烧录的全链路解析 在移动设备数字版权管理(DRM)领域,Widevine L1认证代表着最高级别的安全级别,它要求内容解密必须在硬件级可信执行环境(TEE)中…...

用LC118这颗SOP-8小芯片,搞定你的3V玩具小车电机正反转(附完整电路)

用LC118这颗SOP-8小芯片打造3V玩具小车电机驱动方案 在微型机器人或玩具车设计中,电机驱动电路往往是决定整体性能的关键环节。当项目受限于两节AA电池或单节锂电池供电时,传统驱动方案常面临电压不足、功耗过大或体积超标等问题。LC118这颗SOP-8封装的驱…...

保姆级教程:在QEMU Vexpress-A9上从零搭建Linux 6.0驱动开发环境并验证platform_driver

从零构建QEMU Vexpress-A9上的Linux 6.0驱动开发实战指南 在嵌入式Linux开发领域,理解驱动模型的核心机制是每个工程师的必修课。而platform_driver作为Linux设备驱动框架中的重要组成部分,其设计理念体现了现代内核开发的抽象与分层思想。本文将带您从…...

HSTracker终极指南:macOS炉石传说智能套牌追踪器与数据分析神器

HSTracker终极指南:macOS炉石传说智能套牌追踪器与数据分析神器 【免费下载链接】HSTracker A deck tracker and deck manager for Hearthstone on macOS 项目地址: https://gitcode.com/gh_mirrors/hs/HSTracker 想要在macOS上玩转炉石传说,获得…...

穿越机电调调参实战:从“消磁补偿”到“闭环模式”,BLHeliSuite参数详解与飞行手感优化

BLHeli电调深度调参指南:从基础原理到飞行手感优化 1. 理解电调调参的核心逻辑 每次看到BLHeliSuite里密密麻麻的参数列表,新手飞手往往会感到无从下手。实际上,这些参数背后都对应着电机运行的物理原理和飞行场景的实际需求。调参不是玄学&a…...

PyQt5开发避坑指南:VSCode配置QtDesigner时,90%新手会遇到的路径问题与解决方案

PyQt5开发避坑指南:VSCode配置QtDesigner时90%新手会遇到的路径问题与解决方案 第一次在VSCode里配置PyQt5开发环境时,最让人抓狂的往往不是代码本身,而是那些看似简单却频频报错的路径配置。特别是当你按照教程一步步操作,却在调…...

Spring Boot整合Canal客户端:手把手实现MySQL数据变更实时监听与同步

Spring Boot深度整合Canal:构建高可靠MySQL数据同步方案 在数据驱动的现代应用中,实时捕获数据库变更已成为构建弹性系统的关键能力。想象这样一个场景:当用户在前台提交订单时,风控系统需要立即分析交易风险,推荐引擎…...

C语言新手必看:从电子科大程算I机考真题里,我总结出的5个函数题避坑指南

C语言新手必看:从电子科大程算I机考真题里,我总结出的5个函数题避坑指南 第一次参加电子科大程算I机考的同学,往往会在函数题上栽跟头。作为过来人,我复盘了近年真题,发现80%的失分都集中在几个典型陷阱上。今天不谈标…...

数字孪生AI:如何让历史数据“开口说话”?

数字孪生AI:如何让历史数据“开口说话”? 引言 想象一下,如果能将一座工厂、一条交通干线甚至一个城市的“过去”完整地复现、分析与推演,我们能从中发现多少被忽略的规律,避免多少重复的失误?这正是数字孪…...

ThinkPad P53内存升级避坑指南:从断电到双通道,保姆级教程带你一次搞定

ThinkPad P53内存升级避坑指南:从断电到双通道,保姆级教程带你一次搞定 每次打开设计软件时卡顿的进度条,或是同时运行多个虚拟机时的系统崩溃,都在提醒你:16GB内存已经不够用了。作为ThinkPad P53的用户,你…...

安卓13时代,如何绕过应用检测?深入AOSP源码修改定位与设备信息的实战指南

安卓13深度定制:从AOSP源码层重构设备指纹的工程实践 在移动应用风控与隐私保护的博弈中,设备指纹技术已进化到多维度交叉验证阶段。主流金融、社交类应用通过融合传感器数据、内核级系统调用以及硬件抽象层(HAL)特征,…...

RWKV7-1.5B-World的Java后端集成指南:SpringBoot API服务开发

RWKV7-1.5B-World的Java后端集成指南:SpringBoot API服务开发 1. 前言:为什么选择RWKV7-1.5B-World RWKV7-1.5B-World作为新一代开源大语言模型,以其高效的推理性能和适中的模型尺寸,成为企业级应用的热门选择。对于Java开发者而…...

ArcGIS Pro二次开发:用C#和Geoprocessing工具5分钟搞定面要素重叠检查

ArcGIS Pro二次开发:5分钟实现面要素拓扑检查的自动化方案 地理信息系统(GIS)工作中,面要素的拓扑检查是确保数据质量的关键环节。传统手动操作不仅耗时费力,还容易因操作失误导致结果偏差。本文将展示如何利用ArcGIS Pro SDK和C#代码&#x…...

TMSpeech:Windows本地实时语音转文字终极指南 - 5分钟完成专业配置

TMSpeech:Windows本地实时语音转文字终极指南 - 5分钟完成专业配置 【免费下载链接】TMSpeech 腾讯会议摸鱼工具 项目地址: https://gitcode.com/gh_mirrors/tm/TMSpeech 想要一款完全免费、无需联网的实时语音转文字工具吗?TMSpeech正是你需要的…...

AI Agent Harness与区块链结合:可信执行

AI Agent Harness与区块链结合:构建下一代可信AI执行体系 引言 背景介绍 2023年以来,以AutoGPT、GPTs为代表的AI Agent技术爆发,正在重新定义软件的交互形态:不同于传统软件的固定逻辑,AI Agent可以自主感知环境、调用工具、制定决策、完成复杂任务,被行业普遍认为是继…...

中兴光猫深度管理:5分钟解锁zteOnu隐藏功能,告别Web界面限制

中兴光猫深度管理:5分钟解锁zteOnu隐藏功能,告别Web界面限制 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 你是否曾经面对中兴光猫的Web管理界面感到束手无策…...

终极解决方案:一次性修复Windows所有VC++运行库依赖问题

终极解决方案:一次性修复Windows所有VC运行库依赖问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经兴奋地打开一款新游戏或专业软件&am…...

如何快速掌握英雄联盟LCU工具:3大核心功能完全指南

如何快速掌握英雄联盟LCU工具:3大核心功能完全指南 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League Akari 是一款基于英雄联…...

OpenFace完整指南:5分钟掌握面部行为分析核心技术

OpenFace完整指南:5分钟掌握面部行为分析核心技术 【免费下载链接】OpenFace OpenFace – a state-of-the art tool intended for facial landmark detection, head pose estimation, facial action unit recognition, and eye-gaze estimation. 项目地址: https:…...