Skip to main content

05 · 结构化输出:让模型交出”保证格式”的数据

本片目标:让模型不只输出文本,而是输出符合你定义的 schema 的对象——客服工单、抽取字段、分类结果。核心是 with_structured_output + Pydantic 蓝图。 新增规定性:5(输出契约:定义 BaseModel 蓝图,模型输出必须匹配) 数据字典with_structured_output 参数、Pydantic 蓝图、method 三种模式。 进程线程模型:同 invoke(同步阻塞)。 网络模型tool_calling 模式 = 模型走”工具调用”通道返回结构化 JSON(不是靠提示词”请输出 JSON”)。

1. 上集回顾

第 04 篇让模型输出文本和流式。但业务真正要的是结构化数据
  • 客服:从用户吐槽里抽出 intentorder_idurgency
  • RAG:回答完还要返回引用来源列表
  • 报表:输出字段名必须对,方便程序直接读。
靠提示词”请输出 JSON”是脆弱的:模型可能输出多余说明文字、字段名拼错、JSON 语法错。你需要一个契约——模型必须输出符合你定义结构的对象,格式错了框架就重试或报错。 这就是 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 篇学的 parser,只是”剥的壳”不同
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[另一个蓝图],框架递归解析。典型场景:一次返回”一批工单”:
嵌套蓝图的用处:一次模型调用拿到”一批结构化结果”。第 09 篇 RAG 组装、第 15 篇完整后端项目会用这个能力返回”答案 + 引用来源列表”(list[str] 类型的 sources 字段)——那个蓝图结构在 05 篇你已经会写了,只是还没接上检索。

4. 进程线程模型

网络往返仍只有 1 次——结构化输出不是”先生成再校验重试”(除非解析失败)。它是一次调用,模型直接通过工具调用通道吐出 JSON。

5. 网络模型

关键洞察with_structured_output 底层用的是工具调用协议——模型被”要求调用一个返回 JSON 的工具”。这是各家模型厂商都稳定支持的能力,比”提示词里写请输出 JSON”可靠得多。

6. 验证:跑起来

配套代码 code/05_structured.py
  1. 定义 SupportTicket 蓝图;
  2. with_structured_output 包模型;
  3. 传一段吐槽,打印返回对象的类型、字段值、model_dump()
  4. 对比普通 invoke 的字符串输出;
  5. 嵌套蓝图:一次返回一批工单。
预期输出(节选,实测)

7. 边界

  • 字段越多越容易错——蓝图字段太多、描述不清时模型可能填错。保持字段少而清晰,description 写清楚。
  • method 选择:默认 function_calling 优先;你的模型不支持工具调用再降级 json_mode
  • 嵌套结构:蓝图可以嵌套(BaseModel 里有 list[AnotherModel]),框架递归解析。
  • 枚举/校验:Pydantic 的 Field(ge=1, le=5) 等约束会在解析时校验,超出会报错。

推荐资料(延伸阅读)


8. 未完待续

现在”输入”(模板)和”输出”(解析/结构化)都齐了。但有一个致命问题第 01 篇就埋下了:模型没有记忆
每次调用模型都是”金鱼脑”——不记得上次说了什么。怎么让对话连贯?这就是第 06 篇:记忆与会话。 06 · 记忆与会话