【langchain】结构化输出:ToolStrategy与ProviderStrategy 【langchain】结构化输出ToolStrategy与ProviderStrategy当AI开始说人话但你需要的是JSON你有没有遇到过这种抓狂的场景让AI分析一段文本它给你回了一大段优美的散文——“根据您提供的信息这位客户的姓名似乎是张三他的联系方式可能是138xxxx…”“似乎”、“可能”、“根据您提供的信息”…这些客套话在代码里全是噪音。你真正想要的是{name:张三,phone:138xxxx,email:zhangsanexample.com}就像去餐厅点餐服务员给你念了五分钟的菜品介绍而你只想知道价格和卡路里。今天我们就来聊聊LangChain 1.0如何让AI闭嘴直接给你结构化数据。两种驯服AI的策略LangChain 1.0提供了两种结构化输出策略就像两种不同的话术技巧让AI乖乖按格式输出策略适用场景可靠性兼容性ProviderStrategyOpenAI、Anthropic、Gemini等原生支持⭐⭐⭐⭐⭐仅限特定厂商ToolStrategy所有支持工具调用的模型⭐⭐⭐⭐通用兼容ProviderStrategy原生派的特权想象你走进一家高级餐厅服务员训练有素你一说按这个格式报菜名他立刻用标准格式回复。这就是ProviderStrategy——利用模型厂商原生的结构化输出能力。frompydanticimportBaseModel,Fieldfromlangchain.agentsimportcreate_agentfromlangchain.agents.structured_outputimportProviderStrategyclassOrderSummary(BaseModel):订单摘要customer:strField(description客户名称)total_items:intField(description商品总数)total_amount:floatField(description订单总金额美元)# 使用原生结构化输出agentcreate_agent(modelopenai:gpt-4o,tools[],response_formatProviderStrategy(OrderSummary),)resultagent.invoke({messages:[{role:user,content:Acme Corp买了10个Widget A$29.99和5个Widget B$49.99}]})print(result[structured_response])# OrderSummary(customerAcme Corp, total_items15, total_amount549.85)优势很明显✅ 模型在生成时就强制遵循Schema不会跑偏✅ 支持严格模式strict mode使用约束解码✅ 通常性能更好延迟更低但有个坑要注意DeepSeek等部分国内大模型暂时不支持ProviderStrategy会直接报400错误。ToolStrategy万能派的曲线救国如果服务员没受过专业训练怎么办你可以说“请把信息填在这个表格里”——本质上是用填表这个工具来约束输出格式。这就是ToolStrategy的工作原理fromlangchain.agents.structured_outputimportToolStrategy agentcreate_agent(modeldeepseek-chat,# 或其他不支持原生结构化的模型tools[],response_formatToolStrategy(OrderSummary),)LangChain会悄悄创建一个虚拟工具让模型以为自己在调用工具实际上是在生成结构化数据。它的优势✅ 兼容所有支持工具调用的模型几乎是全部✅ 不挑厂商本地模型、开源模型都能用但也有代价❌ 多了一层转换可靠性略低于原生方案❌ 需要模型支持工具调用虽然这已经普及了Pydantic你的数据模具无论用哪种策略你都需要先定义输出格式。LangChain推荐使用Pydantic模型——这就像给AI一个精确的模具告诉它按这个形状浇筑数据。基础定义frompydanticimportBaseModel,Field,EmailStr,validatorfromtypingimportList,OptionalfromenumimportEnumclassPriority(str,Enum):LOWlowMEDIUMmediumHIGHhighclassTaskItem(BaseModel):单个任务项title:strField(description任务标题)completed:boolField(description是否已完成)classTaskList(BaseModel):任务清单project_name:strField(description项目名称)priority:PriorityField(description优先级)tasks:List[TaskItem]Field(description任务列表)deadline:Optional[str]Field(None,description截止日期可选)# 自定义验证validator(project_name)defvalidate_name(cls,v):iflen(v)2:raiseValueError(项目名称至少需要2个字符)returnv.strip()支持的Schema类型LangChain很灵活你可以用多种形式定义结构类型示例返回结果Pydantic BaseModelclass Contact(BaseModel)Pydantic实例TypedDictclass Contact(TypedDict)字典dataclassdataclass class Contact字典JSON Schema{type: object, ...}字典推荐用Pydantic因为它提供运行时类型验证还能加自定义校验逻辑。错误处理当AI手滑时即使是最先进的模型偶尔也会手滑——返回不符合格式的数据。ToolStrategy提供了错误重试机制# 方式1自动处理所有错误默认ToolStrategy(schemaOrderSummary,handle_errorsTrue)# 方式2自定义错误提示ToolStrategy(schemaOrderSummary,handle_errors请提供完整的订单信息包括客户名、商品数量和总金额。)# 方式3自定义错误处理函数defmy_error_handler(error:Exception)-str:returnf格式错误{str(error)}。请检查数字字段是否为数值类型。ToolStrategy(schemaOrderSummary,handle_errorsmy_error_handler)# 方式4不处理直接抛出异常调试时用ToolStrategy(schemaOrderSummary,handle_errorsFalse)工作原理当验证失败时错误信息会被送回给模型AI会尝试修正并重新输出。这就像一个自动纠错循环直到输出符合格式或达到重试上限。实战智能订单解析器让我们把学到的知识串起来做一个实用的例子——从混乱的客户消息中提取结构化订单信息frompydanticimportBaseModel,Fieldfromlangchain.agentsimportcreate_agentfromlangchain.agents.structured_outputimportToolStrategy,ProviderStrategyfromlangchain.chat_modelsimportinit_chat_modelclassLineItem(BaseModel):订单行项目product_name:strField(description产品名称)quantity:intField(description数量,ge1)unit_price:floatField(description单价,gt0)classCustomerOrder(BaseModel):客户订单customer_name:strField(description客户姓名)items:List[LineItem]Field(description订单项目)notes:Optional[str]Field(None,description特殊备注)propertydeftotal(self)-float:returnsum(item.quantity*item.unit_priceforiteminself.items)# 初始化模型modelinit_chat_model(openai:gpt-4o-mini)# 策略选择优先ProviderStrategy不支持则回退到ToolStrategytry:response_formatProviderStrategy(CustomerOrder,strictTrue)except:response_formatToolStrategy(CustomerOrder,handle_errors请确保所有数字字段正确填写。)agentcreate_agent(modelmodel,tools[],response_formatresponse_format,)# 模拟一条混乱的客户消息messy_message 嗨我是李明想订点东西。 需要3个无线耳机每个299元 再加2个充电宝单价150吧。 对了希望能尽快发货急用 resultagent.invoke({messages:[{role:user,content:messy_message}]})orderresult[structured_response]print(f客户{order.customer_name})print(f总计¥{order.total:.2f})print(f商品数{len(order.items)}件)# 输出# 客户李明# 总计¥1197.00# 商品数2件关键细节结果存储在result[structured_response]中这是一个已验证的Pydantic实例可以直接访问属性如果启用了错误处理验证失败会自动触发重试策略选择决策树面对不同场景该如何选择记住这个简单的决策流程模型是否支持原生结构化输出 ├─ 是OpenAI GPT-4o、Anthropic Claude等 │ └─ 使用 ProviderStrategy(strictTrue) 获得最佳可靠性 │ └─ 否DeepSeek、部分开源模型等 └─ 使用 ToolStrategy(handle_errorsTrue) 保证兼容性懒人版直接传Pydantic类让LangChain自动选择# LangChain会自动检测模型能力选择最优策略agentcreate_agent(modelmodel,tools[],response_formatCustomerOrder,# 直接传Schema)但要注意LangChain 1.0之后显式使用Strategy是推荐做法自动选择可能在某些边缘情况下表现不稳定。生产环境 checklist在把结构化输出部署到生产环境前检查这几项✅Schema版本化业务变动时保留旧版本Schema以保证兼容性✅错误监控记录验证失败率如果过高可能需要调整Prompt或Schema✅超时设置重试机制会增加延迟设置合理的超时时间✅敏感信息不要在Schema中定义包含PII个人身份信息的字段描述小结今天我们学习了如何让AI说机器能听懂的话ProviderStrategy是VIP通道利用模型原生能力可靠性最高但兼容性有限ToolStrategy是万能钥匙通过工具调用实现兼容所有支持工具调用的模型Pydantic是你的数据模具定义清晰的结构并自动验证错误重试是安全网让AI有机会自我修正结构化输出不只是技术细节它是AI从玩具走向工具的关键一步。当你的应用能稳定地从AI输出中提取结构化数据时自动化流程、数据分析、系统集成才能真正落地。下一篇我们将聊聊流式处理——如何让AI的响应像打字机一样实时呈现而不是让用户盯着思考中…的转圈图标发呆。关注公众号【dev派】发送 “agent” 获取全部源码和模板