LangChain【6】之输出解析器:结构化LLM响应的关键工具

文章目录

  • 一 LangChain输出解析器概述
    • 1.1 什么是输出解析器?
    • 1.2 主要功能与工作原理
    • 1.3 常用解析器类型
  • 二 主要输出解析器类型
    • 2.1 Pydantic/Json输出解析器
    • 2.2 结构化输出解析器
    • 2.3 列表解析器
    • 2.4 日期解析器
    • 2.5 Json输出解析器
    • 2.6 xml输出解析器
  • 三 高级使用技巧
    • 3.1 自定义解析逻辑
    • 3.2 重试与错误处理
    • 3.3 多模式解析
  • 四 实际应用示例
    • 4.1 构建问答系统
    • 4.2 性能优化建议
  • 五 总结

一 LangChain输出解析器概述

  • LangChain输出解析器是LangChain框架中的核心组件,主要用于将大型语言模型(LLM)生成的非结构化文本转换为结构化数据格式。它允许开发者定义期望的输出结构,并通过提示工程指导LLM生成符合该格式的响应。输出解析器在验证和转换模型输出时发挥着关键作用,确保数据能够无缝集成到应用程序的工作流程中。

1.1 什么是输出解析器?

输出解析器是LangChain框架中的一类组件,专门负责两大功能:

  1. 指令格式化:指导LLM如何格式化其输出
  2. 结果解析:将LLM的文本响应转换为结构化格式
    与直接使用原始API调用相比,输出解析器提供了更可靠、更可预测的结果处理方式,极大简化了后续的数据处理流程。

1.2 主要功能与工作原理

  • 输出解析器通过两个核心机制实现功能:首先通过get_format_instructions方法生成格式化指令,明确告知LLM输出应遵循的结构;然后通过parse方法将LLM的原始响应解析为目标数据结构。这种双重机制既保证了输出的规范性,又提供了灵活的数据转换能力。典型的应用场景包括将文本转换为JSON对象、列表、枚举值或特定领域对象等结构化数据。

1.3 常用解析器类型

  • LangChain提供了丰富的内置解析器,包括ListParser(列表解析器)、DatetimeParser(日期时间解析器)、EnumParser(枚举解析器)和PydanticOutputParser(JSON解析器)等。其中PydanticOutputParser特别强大,它基于Pydantic模型定义数据结构,可以处理嵌套复杂的JSON格式,并自动生成对应的格式指令。此外还有StructuredOutputParser用于处理自定义类结构,Auto-FixingParser可自动修复格式错误。

二 主要输出解析器类型

LangChain提供了多种输出解析器,适用于不同场景:

2.1 Pydantic/Json输出解析器

    • Pydantic/Json解析器允许您定义严格的输出模式,确保LLM响应符合预期的数据结构,非常适合需要强类型验证的场景。
from langchain.output_parsers import PydanticOutputParser
from pydantic import Field, BaseModelclass UserProfile(BaseModel):name: str = Field(description="用户全名")age: int = Field(description="用户年龄")hobbies: list[str] = Field(description="用户爱好列表")parser = PydanticOutputParser(pydantic_object=UserProfile)
  • 完整案例:
import os
from langchain_core.output_parsers import PydanticOutputParser
# from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel# 配置 API 易环境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 定义期望的数据结构
class Joke(BaseModel):setup:str =Field(description="设置笑话的问题")punchline:str =Field(description="解决笑话的答案")# 用于提示语言模型填充数据结构的查询意图
joke_query="告诉我一个笑话"
# 设置解析器+将指令注入提示模板
# parser=JsonOutputParser(pydantic_object=Joke)
parser=PydanticOutputParser(pydantic_object=Joke)
prompt=PromptTemplate(template="回答用户的查询。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
  • 输出结果:
"""
The output should be formatted as a JSON instance that conforms to the JSON schema below.As 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.Here is the output schema:
{"properties": {"setup": {"description": "设置笑话的问题", "title": "Setup", "type": "string"}, "punchline": {"description": "解决笑话的答案", "title": "Punchline", "type": "string"}}, "required": ["setup", "punchline"]}
"""
chain=prompt|model|parser
response=chain.invoke({"query":joke_query})
print(response)
"""
{'setup': '为什么计算机不能得感冒?', 'punchline': '因为它们有防火墙!'}
"""

2.2 结构化输出解析器

  • 当需要灵活定义输出结构而不想引入Pydantic依赖时,结构化输出解析器是理想选择。
from langchain.output_parsers import StructuredOutputParser, ResponseSchemaresponse_schemas = [ResponseSchema(name="answer", description="问题的答案"),ResponseSchema(name="source", description="答案来源")
]parser = StructuredOutputParser.from_response_schemas(response_schemas)
  • 完整代码
import os
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI# 配置 API 易环境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)response_schemas = [ResponseSchema(name="answer", description="问题的答案"),ResponseSchema(name="source", description="答案来源")
]# 设置解析器+将指令注入提示模板
parser = StructuredOutputParser.from_response_schemas(response_schemas)prompt=PromptTemplate(template="回答用户的查询。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
"""
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":{"answer": string  // 问题的答案"source": string  // 答案来源
}"""
chain=prompt|model|parser
# 用于提示语言模型填充数据结构的查询意图
joke_query="告诉我一个笑话"
response=chain.invoke({"query":joke_query})print(response)
"""
{'answer': '为什么数学书总是很忧伤?因为它有太多的问题!', 'source': '常见幽默笑话'}
"""

2.3 列表解析器

  • 简单高效地将逗号分隔的列表响应转换为Python列表,适用于简单的枚举场景。
from langchain.output_parsers import CommaSeparatedListOutputParserparser = CommaSeparatedListOutputParser()

2.4 日期解析器

  • 专门处理日期时间字符串,将其转换为Python datetime对象,省去了手动解析的麻烦。
from langchain.output_parsers import DatetimeOutputParserparser = DatetimeOutputParser()

2.5 Json输出解析器

  • JSON作为现代API和Web应用中最常用的数据交换格式,LangChain提供了专门的JSON输出解析器来简化处理流程。

import osfrom langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel# 配置 API 易环境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 定义期望的数据结构
class Joke(BaseModel):setup:str =Field(description="设置笑话的问题")punchline:str =Field(description="解决笑话的答案")# 用于提示语言模型填充数据结构的查询意图
joke_query="告诉我一个笑话"
# 设置解析器+将指令注入提示模板
parser=JsonOutputParser(pydantic_object=Joke)
prompt=PromptTemplate(template="回答用户的查询。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
"""
The output should be formatted as a JSON instance that conforms to the JSON schema below.As 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.Here is the output schema:{"properties": {"setup": {"description": "设置笑话的问题", "title": "Setup", "type": "string"}, "punchline": {"description": "解决笑话的答案", "title": "Punchline", "type": "string"}}, "required": ["setup", "punchline"]}"""
chain=prompt|model|parser
response=chain.invoke({"query":joke_query})
for s in chain.stream({"query":joke_query}):print(s)"""
{}
{'setup': ''}
{'setup': '为'}
{'setup': '为什'}
{'setup': '为什么'}
{'setup': '为什么电'}
{'setup': '为什么电脑'}
{'setup': '为什么电脑很'}
{'setup': '为什么电脑很好'}
{'setup': '为什么电脑很好吃'}
{'setup': '为什么电脑很好吃?'}
{'setup': '为什么电脑很好吃?', 'punchline': ''}
{'setup': '为什么电脑很好吃?', 'punchline': '因'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字节'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字节('}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字节(bytes'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字节(bytes)'}
{'setup': '为什么电脑很好吃?', 'punchline': '因为它们有很多字节(bytes)!'}
"""

2.6 xml输出解析器

  • LangChain的XML输出解析器为这些场景提供了专业支持。

import osfrom langchain_core.output_parsers import  XMLOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI# 配置 API 易环境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 用于提示语言模型填充数据结构的查询意图
actor_query="生成周星驰的简化电影作品列表,按照最新的时间降序"# 设置解析器+将指令注入提示模板
parser=XMLOutputParser(tags=["movies","actor","film","name","genre"])
prompt=PromptTemplate(template="回答用户的查询。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
  • 执行输出:
"""
The output should be formatted as a XML file.
1. Output should conform to the tags below.
2. If tags are not given, make them on your own.
3. Remember to always open and close all the tags.As an example, for the tags ["foo", "bar", "baz"]:
1. String "<foo><bar><baz></baz></bar>
</foo>" is a well-formatted instance of the schema.
2. String "<foo><bar></foo>" is a badly-formatted instance.
3. String "<foo><tag></tag>
</foo>" is a badly-formatted instance.Here are the output tags:['movies', 'actor', 'film', 'name', 'genre']
"""
chain=prompt|model
response=chain.invoke({"query":actor_query})
xml_output=parser.parse(response.content)
print(response.content)
"""
```xml
<movies><actor><name>周星驰</name><film><name>美人鱼</name><genre>喜剧</genre><year>2016</year></film><film><name>西游降魔篇</name><genre>喜剧</genre><year>2013</year></film><film><name>长江七号</name><genre>科幻</genre><year>2008</year></film><film><name>功夫</name><genre>动作</genre><year>2004</year></film><film><name>少林足球</name><genre>喜剧</genre><year>2001</year></film></actor>
</movies>这是一个简化的电影作品列表,列出了周星驰的一些电影,包括电影名称、类型和年份。这个列表是按照最新的时间降序排列的。
"""

三 高级使用技巧

3.1 自定义解析逻辑

  • 通过继承BaseOutputParser,可以创建完全自定义的解析逻辑,处理特殊响应格式。
from langchain.output_parsers import BaseOutputParserclass BooleanParser(BaseOutputParser[bool]):def parse(self, text: str) -> bool:cleaned = text.strip().lower()if cleaned in ("yes", "true", "1"):return Trueelif cleaned in ("no", "false", "0"):return Falseraise ValueError(f"无法解析为布尔值: {text}")@propertydef _type(self) -> str:return "boolean_parser"

3.2 重试与错误处理

  • 当初始解析失败时,重试解析器会自动尝试修正错误,显著提高系统鲁棒性。
from langchain.output_parsers import RetryWithErrorOutputParserretry_parser = RetryWithErrorOutputParser.from_llm(parser=parser,llm=chat_llm
)

3.3 多模式解析

  • 输出修正解析器可以检测并尝试自动修复格式错误的响应,特别适合生产环境中提高可靠性。
from langchain.output_parsers import OutputFixingParserfixing_parser = OutputFixingParser.from_llm(parser=parser, llm=chat_llm)

四 实际应用示例

4.1 构建问答系统

import osfrom langchain_core.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field# 配置 API 环境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"template = """根据上下文回答问题,并按照要求格式化输出。
上下文: {context}
问题: {question}
{format_instructions}"""prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI(model="gpt-4")# 定义输出数据结构
class Answer(BaseModel):answer: str = Field(description="根据上下文回答问题")confidence: float = Field(description="回答的置信度")# 创建解析器
parser = JsonOutputParser(pydantic_model=Answer)chain = prompt | model | parserresult = chain.invoke({"context": "LangChain是一个LLM应用开发框架...","question": "LangChain是什么?","format_instructions": parser.get_format_instructions()
})print(result)

4.2 性能优化建议

  1. 清晰的指令:在提示中明确说明输出格式要求。
  2. 渐进式解析:复杂结构可分步解析。
  3. 错误回退:实现备用解析策略。
  4. 缓存机制:对相同输入缓存解析结果。
  5. 监控指标:跟踪解析成功率,及时发现模式问题。

五 总结

  • LangChain的输出解析器组件为LLM应用开发提供了关键的结构化数据处理能力。通过合理选择和使用各种解析器,开发者可以:
    • 确保数据的一致性和可靠性
    • 减少胶水代码和手动解析工作
    • 构建更健壮的生产级应用
    • 专注于业务逻辑而非数据清洗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot项目中JSON解析库的深度解析与应用实践

在现代Web开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;作为轻量级的数据交换格式&#xff0c;已成为前后端通信的核心桥梁。Spring Boot作为Java生态中最流行的微服务框架&#xff0c;提供了对多种JSON库的无缝集成支持。本文将深入探讨Spring B…

OPenCV CUDA模块光流------高效地执行光流估计的类BroxOpticalFlow

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::BroxOpticalFlow 是 OpenCV CUDA 模块中实现Brox光流算法的类。该类用于在 GPU 上高效地计算两帧图像之间的稠密光流&#xff08;Dens…

视觉分析在人员行为属性检测中的应用

基于视觉分析的人员行为属性检测方案 一、背景与需求分析 在工业生产、建筑施工、公共安全等领域&#xff0c;人员行为属性的合规性检测是保障安全生产的关键环节。例如&#xff0c;工地工人未佩戴安全帽、厨房人员未佩戴手套、作业现场人员使用手机等行为&#xff0c;均可能…

Linux--进程的程序替换

问题导入&#xff1a; 前面我们知道了&#xff0c;fork之后&#xff0c;子进程会继承父进程的代码和“数据”&#xff08;写实拷贝&#xff09;。 那么如果我们需要子进程完全去完成一个自己的程序怎么办呢&#xff1f; 进程的程序替换来完成这个功能&#xff01; 1.替换原理…

场景题-3

如何实现一个消息队列 拆解分析主流的几种消息队列 1、基本架构 生产者Producer、消费者Consumer、Broker&#xff1a;生产者发送消息&#xff0c;消费者接受消息&#xff0c;Broker是服务端&#xff0c;处理消息的存储、备份、删除和消费关系的维护。 主题和分区&#xff…

vue2 项目中 npm run dev 运行98% after emitting CopyPlugin 卡死

今天在运行项目时&#xff0c;发现如下问题&#xff1a; 开始以为是node_modules依赖的问题&#xff0c;于是重新 npm install&#xff0c;重启项目后还是未解决。 在网上找了一圈发现有人说是 require引入图片地址没有写。在我的项目中排查没有这个问题&#xff0c;最后发现某…

73 LV的使用(XFS文件系统)

四 LV的使用 先创建一个LV01 lvcreate -L 10G lv01 datavg Logical volume "lv01" created. 将创建出来的LV01进行格式化 mkfs.xxx LV的名称(绝对路径) 绝对路径的组成:/dev/你创建VG的名字/LV的名字 mkfs.xfs /dev/datavg/lv01 挂载你的LV…

mybatis中判断等于字符串的条件怎么写

mybatis中判断等于字符串的条件怎么写_mybatis 等于字符串-CSDN博客 因为mybatis映射文件&#xff0c;是使用的ognl表达式&#xff0c;ognl是java语言&#xff08;强类型语言&#xff09;&#xff0c;会把‘X’解析成字符&#xff0c;而不是字符串。 所以比较字符串相等使用是…

C语言实现绝对值差值函数

在C语言中&#xff0c;可以编写一个函数来计算两个数的差值的绝对值。以下是一个简单的实现&#xff1a; #include <stdio.h> #include <stdlib.h> // 用于abs函数&#xff08;如果需要&#xff09; // 方法1&#xff1a;使用标准库函数 int absoluteDifference1…

Three.js中AR实现详解并详细介绍基于图像标记模式AR生成的详细步骤

文档地址 Three.js中AR实现详解 以下是Three.js中实现AR功能的详细解析&#xff0c;涵盖技术原理、实现步骤、核心组件及优化策略&#xff1a; &#x1f9e9; 一、技术基础 AR.js框架的核心作用 AR.js是Three.js实现AR的基石&#xff0c;提供以下核心能力&#xff1a; 多模…

Vue3.5 企业级管理系统实战(二十三):权限指令

在实际应用场景中&#xff0c;常常需要依据用户角色对按钮的操作权限实施控制。实现这一控制主要有两种方式&#xff1a;一种是借助前端指令基于角色进行权限管控&#xff0c;另一种是通过后台返回对应的权限属性来实现精细化控制。本文聚焦于前端权限指令展开探讨。 1 权限指…

软考 系统架构设计师系列知识点之杂项集萃(81)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;80&#xff09; 第145题 商业智能是企业对商业数据的搜集、管理和分析的系统过程&#xff0c;主要技术包括&#xff08;&#xff09;。 A. 数据仓库、联机分析和数据挖掘 B. 数据采集、数据清洗…

深入浅出Java ParallelStream:高效并行利器还是隐藏的陷阱?

在Java 8带来的众多革新中&#xff0c;Stream API彻底改变了我们对集合操作的方式。而其中最引人注目的特性之一便是parallelStream——它承诺只需简单调用一个方法&#xff0c;就能让数据处理任务自动并行化&#xff0c;充分利用多核CPU的优势。但在美好承诺的背后&#xff0c…

SQL Transactions(事务)、隔离机制

目录 Why Transactions? Example: Bad Interaction Transactions ACID Transactions COMMIT ROLLBACK How the Transaction Log Works How Data Is Stored Example: Interacting Processes Interleaving of Statements Example: Strange Interleaving Fixing the…

第R9周:阿尔茨海默病诊断(优化特征选择版)

文章目录 1. 导入数据2. 数据处理2.1 患病占比2.2 相关性分析2.3 年龄与患病探究 3. 特征选择4. 构建数据集4.1 数据集划分与标准化4.2 构建加载 5. 构建模型6. 模型训练6.1 构建训练函数6.2 构建测试函数6.3 设置超参数 7. 模型训练8. 模型评估8.1 结果图 8.2 混淆矩阵9. 总结…

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…

【大模型】大模型数据训练格式

1. SFT&#xff08;有监督微调&#xff09; 1.1 数据格式 JSONL&#xff08;每行一个 JSON 对象&#xff09;最为流行&#xff1b;也可用 CSV&#xff0f;TSV&#xff0c;但 JSONL 更灵活。字段设计 prompt&#xff1a;用户输入或任务指令&#xff08;通常以“系统指令&#…

[论文阅读] 人工智能 | 利用负信号蒸馏:用REDI框架提升LLM推理能力

【论文速读】利用负信号蒸馏&#xff1a;用REDI框架提升LLM推理能力 论文信息 arXiv:2505.24850 cs.LG cs.AI cs.CL Harnessing Negative Signals: Reinforcement Distillation from Teacher Data for LLM Reasoning Authors: Shuyao Xu, Cheng Peng, Jiangxuan Long, Weidi…

Cursor 1.0正式推出:全面解析你的AI 编程助手

目录 前言 一、BugBot&#xff1a;你的私人代码审查专家 二、Background Agent&#xff1a;7x24小时在线的云端开发伙伴 三、Jupyter Notebook 深度集成&#xff1a;数据科学家的福音 四、记忆功能 (Memories)&#xff1a;让 AI 更懂你的项目 五、MCP 与工具生态&#xf…

QILSTE 精巧电子元件H4-108FO/5M解析

型号&#xff1a;H4-108FO/5M 在电子元件的浩瀚宇宙中&#xff0c;H4-108FO/5M 仿佛一颗散发着独特光芒的恒星&#xff0c;其参数和特性交织成一张错综复杂的网络&#xff0c;既令人困惑又充满惊喜。这款型号的产品&#xff0c;以其 1.60.80.4mm 的微小尺寸&#xff0c;却蕴含…