05 · 结构化输出:让模型交出”保证格式”的数据
本片目标:让模型不只输出文本,而是输出符合你定义的 schema 的对象——客服工单、抽取字段、分类结果。核心是with_structured_output+ Pydantic 蓝图。 新增规定性:5(输出契约:定义BaseModel蓝图,模型输出必须匹配) 数据字典:with_structured_output参数、Pydantic 蓝图、method三种模式。 进程线程模型:同 invoke(同步阻塞)。 网络模型:tool_calling 模式 = 模型走”工具调用”通道返回结构化 JSON(不是靠提示词”请输出 JSON”)。
1. 上集回顾
第 04 篇让模型输出文本和流式。但业务真正要的是结构化数据:- 客服:从用户吐槽里抽出
intent、order_id、urgency; - RAG:回答完还要返回引用来源列表;
- 报表:输出字段名必须对,方便程序直接读。
with_structured_output。
2. 数据字典:Pydantic 蓝图(规定性 5 的核心)
2.1 蓝图定义
关键:Pydantic 蓝图既是提示词的一部分(描述指导模型),又是输出校验器(解析结果必须符合)。
2.2 with_structured_output 签名
返回值:
invoke 后直接返回 Pydantic 实例(不是 AIMessage!)。type(result) 就是你的蓝图类。
2.3 它内部是什么?(衔接 04 篇的 parser 家族)
with_structured_output 不是”魔法 API”——它内部就是一个模型 + 一个解析器组成的管道(实测源码确认):
04 篇说过”StrOutputParser实现了通用接口BaseOutputParser,以后自定义解析器只需实现parse方法”——PydanticToolsParser就是这个家族里”最重”的成员。它把模型返回的tool_calls(JSON)解析成你的蓝图对象。 所以with_structured_output返回RunnableSequence而不是普通模型,就是因为它是bind_tools 的模型 | PydanticToolsParser两步管道。完整 parser 家族全景(StrOutputParser/JsonOutputParser/PydanticToolsParser等)见第 13 篇全地图的output_parsers模块。
3. 关键方法
3.1 嵌套蓝图:字段里带 list
蓝图可以嵌套——字段类型是 list[另一个蓝图],框架递归解析。典型场景:一次返回”一批工单”:
list[str] 类型的 sources 字段)——那个蓝图结构在 05 篇你已经会写了,只是还没接上检索。
4. 进程线程模型
5. 网络模型
with_structured_output 底层用的是工具调用协议——模型被”要求调用一个返回 JSON 的工具”。这是各家模型厂商都稳定支持的能力,比”提示词里写请输出 JSON”可靠得多。
6. 验证:跑起来
配套代码code/05_structured.py:
- 定义
SupportTicket蓝图; with_structured_output包模型;- 传一段吐槽,打印返回对象的类型、字段值、
model_dump(); - 对比普通
invoke的字符串输出; - 嵌套蓝图:一次返回一批工单。
7. 边界
- 字段越多越容易错——蓝图字段太多、描述不清时模型可能填错。保持字段少而清晰,
description写清楚。 - method 选择:默认
function_calling优先;你的模型不支持工具调用再降级json_mode。 - 嵌套结构:蓝图可以嵌套(
BaseModel里有list[AnotherModel]),框架递归解析。 - 枚举/校验:Pydantic 的
Field(ge=1, le=5)等约束会在解析时校验,超出会报错。
推荐资料(延伸阅读)
- LangChain 官方文档 · 结构化输出 —— with_structured_output 权威指南
- Pydantic 官方文档 · 模型 —— Pydantic 蓝图的定义规范