
输出解析器(Output parsers)
概念
**负责获取模型的输出,并将输出转换为更结构化的格式。**当使用 LLM 生成结构化数据或规范化聊天模型和 LLM 的输出时,这很有用。
大型语言模型(LLM)的输出本质上是非结构化的文本 。但在构建应用程序时,我们通常希望得到结构化的、机器可读的数据,这样可以将其转换为更适合下游任务的格式,比如:
- JSON 对象
- Python 字典或列表
- 一个特定的
Pydantic模型实例 - 一个简单的布尔值或字符串枚举
输出解析器的作用就是架起这座桥梁: 它们将 LLM 的非结构化文本输出转换为结构化格式。这使得与 LLM 的交互从 "模糊的文本对话" 变成了 "精确的数据 API 调用",是构建可靠、高效 LLM 应用不可或缺的组件。
和 with_structured_output()的区别
他们都实现了相同的功能,但
-
维度不同 :输出解析器是 LangChain 中的一个功能性组件,with_structured_output() 是聊天模型的一个方法。
-
用法不同 :输出解析器的工作流程可以是链式的,可以将 Prompt、LLM 和 Parser 像管道一样连接起来:chain = prompt | llm | parser。而 with_structured_output(schema) 却不行,只能手动调用,返回一个新的、具备了结构化输出能力的 Runnable(可运行对象)
可以根据自己的使用场景选择,如果想使用链式就选择输出解析器。
解析文本输出
其实对于使用 StrOutputParser 输出解析器输出文本,我们已经使用过多次了。对于 StrOutputParser,它也实现了标准的 Runnable 接口。示例如下:
python
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
model = ChatOpenAI(model="gpt-4o-mini")
chain = model | StrOutputParser()
for chunk in chain.stream("写一首夏天的诗词,50字以内。"):
print(chunk, end="|")
输出如下:
python
|炎|夏|骄|阳|照|,|绿|树|映|蓝|天|。|
|蝉|鸣|声|声|烈|,|荷|塘|映|清|鲜|。|
|微|风|拂|面|过|,|凉|意|透|心|间|。|
|烦|忧|随|汗|去|,|畅|享|此|夏|欢|。||
若是不使用输出解析器,而是直接得到聊天模型返回的 AIMessage,文本内容则需要从消息中的 content 字段获取。
解析结构化对象输出
要输出结构化对象,需要用到的输出解析器是 PydanticOutputParser。
class langchain_core.output_parsers.pydantic.PydanticOutputParser 类,其参数如下:
pydantic_object:要解析的 pydantic 模型。
内置方法:
invoke():将单个输入转换为输出。
get_format_instructions() -> str:重要!!
- 作用:生成一个指令字符串,这个字符串会被添加到发送给 LLM 的提示(Prompt)的末尾。
- 目的:告诉 LLM 应该以什么样的格式返回它的响应。例如,"请将你的回复封装在 XML 标签中" 或 "请以 JSON 格式输出,包含 name 和 age 两个字段"。
代码示例如下:
python
# 导入OpenAI聊天模型对接库,用于调用GPT-4o-mini等大模型
from langchain_openai import ChatOpenAI
# 导入Pydantic输出解析器:用于把LLM返回的文本,自动解析成结构化对象
from langchain_core.output_parsers import PydanticOutputParser
# 导入提示词模板:用于构建固定格式的提问模板
from langchain_core.prompts import PromptTemplate
# 导入可选类型:用于定义可以为None的字段
from typing import Optional
# 导入Pydantic基类与字段校验工具:用于定义结构化输出格式
from pydantic import BaseModel, Field
# ===================== 1. 初始化大模型 =====================
# 创建大模型实例,指定使用 gpt-4o-mini 模型
model = ChatOpenAI(model="gpt-4o-mini")
# ===================== 2. 定义输出数据结构 =====================
# 继承 BaseModel,定义一个结构化输出类,告诉LLM要输出什么格式
class Joke(BaseModel):
"""给用户讲一个笑话。""" # 类注释:给模型看的功能说明
# 笑话开头(问题/铺垫)
# Field:给字段加描述,帮助LLM理解每个字段含义
setup: str = Field(description="这个笑话的开头")
# 笑话包袱(笑点/反转)
punchline: str = Field(description="这个笑话的妙语")
# 笑话评分(可选,可为空)
# Optional[int]:表示这个字段可以是 int 或 None
# default=None:默认值为空
rating: Optional[int] = Field(
default=None, description="从1到10分,给这个笑话评分"
)
# ===================== 3. 创建输出解析器 =====================
# 创建解析器,绑定上面定义的 Joke 结构
# 作用:让LLM输出符合这个结构的内容,并自动解析成对象
parser = PydanticOutputParser(pydantic_object=Joke)
# ===================== 4. 构建提示词模板 =====================
# 定义提示词模板,固定格式
prompt = PromptTemplate(
# 模板内容:
# 1. 告诉模型回答用户问题
# 2. 插入 format_instructions(格式要求)
# 3. 插入用户真正的 query(问题)
template="Answer the user query.\n{format_instructions}\n{query}\n",
# 声明模板中需要动态传入的变量:这里只有用户问题 query
input_variables=["query"],
# partial_variables:预先传入固定不变的变量,不用每次调用都传
# parser.get_format_instructions() 自动生成格式说明文本,告诉LLM怎么输出
partial_variables={"format_instructions": parser.get_format_instructions()},
)
# ===================== 5. 构建链式调用 =====================
# LangChain 链式语法:
# 提示词 → 大模型生成回答 → 解析成结构化对象
chain = prompt | model | parser
# ===================== 6. 流式调用并输出 =====================
# stream:流式输出,一边生成一边返回,不用等全部完成
for chunk in chain.stream({"query": "给我讲一个关于唱歌的笑话"}):
# chunk 就是解析后的 Joke 对象,流式逐块输出
print(chunk, end="|")
结果如下:
python
setup='为什么歌手总是带着铅笔去演出?' punchline='' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要不断' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要不断调整' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要不断调整音' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要不断调整音调' rating=None|
setup='为什么歌手总是带着铅笔去演出?' punchline='因为他们想要不断调整音调!' rating=None
解析 JSON 输出
要输出 JSON 格式,需要用到的输出解析器是 JsonOutputParser。
class langchain_core.output_parsers.json.JsonOutputParser 类,其参数如下:
pydantic_object:用于验证的 Pydantic 对象。如果为空,则不执行任何验证。
内置方法:
invoke():将单个输入转换为输出。
get_format_instructions() -> str:重要!!
- 作用:生成一个指令字符串,这个字符串会被添加到发送给 LLM 的提示(Prompt)的末尾。
- 目的:告诉 LLM 应该以什么样的格式返回它的响应。例如,"请将你的回复封装在 XML 标签中" 或 "请以 JSON 格式输出,包含 name 和 age 两个字段"。
代码示例如下,这将提示模型返回 JSON:
python
# 导入 LangChain 对接 OpenAI 大模型的类,用于创建聊天模型实例
from langchain_openai import ChatOpenAI
# 导入 Json 输出解析器:
# 作用 → 把大模型返回的字符串自动转成 Python 字典(JSON 对象)
from langchain_core.output_parsers import JsonOutputParser
# 导入提示词模板:用于拼接固定格式的提示词
from langchain_core.prompts import PromptTemplate
# ===================== 1. 初始化大模型 =====================
# 创建大模型对象,指定使用 gpt-4o-mini 模型
model = ChatOpenAI(model="gpt-4o-mini")
# ===================== 2. 创建 JSON 解析器 =====================
# 创建一个通用的 JSON 解析器
# 它不需要定义 Pydantic 类,直接让模型返回 JSON 格式字符串,然后自动转字典
parser = JsonOutputParser()
# ===================== 3. 构建提示词模板 =====================
prompt = PromptTemplate(
# 模板内容:
# 1. 告诉模型:回答用户问题
# 2. 插入 {format_instructions}:告诉模型必须按 JSON 格式输出
# 3. 插入 {query}:用户真正的问题
template="Answer the user query.\n{format_instructions}\n{query}\n",
# 声明需要动态传入的变量:只有用户问题 query
input_variables=["query"],
# partial_variables:预先传入固定不变的变量
# parser.get_format_instructions() 会自动生成一段文字,告诉模型:
# "请返回 JSON 格式,不要多余内容"
partial_variables={"format_instructions": parser.get_format_instructions()},
)
# ===================== 4. 构建执行链 =====================
# LangChain 链式调用语法:
# 提示词 → 大模型生成内容 → JSON 解析器解析成字典
chain = prompt | model | parser
# ===================== 5. 执行并输出结果 =====================
# invoke:一次性调用,等待模型全部生成完成后返回结果
# 传入用户问题:给我讲一个关于唱歌的笑话
result = chain.invoke({"query": "给我讲一个关于唱歌的笑话"})
# 打印最终结果(已经是 Python 字典格式)
print(result)
结果如下:
python
{'joke': '为什么歌手总是带着梯子?\n因为他们想要在音乐会上达到更高的层次!'}
也可以使用带 Pydantic 情况下的 JsonOutputParser,如下所示:
python
# 导入OpenAI聊天模型,用于调用GPT系列大模型
from langchain_openai import ChatOpenAI
# 导入JSON输出解析器:可以根据Pydantic模型,约束大模型输出标准JSON并自动转为字典
from langchain_core.output_parsers import JsonOutputParser
# 导入提示词模板,用来统一构造固定格式的用户提示
from langchain_core.prompts import PromptTemplate
# 导入Optional:标识字段可以为整型,也可以为None空值
from typing import Optional
# 导入Pydantic基类BaseModel和字段描述工具Field
from pydantic import BaseModel, Field
# 1. 初始化大模型实例
# 指定使用 gpt-4o-mini 模型
model = ChatOpenAI(model="gpt-4o-mini")
# 2. 用Pydantic定义结构化输出模型
# 继承BaseModel,强制约束大模型返回的数据结构、字段含义、类型
class Joke(BaseModel):
"""给用户讲一个笑话。""" # 类注释会一并传给大模型,作为功能说明
# 笑话铺垫/开头,字符串类型,附带字段描述给大模型参考
setup: str = Field(description="这个笑话的开头")
# 笑话笑点/包袱,字符串类型
punchline: str = Field(description="这个笑话的妙语")
# 笑话评分:可为整数或为空,默认值None
rating: Optional[int] = Field(
default=None,
description="从1到10分,给这个笑话评分"
)
# 3. 创建JSON解析器,并绑定自定义Pydantic结构
# 作用:
# 1. 自动生成格式要求提示词,告诉大模型必须按Joke结构输出JSON
# 2. 把大模型返回的JSON字符串,自动解析为Python字典
parser = JsonOutputParser(pydantic_object=Joke)
# 4. 构造提示词模板
prompt = PromptTemplate(
# 模板句式:
# 先要求回答用户问题,再插入自动生成的JSON格式要求,最后接入用户提问
template="Answer the user query.\n{format_instructions}\n{query}\n",
# 声明模板里需要动态传入的变量名
input_variables=["query"],
# 预填充固定变量:把解析器生成的格式说明提前注入模板
partial_variables={"format_instructions": parser.get_format_instructions()},
)
# 5. 构建LangChain链式流水线
# 流程:提示词构造 → 大模型生成 → JSON结构化解析
chain = prompt | model | parser
# 6. 同步调用链,传入用户问题,打印解析后的结构化字典结果
print(chain.invoke({"query": "给我讲一个关于唱歌的笑话"}))
结果如下:
python
{'setup': '为什么歌手从不在森林里唱歌?', 'punchline': '因为他们会被树木的'静'止住!', 'rating': None}
除了上面讲的文本、对象、JSON 解析器,其实 LangChain 官方还提供了更多类型的解析器,如:
- XML 解析器:
XMLOutputParser - Yaml 解析器:
YamlOutputParser - CSV 解析器:
CommaSeparatedListOutputParser - 枚举解析器:
EnumOutputParser - 日期解析器:
DatetimeOutputParser等等,更多类型参考这里。
除此之外,LangChain 还支持我们自定义输出解析器,以将模型输出结构化为自定义格式,详细情况参考这里。