第 6 章 输出解析器
本章课程目标:
- 理解**输出解析器(Output Parser)**是什么、为什么需要它,以及它在 Model I/O 中所处的位置。
- 会使用 StrOutputParser、JsonOutputParser 处理字符串与 JSON 输出。
- 理解 LangChain 官方的**结构化输出(Structured Output)**思路,掌握 TypedDict、Pydantic、JSON Schema 三种 schema 方式的差异。
学习建议: 这章要解决的是“模型说的话,程序怎么放心使用”。可以从 StrOutputParser 跑到 JsonOutputParser,再跑到 Pydantic,边跑边看哪里只是解析,哪里才发生校验。读完后能分清 Parser、Structured Output、TypedDict、Pydantic、JSON Schema 的边界,就已经抓住重点了。
官方文档与资源:详见 工具导航与参考资料索引 - 提示词与结构化输出。
1、输出解析器简介
本章对应 Model I/O 中的输出解析(Parse)部分:把模型的文本输出转成程序易用的结构化数据(如字符串、JSON、强类型对象)。与 第 5 章 提示词(Format(输入格式化))、第 3 章模型(Predict(模型调用))组合,即形成「输入 → 模型 → 输出解析」完整链路,第 7 章 LCEL 会用管道符将三者串成一条链。
1.1 定义
输出解析器(Output Parser),就是站在模型输出和程序最终要用的数据之间的一层转换器。
它的核心任务是:把模型返回的内容,从“面向人阅读”的文本,转成“面向程序处理”的结构化结果。
这条链可以拆成:
- Prompt 负责把输入整理好,告诉模型“你要怎么回答”;
- Model 负责生成结果,真正“生成回答”;
- Output Parser 负责把结果转成字符串、JSON 或对象,把这份回答“整理成程序好用的样子”。
- 第 15 章 LCEL 与链式调用 会把这条链真正串起来。

放到实际使用中,根据解析器类型不同,输出解析器通常会承担下面几类工作:
- 格式转换:把模型回答转成
str、dict、Pydantic 对象等。 - 结构约束:引导模型尽量按指定字段输出。
- 结果校验:检查字段类型、范围、必填项是否符合预期。
- 工程衔接:让模型输出能被数据库、接口、前端、工作流直接消费。
1.2 输出解析器的作用
初学大模型时,最容易把模型回答理解成“它回我一段文字就结束了”。但在真实项目里,模型输出通常还要继续流向别的程序模块,例如:
- 存进数据库;
- 返回给前端页面渲染;
- 交给下一个工作流节点;
- 作为 Agent、工具、接口调用的参数;
- 进入风控、审核、统计、报表逻辑。
这时,“一段自然语言”通常就不够用了。程序更希望拿到的是:
- 一个字符串;
- 一个 JSON 字典;
- 一个字段固定的对象;
- 一个带校验规则的强类型数据结构。
如果只靠 split()、正则、字符串截取去拆模型输出,代码往往会变得脆弱:模型多加一句解释、少一个逗号、换一个字段名,程序就可能出错。
1.3 常见输出解析器分类
| 解析器 | 最终结果 | 适用场景 | 说明 |
|---|---|---|---|
StrOutputParser | 字符串 str | 只需要展示文本,不需要拆字段 | 最简单,通常就是取出模型输出正文内容 |
JsonOutputParser | Python dict / list | 希望模型返回 JSON,再交给程序继续处理 | 适合字段抽取、接口返回、工作流参数传递 |
PydanticOutputParser | Pydantic 对象 | 需要强类型和运行时校验 | 适合对字段类型、长度、范围有明确要求的业务场景 |
1.4 常见结构化输出方案
除了“输出解析器”以外,LangChain 还提供了更进一步的**结构化输出(Structured Output)**能力。
它的重点不是“事后把结果解析出来”,而是“事前就规定模型应该按什么结构输出”。这里会经常出现一个词:schema。
schema 可以看成“数据结构说明书”或“输出格式规范”。 它描述的是:一份数据应该包含哪些字段、每个字段是什么类型、哪些字段必填,以及有时还会补充字段长度、取值范围、枚举值等约束。
例如,如果规定模型输出一个人物信息:
{
"name": "张三",
"age": 20
}那么这个 schema 想表达的其实就是:
- 必须有
name字段; - 必须有
age字段; name应该是字符串;age应该是整数。
所以,结构化输出的本质,就是先定义 schema,再让模型按这个 schema 输出结果。
官方常见的结构化输出方案有三种:
| 方案 | 定义方式 | 最终结果 | 是否支持运行时校验 | 适用场景 |
|---|---|---|---|---|
TypedDict | Python 标准库 typing.TypedDict | dict | 否 | 只需要固定字段结构,不需要严格校验 |
Pydantic | BaseModel + Field(...) | Pydantic 对象 | 是 | 需要强类型、范围、长度、必填项校验 |
JSON Schema | 标准 JSON Schema 字典 | 通常为 dict | 视具体实现而定 | 需要跨语言、跨系统共享结构协议 |
在 LangChain 中,这些结构通常会和下面这种方式配合使用:
model.with_structured_output(...)也就是说:
TypedDict/Pydantic/JSON Schema是“定义输出结构”的方式;with_structured_output(...)是“让模型按这个结构输出并自动解析”的入口。
1.5 输出解析器与结构化输出的关系
这两个概念很容易混,但可以这样区分:
- 输出解析器:更强调“模型已经输出了,我怎么把它转成程序可用的数据”;
- 结构化输出:更强调“在模型输出之前,我先规定好它应该长什么样”。
你也可以把它们理解成:
- 输出解析器偏后处理;
- 结构化输出偏前约束 + 自动解析。
但它们不是“必须二选一”的关系,也不是“必须同时使用”的关系。
常见情况主要有三种:
第一种:只用输出解析器
适合模型先正常输出,再由程序把结果转成字符串、JSON 或对象。
from langchain_core.output_parsers import JsonOutputParser
parser = JsonOutputParser()
result = model.invoke("请用 JSON 返回:name、age")
data = parser.invoke(result)
print(data)这种方式的特点很直接:先让模型生成结果,再由 parser 负责解析,所以它特别适合传统的 prompt | model | parser 链式调用。
第二种:只用结构化输出
适合模型本身支持 with_structured_output(...),LangChain 直接约束模型输出结构并自动解析。
from typing import TypedDict
class Person(TypedDict):
name: str
age: int
structured_model = model.with_structured_output(Person)
result = structured_model.invoke("请返回一个人物信息")
print(result)这种方式不再需要单独手写 parser,而是由 with_structured_output(...) 统一完成“约束输出 + 自动解析”,更适合现代模型已经支持原生结构化输出的场景。
第三种:结构化输出 + 额外校验 / 处理
在更严格的工程场景中,也可以做结构化输出,再补额外处理逻辑。
structured_model = model.with_structured_output(Person)
result = structured_model.invoke("请返回一个人物信息")
# 这里可以继续做业务校验、入库前清洗、字段转换等处理
print(result)这一类场景不一定非要再接一个 Output Parser,但常常会继续补:业务规则校验;字段清洗;入库前转换;接口返回前二次封装。
所以这里的关键结论是:
- 输出解析器和结构化输出可以独立使用;
- 也可以组合使用;
- 是否同时使用,取决于模型能力和业务要求。
它们的目标是一致的:让模型输出稳定地进入程序系统,而不是只停留在自然语言层面。
1.6 实际使用场景
| 场景 | 如果不做解析,常见问题 | 更合适的做法 |
|---|---|---|
| 聊天问答、文案润色、摘要展示 | 只需要显示文本,结构要求低 | StrOutputParser |
| 从文本里抽取字段,如“问题/答案”“时间/人物/事件” | 文本不稳定,后续逻辑难写 | JsonOutputParser |
| 给前端卡片、表单、列表页返回固定字段 | 字段缺失或字段名漂移会影响渲染 | with_structured_output(TypedDict) |
| 给数据库、审批流、订单系统写入严格数据 | 需要校验类型、范围、长度 | PydanticOutputParser 或 with_structured_output(Pydantic) |
| 与外部系统按统一协议对接 | 需要语言无关、协议明确 | JSON Schema |
2、输出解析器常用方法
2.1 动作一:解析输出
在 LangChain 里,解析器最常见的两种使用方式是:
parser.invoke(...):更偏 LangChain / Runnable 风格,适合和prompt | model | parser链式组合。本章案例大多是这种写法。parser.parse(text):更偏“我已经拿到一段纯文本了,现在只想解析这段文本”。
这两个方法的区别很简单:
- 如果你还在 LangChain 的调用链里,常用
invoke(...); - 如果你手里已经是
result.content这种字符串,常用parse(text)。
说明:很多入门教程会笼统说“
parse(result)用来解析模型结果”。从概念上这样理解没问题,但parse(...)更偏向解析文本字符串,而链式开发中我们常直接使用parser.invoke(result)。
2.2 动作二:给模型“格式说明”
解析器不只是“事后处理”,很多时候还会事前帮你约束模型输出。
最常见的方法就是:
parser.get_format_instructions()它会返回一段格式说明文字,告诉模型:应该输出什么结构;有哪些字段;每个字段是什么类型;是否只能返回 JSON;是否不能加额外解释文字。
这段说明通常会被拼进 Prompt 中,让模型一开始就尽量按可解析格式输出,从而降低解析失败率。
3、常见解析器用法与案例
3.1 StrOutputParser
StrOutputParser 是 LangChain 里最简单的输出解析器。它做的事情非常直接:把模型返回内容取出来,当作字符串使用。它不做结构化解析,也不关心字段、键名、数据类型,只关心“把最终文本拿到手”。
它特别适合这些任务:
- 问答机器人直接展示文本;
- 文章摘要、标题生成、改写润色;
- 翻译、续写、营销文案;
- 只需要把结果显示到前端,不需要拆字段的场景。
一句话来说:如果下游只需要一段文本,而不是结构化字段,就用它。
【案例源码】案例与源码-2-LangChain框架/05_parser/StrOutputParserDemo.py
"""
【案例】StrOutputParser 字符串解析器
对应教程章节:第 6 章 - 输出解析器 → 2、常用输出解析器用法
知识点速览:
一、为什么需要「输出解析器」?
- 大模型返回的通常是 AIMessage 等对象,直接拿到的可能是整块对象,不方便当字符串用。
- 输出解析器的作用:把「模型输出」转成程序里好用的形式(如 str、dict、强类型对象)。
二、StrOutputParser 是什么?
- LangChain 里最简单的解析器:从模型返回中取出 content 字段,转成 纯字符串,不做 JSON 等结构解析。
- 适合:只关心「模型说了什么话」、不需要拆成字段的场景。
三、典型流程:构造 Prompt → model.invoke(prompt) 得到 result → parser.invoke(result) 得到 str。
"""
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from loguru import logger
load_dotenv(encoding="utf-8")
# 构造对话模板(与第 5 章 ChatPromptTemplate 用法一致)
chat_prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个{role},请简短回答我提出的问题"),
("human", "请回答:{question}"),
]
)
# 填充占位符,得到消息列表,供模型使用
prompt = chat_prompt.invoke(
{"role": "AI助手", "question": "什么是LangChain,简洁回答100字以内"}
)
logger.info(prompt)
# 初始化大模型(需配置 API Key 等)
model = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 调用模型:传入 prompt,得到的是 AIMessage 等对象(原始输出)
result = model.invoke(prompt)
logger.info(f"模型原始输出:\n{result}")
# 创建字符串解析器:只做「从 result 里取 content 转成 str」
# 单条 AIMessage 时确实等价于 result.content;用解析器的好处:可链式组合(prompt | model | parser)、
# 流式时统一处理 chunk、多条消息时按约定取最后一条等,且与 JsonOutputParser 等接口一致便于替换。
parser = StrOutputParser()
# 解析:parser.invoke(result) 等价于从 result 中取 content,得到纯字符串
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
logger.info("\n")
logger.info(
f"结果类型: {type(response)}"
) # 输出示例: <class 'langchain_core.messages.base.TextAccessor'>
"""
【输出示例】
2026-02-27 14:32:50.639 | INFO | __main__:<module>:37 - messages=[SystemMessage(content='你是一个AI助手,请简短回答我提出的问题', additional_kwargs={}, response_metadata={}), HumanMessage(content='请回答:什么是LangChain,简洁回答100字以内', additional_kwargs={}, response_metadata={})]
2026-02-27 14:32:54.776 | INFO | __main__:<module>:49 - 模型原始输出:
content='LangChain 是一个开源框架,用于构建基于大语言模型(LLM)的应用程序。它提供模块化组件(如链、代理、记忆、工具等),支持提示工程、数据检索增强(RAG)、多步推理和外部工具调用,简化 LLM 应用的开发与集成。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 67, 'prompt_tokens': 38, 'total_tokens': 105, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-7f8b2cc0-7b6a-98c7-8180-4d8fe4433fd3', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019c9dcc-cdc5-71d3-9b0e-8ca64d9ae28d-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 38, 'output_tokens': 67, 'total_tokens': 105, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
2026-02-27 14:32:54.777 | INFO | __main__:<module>:56 - 解析后的结构化结果:
LangChain 是一个开源框架,用于构建基于大语言模型(LLM)的应用程序。它提供模块化组件(如链、代理、记忆、工具等),支持提示工程、数据检索增强(RAG)、多步推理和外部工具调用,简化 LLM 应用的开发与集成。
2026-02-27 14:32:54.777 | INFO | __main__:<module>:57 -
"""你可能会问:既然 AIMessage.content 也能直接拿文本,为什么还要 StrOutputParser?
原因主要有三点:
- 链式统一:后续可以自然写成
prompt | model | parser。 - 接口一致:今天是字符串,明天想切成 JSON,只要换 parser,不必重写整体结构。
- 可读性更强:代码语义变成“这里是输出解析环节”,对初学者和团队协作都更友好。
3.2 JsonOutputParser
JsonOutputParser(JSON 解析器)可以把模型输出中可解析的 JSON 内容,转换成程序可直接使用的结构化数据。
这里要注意:它不是“任意一段自然语言都能稳定转成 JSON”的魔法。Prompt 仍然需要提前说明输出格式;如果模型输出完全偏离 JSON,解析依然可能失败。
在项目开发里,JSON 是最常见的结构化数据格式。因为它:适合前后端传输;适合接口返回;适合数据库中间层处理;适合继续转成对象或表单数据。
所以很多时候,我们希望模型不要只回答一句话,而是直接返回:
{
"q": "...",
"a": "..."
}或者:
{
"time": "...",
"person": "...",
"event": "..."
}这时就可以使用 JsonOutputParser。
3.2.1 用法一:直接在提示词里手写 JSON 要求
这是最直观的方式:在 Prompt 中明确写出“请返回 JSON,并包含哪些字段”。
【案例源码】案例与源码-2-LangChain框架/05_parser/JsonOutputParserDemo.py
"""
【案例】JsonOutputParser 基础用法:在提示词里直接要求返回 JSON
对应教程章节:第 6 章 - 输出解析器 → 2、常用输出解析器用法
知识点速览:
一、JsonOutputParser 是什么?
- 把模型的自由文本输出解析成结构化 JSON(Python 里就是 dict / list)。
- 模型若返回的是「像 JSON 的文本」,解析器会尝试解析,得到字典后便于后续逻辑、入库或展示。
二、本案例做法:在 system 提示词里手写要求,例如「结果返回 json 格式,q 字段表示问题,a 字段表示答案」。
- 不依赖 get_format_instructions(),适合结构简单、自己说清楚就够用的场景。
- 进阶做法见 JsonOutputParser_GetFormatInstructions.py:用 get_format_instructions() 生成格式说明再拼进提示词。
"""
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from loguru import logger
load_dotenv(encoding="utf-8")
# 在系统消息里直接写明:返回 json,且包含 q(问题)、a(答案)字段
chat_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"你是一个{role},请简短回答我提出的问题,结果返回json格式,q字段表示问题,a字段表示答案。",
),
("human", "请回答:{question}"),
]
)
prompt = chat_prompt.invoke(
{"role": "AI助手", "question": "什么是LangChain,简洁回答100字以内"}
)
logger.info(prompt)
model = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 模型返回的可能是带 JSON 的文本
result = model.invoke(prompt)
logger.info(f"模型原始输出:\n{result}")
print("*" * 60)
# 创建 JSON 解析器(不绑 Pydantic 时,解析结果为 dict/list)
parser = JsonOutputParser()
# 尝试从 result 的 content 中解析出 JSON
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
logger.info("\n")
logger.info(f"结果类型: {type(response)}") # <class 'dict'>
"""
【输出示例】
2026-02-26 12:00:54.190 | INFO | __main__:<module>:29 - messages=[SystemMessage(content='你是一个AI助手,请简短回答我提出的问题,结果返回json格式,q字段表示问题,a字段表示答案。', additional_kwargs={}, response_metadata={}), HumanMessage(content='请回答:什么是LangChain,简洁回答100字以内', additional_kwargs={}, response_metadata={})]
2026-02-26 12:00:56.500 | INFO | __main__:<module>:40 - 模型原始输出:
content='{"q": "什么是LangChain,简洁回答100字以内", "a": "LangChain是一个开源框架,用于构建基于大语言模型(LLM)的应用程序,支持链式调用、数据连接、记忆管理与工具集成,简化提示工程、RAG和Agent开发。"}' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 65, 'prompt_tokens': 54, 'total_tokens': 119, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-f940cf51-c792-904e-9ed9-d2808c5ab264', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019c981b-56ff-73b0-92fd-48ed999ee369-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 54, 'output_tokens': 65, 'total_tokens': 119, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
************************************************************
2026-02-26 12:00:56.501 | INFO | __main__:<module>:48 - 解析后的结构化结果:
{'q': '什么是LangChain,简洁回答100字以内', 'a': 'LangChain是一个开源框架,用于构建基于大语言模型(LLM)的应用程序,支持链式调用、数据连接、记忆管理与工具集成,简化提示工程、RAG和Agent开发。'}
2026-02-26 12:00:56.501 | INFO | __main__:<module>:49 -
"""
# 2026-02-26 12:00:56.501 | INFO | __main__:<module>:50 - 结果类型: <class 'dict'>这个案例适合帮助你理解最基础的工作流:
- Prompt 明确要求输出 JSON;
- 模型返回一段“长得像 JSON 的文本”;
JsonOutputParser把它解析成 Python 里的dict。
这种方式适合:字段很少;结构很简单;自己能一句话把格式说明白;主要目的是快速演示、快速打通流程。
3.2.2 用法二:用 get_format_instructions() 自动生成格式说明
当结构开始复杂时,手写“请返回 JSON,包含 a、b、c 字段……”就容易写漏、写乱、写不严谨。
这时更稳妥的办法是:让解析器自己生成格式说明,再拼进 Prompt。
【案例源码】案例与源码-2-LangChain框架/05_parser/JsonOutputParser_GetFormatInstructions.py
"""
【案例】JsonOutputParser + get_format_instructions():用格式说明引导模型输出
对应教程章节:第 6 章 - 输出解析器 → 2、常用输出解析器用法
知识点速览:
一、get_format_instructions() 做什么?
- 返回一段格式说明字符串,描述「希望模型输出成什么样子」(例如 JSON 里有哪些键、类型是什么)。
- 把这段说明拼进 Prompt(如放在 {format_instructions} 占位符),模型更容易输出可被解析的 JSON,减少格式错误。
二、本案例做法:用 Pydantic 模型 Person 定义「时间、人物、事件」结构 → 用 JsonOutputParser(pydantic_object=Person) 创建解析器 → 用 parser.get_format_instructions() 得到说明 → 把说明拼进 human 消息,再调用模型与解析器。
- 模型会按 Person 的 schema 生成 JSON;当前 JsonOutputParser 解析结果为 dict(若要 Pydantic 实例与完整校验,见 PydanticOutputParser / StructuredOutput_Pydantic.py)。
"""
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from loguru import logger
from pydantic import BaseModel, Field
load_dotenv(encoding="utf-8")
class Person(BaseModel):
"""定义一条「新闻」的结构:时间、人物、事件。用于约束模型输出的 JSON 形状。"""
time: str = Field(description="时间")
person: str = Field(description="人物")
event: str = Field(description="事件")
# 绑定 Pydantic 模型:主要驱动 get_format_instructions() 的 schema;invoke 后得到 dict
parser = JsonOutputParser(pydantic_object=Person)
# 获取「格式说明」:描述 Person 各字段,便于拼进提示词让模型按此输出
format_instructions = parser.get_format_instructions()
# 在 human 消息里加入 {format_instructions},模型会看到「请按如下格式输出 JSON …」
chat_prompt = ChatPromptTemplate.from_messages(
[
("system", "你是一个AI助手,你只能输出结构化JSON数据。"),
("human", "请生成一个关于{topic}的新闻。{format_instructions}"),
]
)
# 填 topic 和 format_instructions,得到消息列表
prompt = chat_prompt.format_messages(
topic="小米su7跑车", format_instructions=format_instructions
)
logger.info(prompt)
model = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
result = model.invoke(prompt)
logger.info(f"模型原始输出:\n{result}")
# 用同一解析器解析,得到符合 Person 结构的数据(dict,或可转成 Person 实例)
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
logger.info(f"结果类型: {type(response)}")
"""
【输出示例】
2026-02-27 15:01:43.675 | INFO | __main__:<module>:47 - [SystemMessage(content='你是一个AI助手,你只能输出结构化JSON数据。', additional_kwargs={}, response_metadata={}), HumanMessage(content='请生成一个关于小米su7跑车的新闻。STRICT OUTPUT FORMAT:\n- Return only the JSON value that conforms to the schema. Do not include any additional text, explanations, headings, or separators.\n- Do not wrap the JSON in Markdown or code fences (no ``` or ```json).\n- Do not prepend or append any text (e.g., do not write "Here is the JSON:").\n- The response must be a single top-level JSON value exactly as required by the schema (object/array/etc.), with no trailing commas or comments.\n\nThe output should be formatted as a JSON instance that conforms to the JSON schema below.\n\nAs an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]} the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.\n\nHere is the output schema (shown in a code block for readability only — do not include any backticks or Markdown in your output):\n```\n{"description": "定义一条「新闻」的结构:时间、人物、事件。用于约束模型输出的 JSON 形状。", "properties": {"time": {"description": "时间", "title": "Time", "type": "string"}, "person": {"description": "人物", "title": "Person", "type": "string"}, "event": {"description": "事件", "title": "Event", "type": "string"}}, "required": ["time", "person", "event"]}\n```', additional_kwargs={}, response_metadata={})]
2026-02-27 15:01:47.540 | INFO | __main__:<module>:57 - 模型原始输出:
content='{"time": "2024年3月28日", "person": "雷军", "event": "小米正式发布首款高性能纯电动轿车SU7,百公里加速2.78秒,续航达800公里,开启预订后24小时订单突破10万辆"}' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 64, 'prompt_tokens': 385, 'total_tokens': 449, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-2ca1b345-6e47-9595-ad8a-37df86762530', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019c9de7-3f73-7081-bd8c-977d405da6ab-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 385, 'output_tokens': 64, 'total_tokens': 449, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
2026-02-27 15:01:47.540 | INFO | __main__:<module>:61 - 解析后的结构化结果:
{'time': '2024年3月28日', 'person': '雷军', 'event': '小米正式发布首款高性能纯电动轿车SU7,百公里加速2.78秒,续航达800公里,开启预订后24小时订单突破10万辆'}
2026-02-27 15:01:47.540 | INFO | __main__:<module>:62 - 结果类型: <class 'dict'>
"""这个案例里,用了一个 Person Pydantic 模型来描述 JSON 结构,再让:
parser.get_format_instructions()自动生成一段规范的格式说明给模型看。
你要抓住的重点是:
JsonOutputParser本质上还是把结果解析成 JSON / dict;- 这里引入 Pydantic 模型,主要是为了更方便地描述输出结构;
- 如果你要的最终结果是 Pydantic 实例 而不是
dict,通常应该看下一节的PydanticOutputParser或with_structured_output(Pydantic模型)。
4、结构化输出
4.1 定义
所谓结构化输出(Structured Output),就是不满足于“模型输出一段 JSON 文本”,而是进一步要求:
- 输出必须符合某个明确 schema;
- LangChain 直接帮你解析成字典或对象;
- 必要时还能做字段验证。
也就是说,普通 JSON 解析更像是:
“请尽量按这个格式说。”
而结构化输出更像是:
“你必须按这个 schema 交付结果。”
LangChain 官方现在特别强调:很多现代模型已经支持原生结构化输出。这意味着,在支持的模型上,优先使用:
model.with_structured_output(...)往往会比传统“手写 Prompt + Parser 解析”的方式更稳、更省心。
但输出解析器并没有过时,它仍然很有价值,尤其是在:使用不支持原生结构化输出的模型时;需要把结果继续做解析 / 清洗时;需要用 Pydantic 追加严格校验时;想把输出解析作为 LCEL 链的一环统一管理时。
4.2 常见方式
LangChain 官方文档里,结构化输出常见有三种 schema 方式:
| 方式 | 返回结果常见形态 | 是否自带运行时校验 | 适合什么场景 |
|---|---|---|---|
| TypedDict | dict | 否 | 结构清晰、字段固定,但校验要求不高 |
| Pydantic | Pydantic 对象 | 是 | 需要强类型、范围校验、长度校验、字段验证 |
| JSON Schema | dict | 取决于具体使用方式 | 需要与外部协议对齐、跨语言协作 |
这里还经常会配合一个写法:Annotated,它不是第四种 schema,而是给字段补充说明信息的一种方式。
5、TypedDict 与 Annotated
5.1 TypedDict:描述“这个字典长什么样”
TypedDict 来自 Python 标准库 typing,它的作用是:描述一个字典应该有哪些键、每个键是什么类型。它更像是一张结构说明书。
对 LangChain 来说,这张说明书很有用,因为它可以据此引导模型输出固定结构,再解析成 Python 字典。
但要特别注意:**TypedDict 不负责真正的运行时校验。**也就是说,它更偏“说明结构”,不是“强制验证”。
5.2 Annotated:给字段加解释说明
Annotated 也是 Python 标准库 typing 里的能力。它的作用不是“换一种类型”,而是:在原有类型上附加一段元数据或说明。
例如:
Annotated[str, "动物名称"]它本质上还是 str,只是附带了一段“这是动物名称”的说明。LangChain 可以利用这些说明生成更清晰的 schema 描述,让模型更容易理解每个字段该填什么。
5.3 案例:TypedDict 版结构化输出
【案例源码】案例与源码-2-LangChain框架/05_parser/StructuredOutput_TypedDict.py
"""
【案例】用 TypedDict + Annotated 做结构化输出
对应教程章节:第 6 章 - 输出解析器 → 3、结构化输出(TypedDict / Pydantic / Annotated)
知识点速览:
一、什么是「结构化输出」?
- 希望模型返回的不是随便一段话,而是固定结构的数据(如指定字段的 dict),方便程序后续处理。
- LangChain 支持用 TypedDict(Python 标准库)或 Pydantic 定义结构,再由模型按该结构生成并解析。
二、with_structured_output 做什么?
- 在模型上调用 llm.with_structured_output(某个类型),会返回一个「带了结构化输出能力」的可调用对象。
- 调用 .invoke(messages) 时,模型会被引导输出符合该结构的 JSON,并自动解析成 Python 的 dict(或对应类型),无需再手写 Parser。
三、本案例:用 typing.TypedDict 定义 Animal(动物名 + emoji)、AnimalList(动物列表);用 Annotated 给字段加描述,便于模型理解各字段含义;最后用 llm.with_structured_output(AnimalList) 一次得到结构化结果。
"""
import os
from typing import TypedDict, Annotated
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
load_dotenv(encoding="utf-8")
llm = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 用 TypedDict 定义「一个动物」的结构;Annotated 里的字符串是给模型看的描述,便于生成合适内容
class Animal(TypedDict):
animal: Annotated[str, "动物"]
emoji: Annotated[str, "表情"]
# 定义「动物列表」:一个字段 animals,类型是 Animal 的列表
class AnimalList(TypedDict):
animals: Annotated[list[Animal], "动物与表情列表"]
# 普通对话消息
messages = [{"role": "user", "content": "任意生成三种动物,以及他们的 emoji 表情"}]
# 给模型绑定「结构化输出」:按 AnimalList 的结构返回并解析
llm_with_structured_output = llm.with_structured_output(AnimalList)
resp = llm_with_structured_output.invoke(messages)
print(
resp
) # 得到符合 AnimalList 的 dict,如 {"animals": [{"animal": "猫", "emoji": "🐱"}, ...]}
"""
【输出示例】
{'animals': [{'animal': '狗', 'emoji': '🐶'}, {'animal': '猫', 'emoji': '🐱'}, {'animal': '鸟', 'emoji': '🐦'}]}
"""这个案例可以作为“现代 LangChain 结构化输出”的第一课:
- 用
TypedDict定义Animal与AnimalList; - 用
Annotated给字段添加说明; - 用
llm.with_structured_output(AnimalList)直接告诉模型输出目标结构; - 调用
.invoke(...)后直接得到解析好的dict。
这比“先要求 JSON,再手动解析”更像真实项目中的推荐写法。
5.4 案例:Annotated 只是描述,不是校验
【案例源码】案例与源码-2-LangChain框架/05_parser/AnnotatedTypedDict.py
"""
【案例】Python 入门:Annotated 与 TypedDict(仅类型提示、无运行时校验)
对应教程章节:第 6 章 - 输出解析器 → 3、结构化输出(TypedDict / Pydantic / Annotated)
知识点速览:
- Annotated[类型, "描述"] 中的描述只是元数据,供文档、类型检查或 LangChain 生成提示用;Python 运行时不会按描述做校验,故 age2=188 不会报错。
- 类型提示在运行时总体是「装饰性」的;若需运行时范围校验,要用 Pydantic 的 Field(见 AnnotatedPydantic.py)。
"""
from typing import Annotated, TypedDict
# Annotated[int, "年龄,范围0-150"]:类型仍是 int,后面的字符串只是元数据,运行时不会做 0–150 的校验
Age = Annotated[int, "年龄,范围0-150"]
class Person(TypedDict):
name: str
age: int
age2: Age # 本质还是 int,元数据 "年龄,范围0-150" 不参与运行时校验
# TypedDict 实例化时不会校验 age2 是否在 0–150,只要类型是 int 即可
p = Person(name="z3", age=111, age2=188)
print(p)
# p = Person(name="z3", age="1111") # 若用字符串赋给 age,部分环境可能报错,取决于具体运行时
"""
【输出示例】
{'name': 'z3', 'age': 111, 'age2': 188}
"""这个案例解决的是一个容易混淆的问题:
Age = Annotated[int, "年龄,范围0-150"]这句话并不意味着 Python 会自动帮你检查“年龄必须在 0 到 150 之间”。它只是说:这个字段的类型是 int;附带一段说明“年龄,范围 0-150”。如果没有额外的校验框架,这段说明不会自动变成校验规则。
所以在 TypedDict 场景下:Annotated 更像提示词增强器;它不是运行时验证器。
5.5 使用场景
TypedDict 适合这些情况:
- 前端页面需要固定字段,但字段值不用做复杂校验;
- 工作流节点之间传递结构化数据;
- 想要结构清晰,但不想引入太重的校验逻辑;
- 模型本身支持较好的结构化输出能力。
一句话总结:TypedDict 适合“我要稳定结构”,但暂时不要求“严格数据合法性校验”。
6、Pydantic:从结构说明到校验
6.1 定义
如果说 TypedDict 主要解决的是“这个字典应该长什么样”,那么 Pydantic 解决的是:“这个数据不仅要长得像,而且必须真的合法。”
Pydantic 是 Python 生态里很常用的数据校验库。它可以在创建对象时对字段做:类型检查;范围检查;长度检查;自定义校验。真实业务里只要涉及结构化数据,就经常会用到它。
6.2 案例:Annotated + Pydantic 触发校验
【案例源码】案例与源码-2-LangChain框架/05_parser/AnnotatedPydantic.py
"""
【案例】Python 入门:Pydantic + Annotated 实现带范围的运行时校验
对应教程章节:第 6 章 - 输出解析器 → 3、结构化输出(TypedDict / Pydantic / Annotated)
知识点速览:
一、和 AnnotatedTypedDict 的区别?
- AnnotatedTypedDict.py:用 typing.Annotated 只加了「描述」元数据,**运行时不会**按「0–150」校验。
- 本文件:用 **Pydantic** 的 Field(ge=0, le=150) 放在 Annotated 里,即 Annotated[int, Field(ge=0, le=150, ...)],Pydantic 会在**运行时**校验数值是否在 0–150,超出则抛 ValidationError。
二、适用场景:需要「强类型 + 取值范围校验」时,用 Pydantic 模型 + Field 约束;LangChain 的结构化输出也可用这类模型做解析与校验。
"""
from typing import Annotated
from pydantic import BaseModel, Field, ValidationError
# 用 Annotated 结合 Pydantic 的 Field:ge=0, le=150 会在运行时校验,不在范围内会触发 ValidationError
Age = Annotated[int, Field(ge=0, le=150, description="年龄,范围0-150")]
class Person(BaseModel):
name: str
age: int
age2: Age # 这里 age2 会被 Pydantic 按 Field(ge=0, le=150) 校验
try:
p = Person(name="z3", age=11, age2=188) # age2=188 超出 0–150,会抛 ValidationError
print(p)
except ValidationError as e:
print("数据校验失败:")
print(e)
"""
【输出示例】
数据校验失败:
1 validation error for Person
age2
Input should be less than or equal to 150 [type=less_than_equal, input_value=188, input_type=int]
For further information visit https://errors.pydantic.dev/2.12/v/less_than_equal
"""这个案例和上一个 AnnotatedTypedDict.py 正好形成对照:
- 在 TypedDict 里,
Annotated[int, "年龄范围0-150"]只是描述; - 在 Pydantic 里,
Annotated[int, Field(ge=0, le=150)]会真正变成运行时校验。
记住一句话就够了:Annotated 本身不校验;真正发生校验的是 Pydantic 的 Field(...) 规则。
6.3 案例:PydanticOutputParser 的完整流程
【案例源码】案例与源码-2-LangChain框架/05_parser/StructuredOutput_Pydantic.py
"""
【案例】PydanticOutputParser:用 Pydantic 模型定义输出结构并校验
对应教程章节:第 6 章 - 输出解析器 → 3、结构化输出(TypedDict / Pydantic / Annotated)
知识点速览:
一、PydanticOutputParser 和 JsonOutputParser 的区别?
- JsonOutputParser:把模型文本解析成「任意」JSON(dict/list),或可绑一个 Pydantic 模型约束形状。
- PydanticOutputParser:**专门**配合 Pydantic 模型,解析结果会转成** Pydantic 实例**,并可利用 Pydantic 的校验(如字段类型、validator),不合格会抛错。
二、本案例流程:用 Pydantic 定义 Product(name、category、description),其中 description 用 field_validator 校验长度 ≥ 10 → 用 PydanticOutputParser(pydantic_object=Product) 创建解析器 → 用 get_format_instructions() 得到格式说明并拼进 Prompt → 模型返回后 parser.invoke(result) 得到 Product 对象。
- 适合:需要强类型、需要在校验失败时明确报错的场景。
"""
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from loguru import logger
from pydantic import BaseModel, Field, field_validator
load_dotenv(encoding="utf-8")
class Product(BaseModel):
"""产品信息:名称、类别、简介。简介长度需 ≥ 10,由下方 validator 校验。"""
name: str = Field(description="产品名称")
category: str = Field(description="产品类别")
description: str = Field(description="产品简介")
@field_validator("description")
def validate_description(cls, value):
"""Pydantic 校验器:description 长度必须 ≥ 10,否则抛 ValueError。"""
if len(value) < 10:
raise ValueError("产品简介长度必须大于等于10")
return value
# 创建 Pydantic 输出解析器:解析结果会转成 Product 实例并做校验
parser = PydanticOutputParser(pydantic_object=Product)
# 生成「格式说明」字符串,拼进 Prompt,引导模型按 Product 的字段输出 JSON
format_instructions = parser.get_format_instructions()
# 在 system 里放入 {format_instructions},human 里放 {topic}
prompt_template = ChatPromptTemplate.from_messages(
[
("system", "你是一个AI助手,你只能输出结构化的json数据\n{format_instructions}"),
("human", "请你输出标题为:{topic}的新闻内容"),
]
)
prompt = prompt_template.format_messages(
topic="华为Mate X7", format_instructions=format_instructions
)
logger.info(prompt)
model = init_chat_model(
model="qwen-plus",
model_provider="openai",
api_key=os.getenv("aliQwen-api"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
result = model.invoke(prompt)
logger.info(f"模型原始输出:\n{result.content}")
# 解析:把 result 转成 Product 实例,若格式或校验不通过会抛错
response = parser.invoke(result)
logger.info(f"解析后的结构化结果:\n{response}")
logger.info(f"结果类型: {type(response)}") # <class 'Product'>
"""
【输出示例】
2026-02-27 15:02:47.018 | INFO | __main__:<module>:53 - [SystemMessage(content='你是一个AI助手,你只能输出结构化的json数据\nThe output should be formatted as a JSON instance that conforms to the JSON schema below.\n\nAs an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}\nthe object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.\n\nHere is the output schema:\n```\n{"description": "产品信息:名称、类别、简介。简介长度需 ≥ 10,由下方 validator 校验。", "properties": {"name": {"description": "产品名称", "title": "Name", "type": "string"}, "category": {"description": "产品类别", "title": "Category", "type": "string"}, "description": {"description": "产品简介", "title": "Description", "type": "string"}}, "required": ["name", "category", "description"]}\n```', additional_kwargs={}, response_metadata={}), HumanMessage(content='请你输出标题为:华为Mate X7的新闻内容', additional_kwargs={}, response_metadata={})]
2026-02-27 15:02:51.175 | INFO | __main__:<module>:63 - 模型原始输出:
{"name": "华为Mate X7", "category": "智能手机", "description": "华为Mate X7是一款全新折叠屏旗舰手机,搭载麒麟9010芯片与HarmonyOS 4.2系统,配备8英寸内屏与6.5英寸外屏,支持5G网络与超高速充电技术。"}
2026-02-27 15:02:51.175 | INFO | __main__:<module>:67 - 解析后的结构化结果:
name='华为Mate X7' category='智能手机' description='华为Mate X7是一款全新折叠屏旗舰手机,搭载麒麟9010芯片与HarmonyOS 4.2系统,配备8英寸内屏与6.5英寸外屏,支持5G网络与超高速充电技术。'
2026-02-27 15:02:51.175 | INFO | __main__:<module>:68 - 结果类型: <class '__main__.Product'>
"""这个案例体现了 Pydantic 路线最完整、最经典的工作流:
- 定义一个
ProductPydantic 模型; - 用
Field(...)给字段加说明; - 用
field_validator(...)写更细的校验逻辑; - 创建
PydanticOutputParser(pydantic_object=Product); - 用
get_format_instructions()生成格式说明; - 把说明拼入 Prompt;
- 模型输出后,解析成 Pydantic 实例。
这个流程比单纯的 JsonOutputParser 更强,因为它不只是“转成字典”,而是“转成一个经过校验的对象”。
6.4 使用场景
当你遇到下面这些需求时,通常就该优先考虑 Pydantic:
- 要把结果写进数据库,不能容忍字段类型乱掉;
- 要把模型输出接到订单、审批、风控、报表等业务系统;
- 某些字段必须满足范围、枚举、长度等限制;
- 希望一旦数据不合法,就立刻抛错,而不是悄悄放过。
一句话总结:
Pydantic 适合“我要的不只是结构化,而是可验证、可托底、可工程化的数据”。
7、JSON Schema:和外部协议对齐时很有用
7.1 定义
JSON Schema 是一种专门用来描述 JSON 结构和约束规则的标准。
它最大的特点是语言无关,前后端都能理解,也因此很适合跨团队、跨系统、跨语言协作。
LangChain 官方也把它列为结构化输出的三种主流方式之一。
7.2 使用场景
如果你的场景是:
- 后端和前端已经约定了一份 JSON 协议;
- 你的 Python 服务要和 Java、Go、Node 等系统对接;
- 想把数据结构标准化、文档化;
- 不想强依赖 Pydantic 或 Python 类型系统;
那么 JSON Schema 就会比 TypedDict 更通用。
7.3 和 TypedDict、Pydantic 的区别
可以简单这样记:
- TypedDict:最像 Python 内部的“结构说明书”。
- Pydantic:最像 Python 内部的“结构 + 校验模型”。
- JSON Schema:最像系统之间共享的“协议文档”。
8、实际开发选择
这一节给出本章的落地选择。
8.1 从简单到严格的选择路径
你可以按下面这条路径做选择:
- 只需要文本展示 用
StrOutputParser - 需要简单 JSON 字段 用
JsonOutputParser - 需要固定结构,且模型支持结构化输出 优先
with_structured_output(TypedDict) - 需要严格校验 用
Pydantic+PydanticOutputParser,或with_structured_output(Pydantic模型) - 需要跨语言 / 外部协议对齐 用
JSON Schema
落到工程选型上,可以记住这句话:普通文本用 Parser,固定结构优先 with_structured_output,强校验上 Pydantic,Agent 最终结果再看 response_format。
8.2 一个更贴近项目落地的选型表
| 需求 | 推荐方案 |
|---|---|
| 聊天机器人回复、文章摘要、翻译 | StrOutputParser |
| 抽取“问题-答案”“时间-人物-事件”等简单字段 | JsonOutputParser |
| 给前端接口返回一个固定字段字典 | with_structured_output(TypedDict) |
| 给数据库、业务系统写入高可靠数据 | with_structured_output(Pydantic) / PydanticOutputParser |
| 与其它语言系统共享统一数据协议 | JSON Schema |
| 输出格式很特殊,内置解析器覆盖不了 | 自定义 BaseOutputParser |
8.3 官方建议
LangChain 官方当前的整体方向是:
- 如果模型原生支持结构化输出,优先用原生能力;
- 如果模型不支持,或你还需要额外解析/校验,再使用输出解析器。
8.4 自定义解析器
大多数场景不需要自己写解析器。优先级一般是:先看 with_structured_output(...),再看内置 Parser,最后才考虑自定义。
但有些输出确实比较特殊,例如模型返回的是一段固定格式的清单、日志、命令块,既不是标准 JSON,也不适合上 Pydantic。这时可以继承 BaseOutputParser,只实现最关键的 parse() 方法。
from langchain_core.output_parsers import BaseOutputParser
class LineListParser(BaseOutputParser[list[str]]):
def parse(self, text: str) -> list[str]:
return [
line.strip("- ").strip()
for line in text.splitlines()
if line.strip()
]它适合做“很轻的格式清洗”。如果结果后面要进数据库、审批流、自动执行工具,仍然建议继续接 Pydantic 或业务校验,不要只靠字符串拆分。
9、常见误区与排错建议
9.1 误区一:能解析成 JSON,就说明数据没问题
不对。JSON 只说明“格式像样”,不说明“业务正确”。
比如用户年龄输出成了 999,它依然是合法 JSON,但显然不合理。
9.2 误区二:Annotated 自带校验
不对。Annotated 只是附加元数据。
真正让“范围、长度、约束”生效的是 Pydantic 的 Field(...)、validator 等机制。
9.3 误区三:输出解析器能完全代替 Prompt 设计
不对。如果 Prompt 没说清楚字段含义、输出边界、不要加额外说明,解析器很可能仍然失败。
9.4 误区四:所有项目都应该直接上 Pydantic
也不一定。如果你只是做文本展示,或者只是一个简单 JSON 演示,直接上 Pydantic 可能过重。
工程化不是“越复杂越好”,而是“够用且稳定”。
9.5 误区五:学了 Parser 就和结构化输出是两套体系
不是。它们本质上解决的是同一个问题:让模型输出可被程序稳定消费。
区别只是在于:
- 有的方式偏“后处理解析”;
- 有的方式偏“原生结构约束 + 自动解析”;
- 有的方式还能进一步做严格校验。
章节思考题:
为什么“模型输出了 JSON”不等于“程序可以放心使用”?
参考思路: JSON 语法正确只是第一步,字段是否齐全、类型是否正确、值是否符合业务规则还需要校验。解析解决“能读”,校验解决“能不能信”。
什么时候
StrOutputParser就够了,什么时候应该上 Pydantic?参考思路: 只需要纯文本展示时,字符串解析足够;结果要进入数据库、接口、流程分支或自动执行时,应考虑 Pydantic 这类强校验。越靠近业务动作,越不能只靠自然语言。
Structured Output 和 Output Parser 的关系应该怎么理解?
参考思路: Structured Output 更偏让模型按结构生成,Parser 更偏在输出后解析和转换。两者可以配合使用:前面约束生成,后面兜底解析和校验。
TypedDict、Pydantic、JSON Schema 的选择取决于什么?
参考思路: TypedDict 适合轻量类型说明,Pydantic 适合 Python 内部强校验和错误提示,JSON Schema 适合跨语言、接口协议或外部系统对齐。不是越重越好,要看边界在哪里。
本章小结:
- 输出解析器是 Model I/O 里的 Parse 环节,负责把模型输出转成程序可直接使用的数据。
- 本章的重点不在于背 API,而在于建立工程认知:大模型输出往往还要继续进入程序链路,因此必须结构化。
- StrOutputParser 适合纯文本场景;JsonOutputParser 适合快速得到
dict;PydanticOutputParser 适合强类型、强校验场景。 - 结构化输出是本章真正的重点。LangChain 官方常见的三种 schema 方式是:TypedDict、Pydantic、JSON Schema。
- TypedDict 适合描述结构;Pydantic 适合描述结构并做运行时校验;Annotated 主要用于补充字段说明,本身不是校验器。
- 现代 LangChain 更推荐在支持的模型上优先考虑
with_structured_output(...),输出解析器则继续在兼容性、后处理、附加校验等方面发挥作用。 - 从掌握结果看,学完本章后,你至少应该:能分清 输出解析器 和 结构化输出 的关系,知道它们都在解决“模型结果如何稳定交给程序”这个问题;知道
StrOutputParser、JsonOutputParser、PydanticOutputParser三类方案各自适用什么场景;理解TypedDict、Annotated、Pydantic、JSON Schema在“描述结构”和“运行时校验”上的边界。
建议下一步: 学习 第 7 章 LCEL 与链式调用,把本章的解析器与 第 5 章 的 Prompt、第 3 章 的 Model 串成真正的 prompt | model | parser 链。