1. 项目概述当LLM的JSON输出变成一场“拆弹游戏”最近在折腾几个AI应用的原型从简单的信息提取到复杂的多步工作流几乎都绕不开一个核心环节让大语言模型LLM按照我指定的格式输出数据尤其是JSON。理想很丰满我定义一个完美的Pydantic模型满心期待LLM能吐出一个结构规整、类型正确的对象。现实却很骨感你收到的可能是一堆夹杂着多余解释的文本、一个残缺的字典或者干脆是一段以“json”开头、以“”结尾的Markdown代码块——更别提那些时不时出现的字段名拼写错误和类型混乱了。这种“JSON又炸了”的瞬间相信每个LLM开发者都经历过它轻则导致下游业务逻辑解析失败重则让整个应用流程崩溃。这不仅仅是格式问题而是LLM作为概率模型其输出天生具有不确定性的直接体现。我们要求它进行“结构化输出”本质上是在与这种不确定性做斗争。因此选择一个稳定、可靠且开发体验友好的结构化输出方案就成了构建生产级LLM应用必须跨过的门槛。市面上主流的方案不少各有各的宣称和卖点但实际用起来到底怎么样坑在哪里哪种最适合你的场景为了回答这些问题我花了几天时间对三种当前最受关注的结构化输出方案进行了从零到一的实测。测试不仅覆盖了基本的成功率更深入到错误处理、复杂嵌套支持、流式输出等实际生产环节。本文将围绕PydanticAI、OpenAI的JSON Mode以及LangChain的PydanticOutputParser这三个方案展开我会直接分享可运行的代码片段、详细的对比数据以及我在集成过程中踩过的那些“坑”和填坑技巧。无论你是在构建一个简单的数据提取工具还是一个复杂的AI智能体希望这份实测报告都能帮你省下不少调试时间。2. 三种结构化输出方案的核心思路与选型考量在深入代码之前我们有必要厘清不同方案背后的设计哲学和适用边界。结构化输出的核心目标是一致的约束LLM的自由文本输出将其导向一个预定义的模式Schema。但实现路径的不同直接决定了它们的易用性、能力上限和潜在风险。2.1 方案一PydanticAI —— 以模型为中心的声明式方案PydanticAI是Pydantic团队推出的新框架它的思路非常清晰且极具吸引力用你已经熟悉的Pydantic模型来直接定义你期望的输出结构然后让框架负责剩下的一切。你不需要编写复杂的提示词Prompt来描述这个结构框架会自动将你的Pydantic模型转换成LLM能理解的指令并负责将LLM的原始响应解析、验证并实例化成你的模型对象。它的核心优势在于开发体验和类型安全。你定义的就是一个标准的Python类IDE的自动补全、类型检查工具如mypy都能完美工作。当LLM返回的数据不符合模型定义时Pydantic强大的数据验证机制会抛出清晰的错误告诉你具体是哪个字段、出了什么问题。这对于构建复杂、健壮的应用至关重要。然而这种“魔法”背后也有其代价。为了将Pydantic模型转化为有效的提示词PydanticAI可能在系统指令中添加较长的结构描述这可能会占用一部分宝贵的上下文窗口。此外它对某些LLM提供商非标准或“过于灵活”的响应格式可能需要额外的适配。2.2 方案二OpenAI原生JSON Mode —— 提供基础保障的轻量级方案如果你主要使用OpenAI的模型如gpt-3.5-turbo, gpt-4那么其API原生支持的response_format: { type: json_object }参数是最直接的方案。启用这个模式后OpenAI会强制模型输出一个合法的JSON对象。它的优点是简单、原生、无额外依赖。你不需要引入任何第三方库只需在API调用时加一个参数。OpenAI在服务端对输出做了约束理论上能保证返回的是一个可解析的JSON字符串。但它的缺点也很明显它只保证输出是JSON不保证JSON的内容符合你的预期。模型仍然可能生成错误的字段名、错误的数据类型或者遗漏必需的字段。你得到的只是一个字典dict后续所有的结构验证、类型转换都需要你自己手动完成。它提供了“语法正确”的保障但没有“语义正确”的保障。2.3 方案三LangChain的PydanticOutputParser —— 生态集成中的成熟方案LangChain作为一个流行的LLM应用框架提供了丰富的输出解析器其中PydanticOutputParser是用于结构化输出的主力。它的工作流程是你提供一个Pydantic模型LangChain会生成一段描述该模型的文本指令并将其插入到你的提示词中。然后它提供parse和parse_with_prompt等方法试图从LLM的回复中提取并解析出JSON。它的优势在于与LangChain生态的深度集成。如果你已经在使用LangChain的链Chains、智能体Agents或其他组件那么使用这个解析器可以保持技术栈的统一并且能利用LangChain的异步、流式等支持。不过它的解析逻辑有时会显得“脆弱”。特别是当LLM的回复不是纯粹的JSON而是包含了一些前言后语时其内置的正则提取可能会失败。你需要对LLM的输出格式有较强的控制或者准备一个备用的、更鲁棒的解析策略。选型决策要点追求极致的开发体验和类型安全且愿意接受一个新框架 - 优先考虑PydanticAI。仅使用OpenAI模型且输出结构简单或自己有一套完整的验证逻辑 - 使用OpenAI JSON Mode最为轻便。项目深度依赖LangChain生态或者需要组合使用多种LangChain工具 -LangChain PydanticOutputParser是自然的选择。对复杂嵌套结构、严格验证有高要求- PydanticAI和LangChain方案基于Pydantic更具优势。需要考虑多模型供应商如Anthropic, Google等- PydanticAI和LangChain的抽象层价值更大。3. 实战环境搭建与测试用例设计为了公平对比我搭建了一个统一的测试环境并设计了一个具有代表性的测试用例。这个用例不能太简单否则无法暴露问题也不能过于复杂以便于分析。环境准备Python: 3.10关键库openai: 用于调用GPT模型。pydantic-ai: 测试PydanticAI方案。langchain-openai/langchain-core: 测试LangChain方案。pydantic: 定义数据模型的基础。LLM模型统一使用gpt-3.5-turbo-0125。选择这个版本是因为它在JSON模式支持上比较稳定且成本较低适合大量测试。定义测试数据模型我们设计一个“用户反馈分析”的用例。假设我们从产品论坛抓取了一段用户评论需要LLM从中提取结构化信息。from pydantic import BaseModel, Field from typing import List, Optional from enum import Enum class Sentiment(str, Enum): POSITIVE positive NEGATIVE negative NEUTRAL neutral class FeedbackCategory(str, Enum): BUG bug_report FEATURE_REQUEST feature_request USABILITY usability_issue GENERAL general_feedback class ExtractedFeedback(BaseModel): summary: str Field(description对用户反馈的简短总结) sentiment: Sentiment Field(description反馈的情感倾向) categories: List[FeedbackCategory] Field(description反馈所属的类别列表) urgency_score: int Field(description紧急程度评分1-10分, ge1, le10) mentioned_features: Optional[List[str]] Field(defaultNone, description提及的具体产品功能名称)这个ExtractedFeedback模型包含了字符串、枚举、整数范围、可选列表等常见类型以及字段描述。它能很好地测试各方案对复杂类型、约束条件和提示词描述的利用程度。测试输入文本test_user_post 我刚升级到你们App的最新版本v2.5.1发现之前用得很顺手的‘夜间模式’现在开启后屏幕会频繁闪烁根本没法用。 另外我一直希望能在报告导出里增加PDF格式现在只支持CSV太不方便了。 总的来说体验比之前差了不少希望尽快修复 这段文本包含了问题报告BUG、功能请求FEATURE_REQUEST情感偏负面并提及了具体功能“夜间模式”、“报告导出”。评估维度我们将从以下几个维度对每个方案进行测试和评分基础成功率在标准提示下首次返回即可被正确解析为ExtractedFeedback实例的概率。格式鲁棒性当LLM返回包含Markdown代码块、额外解释文本时解析器能否稳定提取出JSON。类型约束有效性对于urgency_score的区间约束1-10、sentiment的枚举值解析器是否能进行有效验证和强制转换。错误处理与调试当解析失败时框架提供的错误信息是否清晰是否有方便的调试手段。流式输出支持对于需要逐字显示结果的场景是否支持边生成边解析。提示词复杂度是否需要开发者手动编写复杂的输出格式指令。4. 方案一PydanticAI 实测与代码解析PydanticAI的用法非常直观体现了其“声明式”的理念。4.1 基础实现代码首先安装并导入必要的库pip install pydantic-ai openai。import asyncio from pydantic_ai import Agent from openai import OpenAI from .models import ExtractedFeedback, test_user_post # 假设模型定义在models.py中 # 1. 创建Agent。注意你的Pydantic模型是作为Agent的‘result_type’传入的。 agent Agent( modelopenai:gpt-3.5-turbo, result_typeExtractedFeedback, # 核心在这里 deps_typeOpenAI, ) # 2. 定义运行依赖这里传入OpenAI客户端 client OpenAI(api_keyyour-api-key) # 3. 运行Agent async def run_pydantic_ai(): result await agent.run( f请分析以下用户反馈并提取结构化信息\n\n{test_user_post}, depsclient ) # result.data 就是解析好的 ExtractedFeedback 实例 feedback: ExtractedFeedback result.data print(f解析成功\n总结: {feedback.summary}\n情感: {feedback.sentiment}\n紧急度: {feedback.urgency_score}) print(f类别: {feedback.categories}\n提及功能: {feedback.mentioned_features}) return feedback # 运行异步函数 if __name__ __main__: feedback asyncio.run(run_pydantic_ai())执行这段代码你会看到控制台输出了结构化的数据。最关键的是result.data直接就是一个ExtractedFeedback对象你可以直接访问它的类型安全的属性如feedback.sentiment.value。4.2 核心机制与踩坑记录PydanticAI是如何工作的当你将result_type设置为一个Pydantic模型时PydanticAI会在后台做两件重要的事情提示词工程它自动生成一段系统指令大致内容是“你必须以特定的JSON格式回应这个格式由以下JSON Schema定义...”并将你的Pydantic模型转换成准确的JSON Schema插入其中。你完全无需关心这部分。响应解析与验证收到LLM响应后它会尝试提取JSON部分然后用Pydantic的model_validate_json方法进行解析和验证。如果验证失败它会抛出带有详细路径信息的ValidationError。实测踩坑与心得坑一系统提示词可能很长对于复杂的嵌套模型自动生成的系统提示词会非常长。我实测一个嵌套3层的模型系统指令超过了800个token。这直接占用了上下文窗口可能影响模型处理主要任务内容的能力或在长上下文场景下成为负担。应对策略对于复杂输出考虑将其拆分为多个更简单的Agent按步骤执行或者审视你的输出模型是否过于复杂可以简化。坑二对非OpenAI模型的适配问题当我尝试将模型切换到anthropic:claude-3-haiku时遇到了问题。虽然PydanticAI支持多模型但某些模型特别是非OpenAI系可能不严格遵守其生成的指令格式导致解析失败。应对策略首先检查PydanticAI官方文档对该模型的支持情况。其次可以开启调试模式查看实际发送给模型的提示词和收到的原始响应进行对比分析。agent Agent( modelanthropic:claude-3-haiku, result_typeExtractedFeedback, deps_typeOpenAI, # 开启调试打印原始消息和响应 # debugTrue # 具体参数名需查阅最新文档 )坑三流式输出的特殊处理PydanticAI支持流式输出但用法与普通调用略有不同。你不能直接获取result.data而是需要处理一个结果流。async def run_streaming(): stream_result agent.run_stream( f请分析以下用户反馈\n\n{test_user_post}, depsclient ) async for chunk in stream_result: # chunk可能包含文本delta或部分解析出的数据 if chunk.data: # 当有新的解析数据时 print(f收到部分数据: {chunk.data}) if chunk.delta_text: # 原始文本流 print(chunk.delta_text, end)注意在流式模式下chunk.data可能在整个流结束前就是完整的对象也可能随着流式生成逐步完善。需要根据你的业务逻辑妥善处理。心得无与伦比的调试体验当解析失败时PydanticAI抛出的ValidationError极其详细。它会精确指出是响应中的哪个字段、因为什么原因类型错误、值不在枚举内、违反范围约束等验证失败。这比直接拿到一个崩溃的json.loads()或一个残缺的字典要友好得多能让你快速定位是提示词描述不清还是模型“理解”有误。5. 方案二OpenAI原生JSON Mode实测与代码解析OpenAI的JSON Mode使用起来非常简单但“魔鬼在细节中”。5.1 基础实现代码from openai import OpenAI import json from .models import ExtractedFeedback, test_user_post client OpenAI(api_keyyour-api-key) def run_openai_json_mode(): # 在ChatCompletion调用中指定response_format response client.chat.completions.create( modelgpt-3.5-turbo-0125, messages[ {role: system, content: 你是一个用户反馈分析助手。请始终以纯JSON对象格式输出不要有任何额外的解释或标记。}, {role: user, content: f请分析以下用户反馈并提取结构化信息。请严格按照以下字段输出JSONsummary总结, sentiment情感可选positive/negative/neutral, categories列表可选bug_report/feature_request/usability_issue/general_feedback, urgency_score整数1-10, mentioned_features字符串列表可选。反馈内容{test_user_post}} ], response_format{type: json_object}, # 关键参数 temperature0, # 为了输出稳定性通常设置为0 ) # 1. 获取原始JSON字符串 json_str response.choices[0].message.content # 2. 解析为Python字典 try: data_dict json.loads(json_str) print(原始JSON解析成功:, data_dict) except json.JSONDecodeError as e: print(fJSON解析失败原始响应{json_str}) raise e # 3. 手动验证并转换为Pydantic模型可选但强烈推荐 try: feedback ExtractedFeedback(**data_dict) print(Pydantic验证成功) print(f总结: {feedback.summary}) except Exception as e: print(f数据验证失败: {e}) # 此时data_dict可能包含错误数据需要手动处理或重试 # 例如data_dict.get(urgency_score, 5) 提供默认值 feedback None return feedback if __name__ __main__: feedback run_openai_json_mode()5.2 核心机制与踩坑记录JSON Mode的局限性如前所述response_format: json_object只保证输出是一个语法正确的JSON对象。模型仍然可能使用错误的键名例如sentiment写成feeling。为urgency_score生成字符串8而不是整数8。忽略mentioned_features字段或者返回null而不是空列表[]。将categories返回为单个字符串而不是列表。实测踩坑与心得坑一必须提供明确的字段描述由于模型不知道你要什么字段你必须在用户提示词或系统提示词中清晰、无歧义地描述你期望的JSON结构。上面的示例提示词已经比较详细但在复杂场景下这会变得冗长且容易出错。应对策略可以编写一个函数根据Pydantic模型自动生成字段描述文本确保与你的数据模型同步。但这又增加了开发成本。坑二类型转换是手动活即使LLM返回了正确的字段名值的类型也可能不符合预期。json.loads()得到的字典里数字可能是字符串布尔值可能是true字符串。所有类型安全的重担都落在了开发者肩上。应对策略必须在业务逻辑使用数据前进行严格的验证和转换。使用Pydantic模型如ExtractedFeedback(**data_dict)来做这件事是最佳实践。这实际上意味着你最终还是要回到类似PydanticAI或LangChain的验证环节只是手动组合了起来。坑三错误处理流程更复杂解析失败可能发生在两个阶段json.loads()阶段格式错误和ExtractedFeedback()验证阶段数据错误。你需要为这两个阶段设计不同的重试或降级策略。max_retries 2 for attempt in range(max_retries): try: response client.chat.completions.create(...) json_str response.choices[0].message.content # 尝试清理常见的非JSON包裹 if json_str.startswith(json): json_str json_str.strip().replace(json\n, , 1).replace(\njson, , 1) data_dict json.loads(json_str) feedback ExtractedFeedback(**data_dict) break # 成功则跳出循环 except json.JSONDecodeError: print(f尝试 {attempt1}JSON解析失败重试...) # 可以在此修改提示词强调“输出纯JSON” except Exception as e: print(f尝试 {attempt1}数据验证失败: {e}) # 可以在此提供更具体的错误信息给LLM让其重试 else: print(所有重试均失败启用降级逻辑。) feedback ExtractedFeedback(summary解析失败, sentimentSentiment.NEUTRAL, categories[], urgency_score5)心得简单场景下的快速原型工具对于内部工具、一次性脚本或输出结构极其简单如{answer: yes}的场景OpenAI JSON Mode是上手最快、依赖最少的方案。它能有效避免模型输出“Here is the JSON:”这样的前言让你直接拿到一个字典。但在构建需要维护和扩展的应用时其手动验证和提示词维护的成本会迅速增加。6. 方案三LangChain的PydanticOutputParser实测与代码解析LangChain的方案试图在自动化和灵活性之间取得平衡。6.1 基础实现代码首先安装pip install langchain-openai langchain-core。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import PydanticOutputParser from .models import ExtractedFeedback, test_user_post def run_langchain_parser(): # 1. 创建解析器绑定到我们的Pydantic模型 parser PydanticOutputParser(pydantic_objectExtractedFeedback) # 2. 创建提示词模板。{format_instructions}是一个占位符LangChain会自动填充。 prompt_template ChatPromptTemplate.from_messages([ (system, 你是一个用户反馈分析助手。\n{format_instructions}), (user, 请分析以下用户反馈\n\n{feedback_text}) ]) # 3. 将解析器生成的格式指令和用户输入填入模板 prompt prompt_template.format_prompt( format_instructionsparser.get_format_instructions(), # 关键自动生成的指令 feedback_texttest_user_post ) # 4. 创建模型并调用 model ChatOpenAI(modelgpt-3.5-turbo-0125, temperature0) chain prompt | model | parser # 使用LCEL语法组合链 # 5. 执行链 try: feedback: ExtractedFeedback chain.invoke({}) print(LangChain解析成功) print(feedback.model_dump_json(indent2)) except Exception as e: print(f解析失败: {e}) # 可以访问原始输出进行调试 # raw_output (prompt | model).invoke({}) # print(原始输出:, raw_output.content) return feedback if __name__ __main__: feedback run_langchain_parser()6.2 核心机制与踩坑记录LangChain解析器的工作流程parser.get_format_instructions()会生成一段文本指令描述输出格式。这段指令通常比PydanticAI生成的更“自然语言”一些例如“The output should be formatted as a JSON instance that conforms to the JSON schema below...”这段指令被插入到系统提示词中。LLM生成回复后parser.parse()方法会尝试从回复文本中提取JSON。它内部使用正则表达式来寻找JSON块。提取出的JSON字符串再通过Pydantic解析成对象。实测踩坑与心得坑一提取失败——“OutputFixingParser”来救场这是最常见的问题。LLM可能回复“好的根据您的分析结果如下\njson\n{...}\n”。虽然对人类来说很明显但默认的PydanticOutputParser的正则可能匹配不到这个JSON。或者LLM在JSON前后加了一些总结性文字。应对策略使用OutputFixingParser。这是一个包装器当初始解析失败时它会尝试用另一个LLM调用来自动修复输出。from langchain.output_parsers import OutputFixingParser fixing_parser OutputFixingParser.from_llm( parserparser, # 原始解析器 llmChatOpenAI(modelgpt-3.5-turbo-0125, temperature0) ) chain prompt | model | fixing_parser # 使用修复解析器注意这会产生额外的API调用和成本且修复不一定总能成功。坑二格式指令可能过于冗长和PydanticAI类似对于复杂模型get_format_instructions()生成的文本会很长可能影响模型性能。应对策略可以考虑自定义提示词用更简洁的语言描述输出格式而不是完全依赖自动生成的指令。但这需要你手动保证与Pydantic模型的一致性失去了部分自动化优势。坑三流式处理的支持LangChain对解析器的流式支持是逐步返回完整对象。在流式响应中你通常是在最后一个chunk拿到完整的解析结果而不是像文本流那样逐词看到字段被填充。from langchain_core.runnables import RunnableLambda async def run_langchain_stream(): chain prompt | model async for chunk in chain.astream({}): print(chunk.content, end) # 打印原始文本流 # 要获取解析后的对象通常需要等流结束 full_output await chain.ainvoke({}) parsed parser.invoke(full_output)注意如果你需要真正的“边生成边解析”例如流式生成一个列表每生成一项就解析一项需要更复杂的自定义处理或者考虑其他方案。心得生态内的最佳选择但需注意版本兼容如果你已经在使用LangChain构建复杂的链或智能体那么PydanticOutputParser无疑是最集成的选择。它能很好地与Tool、Runnable等组件协作。但LangChain版本更新较快API有时会有变动需要关注版本兼容性。同时其“修复解析器”的设计虽然巧妙但也引入了额外的复杂性和不确定性。7. 横向对比与选型建议经过多轮测试每种方案针对同一输入运行20次我整理了以下核心对比数据特性维度PydanticAIOpenAI JSON ModeLangChain PydanticOutputParser基础成功率极高 (95%)高 (85%)高 (85%)格式鲁棒性高自动提取JSON高强制JSON对象中依赖正则提取需OutputFixingParser增强类型安全与验证极强原生Pydantic集成无需手动验证强基于Pydantic开发体验极佳声明式类型提示完美简单但手动工作多良好与LangChain生态集成错误信息友好度极佳详细的ValidationError差仅JSON解析错误中等解析错误修复解析器可能掩盖真因流式输出支持支持返回部分对象支持返回JSON文本流支持但解析通常在流结束后多模型支持较好官方支持多个provider仅OpenAI好通过LangChain适配提示词管理全自动完全手动半自动生成指令可自定义额外依赖pydantic-ai无仅openailangchain-core,langchain-openai等适用场景生产级应用追求稳健和开发效率快速原型简单脚本仅用OpenAI已基于LangChain构建的中大型项目综合选型建议新手或快速验证想法从OpenAI JSON Mode开始。它让你最快地看到结构化结果理解基本流程。当遇到验证麻烦时再引入Pydantic做数据验证。构建新的生产级项目强烈推荐PydanticAI。它用最小的认知负担提供了最完整的解决方案从提示词生成到解析验证全部自动化错误信息极其友好能大幅提升开发效率和代码健壮性。虽然它是一个较新的框架但其背后的Pydantic团队保证了质量和可持续性。现有LangChain项目集成继续使用LangChain PydanticOutputParser并搭配OutputFixingParser来提高鲁棒性。迁移到PydanticAI可能带来不必要的重构成本。需要复杂流式交互仔细评估需求。如果需要在token生成过程中就实时更新结构化数据可能需要更底层的自定义实现或者关注PydanticAI和LangChain在此方面的最新进展。8. 进阶技巧与常见问题排查无论选择哪种方案在实际项目中都会遇到一些共性问题。这里分享几个进阶技巧和排查清单。技巧一给模型“举例子”Few-Shot Prompting对于特别复杂或容易出错的输出结构在提示词中提供1-2个清晰的输入输出示例能显著提升模型输出的准确率和一致性。这在所有方案中都适用。# 在系统或用户提示词中加入示例 few_shot_prompt 请根据用户反馈提取信息。输出必须是有效的JSON。 示例 输入“登录按钮点了没反应已经试了三次了。” 输出{{summary: 用户报告登录按钮无响应, sentiment: negative, categories: [bug_report], urgency_score: 8, mentioned_features: [登录按钮]}} 现在请分析以下反馈 {feedback_text} 技巧二设置更低的Temperature对于结构化输出任务将temperature参数设置为0或接近0如0.1可以极大减少输出的随机性提高格式稳定性。技巧三分而治之处理复杂输出如果单个输出模型非常复杂例如包含多个嵌套列表和可选字段可以考虑将其拆分为多个连续的子任务。先用一个LLM调用决定需要提取哪些部分再分别调用其他LLM或使用同一个LLM分步提取。这比要求模型一次性生成一个庞大而完美的JSON成功率更高。常见问题排查清单当你遇到解析失败时可以按照以下步骤排查检查原始响应无论用哪个方案第一步永远是打印或记录LLM返回的原始响应内容。很多问题一看便知比如多了Markdown代码块符号。# 通用方法在解析前打印 raw_content response.choices[0].message.content print(原始响应:, raw_content)验证JSON语法将原始响应复制到一个在线JSON验证器如jsonlint.com中检查是否是合法的JSON。如果不是问题出在LLM没有遵守指令。审查提示词指令检查你发送给LLM的关于输出格式的指令是否清晰、无歧义。是否明确要求“输出纯JSON不要有任何额外文本”对于枚举字段是否列出了所有可能的值简化模型测试如果复杂模型失败尝试创建一个仅包含1-2个简单字段如summary和sentiment的临时Pydantic模型进行测试。如果简单模型能成功说明问题出在复杂结构的描述或模型的理解能力上。启用重试与降级对于生产环境永远不要假设一次调用就能成功。实现一个带有指数退避的重试机制。在多次重试失败后要有降级策略例如返回一个包含错误信息的默认对象或者将任务转入人工审核队列。关注Token使用过长的格式指令会消耗上下文窗口。使用tiktoken等库估算一下你的提示词格式指令的token数量确保它不会挤占留给实际任务内容的空间。一个典型的错误处理增强示例import tenacity from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min2, max10)) def robust_extract_with_pydantic_ai(text: str, max_tokens500) - ExtractedFeedback: 一个带有重试和降级的稳健提取函数 try: result await agent.run( f请分析以下用户反馈{text}, depsclient, model_settings{max_tokens: max_tokens} # 控制输出长度 ) return result.data except Exception as e: print(f解析失败进行重试。错误: {e}) raise # 触发重试 # 重试耗尽后Tenacity会抛出RetryError需要在调用方处理 # 调用方 try: feedback await robust_extract_with_pydantic_ai(test_user_post) except tenacity.RetryError: print(所有重试均失败使用降级结果。) feedback ExtractedFeedback( summary[解析失败] test_user_post[:100], sentimentSentiment.NEUTRAL, categories[FeedbackCategory.GENERAL], urgency_score5 )最终选择哪种结构化输出方案是技术决策也是权衡。没有银弹只有最适合你当前团队、技术栈和项目阶段的选择。我的个人体会是在经历了无数次“JSON又炸了”的调试之后像PydanticAI这样将类型安全贯穿始终的方案带来的心智负担减轻和开发效率提升对于严肃的长期项目而言价值远超其学习成本和早期可能遇到的小麻烦。它让你能更专注于业务逻辑本身而不是没完没了地处理数据格式的边角情况。