掘金 人工智能 前天 12:56
LangChain框架入门05:输出解析器使用技巧
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

在AI应用开发中,大语言模型输出格式常不标准化,LangChain的输出解析器组件解决了这一痛点。它能将模型原始输出转化为结构化数据,支持JSON、XML等多种格式,并提供数据校验和错误处理。文章详细介绍了StrOutputParser、JsonOutputParser、PydanticOutputParser等常用解析器用法,以及如何自定义解析器和利用OutputFixingParser、RetryOutputParser进行错误修复与重试。掌握输出解析器能显著提升开发效率和数据处理的准确性。

✨ **输出解析器的核心作用**:LangChain的输出解析器作为模型与最终数据输出的中间层,旨在将大语言模型输出的原始文本内容解析为结构化的数据格式,如JSON、XML、YAML等。这不仅能实现指定格式输出,还能进行数据校验,确保输出内容符合预期,并在解析失败时提供错误处理和重试机制,从而解决大模型输出格式不标准的问题。

📚 **常用输出解析器类型与用法**:文章介绍了多种内置输出解析器,包括`StrOutputParser`用于简单文本提取,`JsonOutputParser`用于解析JSON格式并生成格式提示词,以及`PydanticOutputParser`用于处理具有强类型约束的复杂结构化数据,它结合Pydantic模型提供了类型验证和数据转换。此外,`ListOutputParser`和`DatetimeOutputParser`等也分别用于处理列表和日期时间数据。

🛠️ **自定义解析器与错误处理机制**:当内置解析器无法满足需求时,可以创建自定义输出解析器,如示例中的`BookTitleParser`,通过重写`get_format_instructions`和`parse`方法来处理特定格式。LangChain还提供了`OutputFixingParser`和`RetryOutputParser`两种错误处理机制,前者通过调用大模型修复错误输出,后者在解析失败时将原始提示词与输出重传给模型以重新生成,两者都能提高输出的鲁棒性,但会增加额外的模型调用成本。

LangChain框架入门05:输出解析器使用技巧

在实际的AI应用开发中,可能经常遇到这样的问题:很多时候大语言模型输出格式不够标准化,有时候返回的是纯文本,有时候是JSON格式,甚至还可能包含一些不需要的冗余信息,如:

Human:帮我生成一个商品信息的json字符串,格式是:{"name": "苹果", "price": "1000"}AI:好的,已经为你生成:{"name": "橘子", "price": "500"}

但实际上,我们期望的是只返回一个JSON字符串,AI却返回了一些多余的文字,为了解决这个问题,LangChain提供了输出解析器(Output Parsers)组件,可以帮助我们将模型的原始输出转换为结构化的、易于处理的数据格式,这一步不仅仅涉及数据类型的转换,也包括对返回数据的处理。

文中所有示例代码:github.com/wzycoding/l…

学习完输出解析器,LangChain框架中最核心的组件就已经讲解完毕,整个与大语言模型交互的流程非常的清晰完整,流程图如下:

一、什么是输出解析器

输出解析器是LangChain框架中的重要组件,它的作用是将大语言模型的原始输出内容解析为如JSON、XML、YAML等结构化数据。在LangChain中,输出解析器位于模型和最终数据输出之间,作为数据处理的中间层。通过输出解析器,可以实现如下目的:

二、输出解析器类型

LangChain提供了多种输出解析器,以下是常见的输出解析器及使用场景:

解析器类型适用场景输出格式
StrOutputParser简单文本输出字符串
JsonOutputParserJSON格式数据字典/列表
PydanticOutputParser复杂结构化数据Pydantic模型对象
ListOutputParser列表数据Python列表
DatetimeOutputParser时间日期数据datetime对象
BooleanOutputParser布尔值输出True/False

输出解析器核心方法:

parse:将大模型输出的内容,格式化成指定的格式返回。

format_instructions:它会返回一段清晰的格式说明字符串,告诉 LLM 希望输出成什么格式(比如 JSON,或者特定格式)。

三、常用输出解析器用法

3.1 StrOutputParser用法

StrOutputParser 是LangChain中最简单的输出解析器,它直接从AIMessage的content中提取纯文本内容。在前面的章节中,其实已经使用过它,代码示例如下,在示例中使用了链式调用,在后续的文章中会详细讲解。

import dotenvfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIfrom langchain_core.output_parsers import StrOutputParser# 读取env配置dotenv.load_dotenv()# 1.构建提示词prompt = ChatPromptTemplate.from_messages([    ("system", "你是一个资深文学家"),    ("human", "请简短赏析{name}这首诗,并给出评价")])# 2.创建模型llm = ChatOpenAI()# 3.创建字符串输出解析器parser = StrOutputParser()# 4.构建链式调用chain = prompt | llm | parser# 5.执行链式调用result = chain.invoke({"name": "静夜思"})print(f"输出类型: {type(result)}")print(f"输出内容: {result}")

执行结果:

输出类型: <class 'str'>输出内容: 《静夜思》是唐代诗人李白创作的一首脍炙人口的诗。这首诗以简练的语言,表达了诗人夜晚孤寂时对故乡的思念之情。全诗四句:**床前明月光,疑是地上霜。****举头望明月,低头思故乡。**从诗的内容看,李白通过月光照在床前的景象,唤起了对故乡的无限思念。第一句“床前明月光”描绘了清冷、静谧的夜景,紧接着“疑是地上霜”巧妙地将月光与霜相比较,增加了诗的意境层次。接下来的“举头望明月”是对月亮的凝视,而“低头思故乡”则自然流露出诗人内心的乡愁。月亮作为传统的象征,承载了思乡之情,情感真挚而直接。评价:此诗语言简练、意境深远,既表现了李白的孤独感,也反映了他心中对故乡的深深依恋。其凝练的情感、清新的画面和强烈的乡愁,成就了这首诗的永恒魅力。

3.2 JsonOutputParser用法

当我们需要模型输出JSON格式数据时,可以使用 JsonOutputParser。这个解析器不仅能解析JSON格式,还能为模型提供输出指定格式的提示词,使用示例如下,这里要注意的是案例中使用的模型是gpt-4o,因为经过多次测试,使用gpt-3.5-turbo输出结果会产生幻觉,幻觉可能表现为格式错误或字段遗漏。

import dotenvfrom langchain_core.output_parsers import JsonOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.pydantic_v1 import BaseModel, Fieldfrom langchain_openai import ChatOpenAI# 读取env配置dotenv.load_dotenv()# 1.定义输出的对象结构class Poetry(BaseModel):    name: str = Field(description="古诗名字")    content: str = Field(description="古诗内容")    author: str = Field(description="古诗作者")# 1.构建提示词prompt = ChatPromptTemplate.from_messages([    ("system", "你是一个资深文学家"),    ("human", "请你输出题目为:{name}这首诗的内容\n{format_instructions}")])# 2.构建llmllm = ChatOpenAI(model="gpt-4o")# 3.构建输出解析器parser = JsonOutputParser(pydantic_object=Poetry)# 4.构建链式调用chain = prompt | llm | parser# 5.执行链式调用result = chain.invoke({"name": "登鹳雀楼", "format_instructions": parser.get_format_instructions()})print(f"输出类型: {type(result)}")print(f"输出内容: {result}")

执行结果:

输出类型: <class 'dict'>输出内容: {'name': '登鹳雀楼', 'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}

3.3 PydanticOutputParser用法

对于结构更复杂、具有强类型约束的需求,PydanticOutputParser 则是最佳选择。它结合了Pydantic模型的强大功能,提供了类型验证、数据转换等高级功能,使用示例如下:

import dotenvfrom langchain_core.output_parsers import PydanticOutputParserfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.pydantic_v1 import BaseModel, Field, validatorfrom langchain_openai import ChatOpenAI# 读取env配置dotenv.load_dotenv()# 诗人信息模型class Poetry(BaseModel):    name: str = Field(description="古诗名字")    content: str = Field(description="古诗内容")    author: str = Field(description="古诗作者")# 诗歌信息模型class Poet(BaseModel):    name: str = Field(description="诗人姓名")    age: int = Field(description="诗人年龄")    sex: int = Field(description="性别,0女,1男")    poetries: list[Poetry] = Field(description="诗歌信息列表")    # 数据验证器    @validator('poetries')    def validate_priority(cls, value):        if len(value) < 1 :            raise ValueError('诗歌列表必须大于等于1')        return value    @validator('age')    def validate_hours(cls, value):        if value <= 0:            raise ValueError('年龄必须大于0')        return value# 1.构建提示词prompt = ChatPromptTemplate.from_messages([    ("system", "你是一个管理中国古代诗人信息的专家"),    ("human", "请你介绍一下{name}这位诗人的情况\n{format_instructions}")])# 2.构建llmllm = ChatOpenAI(model="gpt-4o")# 3.构建输出解析器parser = PydanticOutputParser(pydantic_object=Poet)# 4.构建链式调用chain = prompt | llm | parser# 5.执行链式调用result = chain.invoke({"name": "李白", "format_instructions": parser.get_format_instructions()})print(f"输出类型: {type(result)}")print(f"输出内容: {result}")

执行结果:

输出类型: <class '__main__.Poet'>输出内容: name='李白' age=61 sex=1 poetries=[Poetry(name='静夜思', content='床前明月光,疑是地上霜。举头望明月,低头思故乡。', author='李白'), Poetry(name='将进酒', content='君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。', author='李白'), Poetry(name='望庐山瀑布', content='日照香炉生紫烟,遥看瀑布挂前川。飞流直下三千尺,疑是银河落九天。', author='李白')]

四、自定义输出解析器

在某些情况下,LangChain提供的内置的解析器无法满足业务的要求,这时我们可以创建自定义的输出解析器,如下示例,在代码中创建了一个书名号自定义输出解析器,在 get_format_instructions 方法中,提供输出格式的提示词,并在parse方法中通过正则提取书名号包裹的内容,最终返回一个列表。

import dotenvfrom langchain_core.output_parsers.base import BaseOutputParserfrom langchain_core.exceptions import OutputParserExceptionimport refrom langchain_core.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAI# 读取env配置dotenv.load_dotenv()class BookTitleParser(BaseOutputParser):    """自定义书名号内容解析器,用于提取《书名》格式的文本内容"""    def get_format_instructions(self) -> str:        return "请在回答中包含一个或多个被中文书名号《》包裹的内容,例如:《三体》《活着》"    def parse(self, text: str) -> list:        # 使用正则提取被《》包裹的内容        pattern = r'《(.*?)》'        titles = re.findall(pattern, text)        if not titles:            raise OutputParserException(f"未找到任何《书名号》格式的内容: {text}")        return titles# 1.构建提示词prompt = ChatPromptTemplate.from_messages([    ("system", "你是一个资深文学家"),    ("human", "请你推荐5本关于{subject}的好书\n{format_instructions}")])# 2.构建llmllm = ChatOpenAI(model="gpt-3.5-turbo")# 3.构建输出解析器parser = BookTitleParser()# 4.构建链式调用chain = prompt | llm | parser# 5.执行链式调用result = chain.invoke({"subject": "Python编程", "format_instructions": parser.get_format_instructions()})print(f"输出类型: {type(result)}")print(f"输出内容: {result}")

执行结果:

输出类型: <class 'list'>输出内容: ['Python编程:从入门到实践', '流畅的Python', 'Python核心编程', 'Python数据科学手册', 'Python编程快速上手——让繁琐工作自动化']

五、错误修复与重试机制

LangChain 提供两种常见的错误处理机制:

首先是错误修复机制,使用示例如下,将大模型输出的结果传递给fixing_parser,调用parse()方法时,在方法内,首先尝试调用 PydanticOutputParserparse() 方法;若抛出异常,才会触发 OutputFixingParser 的修复逻辑,需要注意的是这里多了一次大模型调用的成本。

import dotenvfrom langchain_openai import ChatOpenAIfrom langchain.output_parsers import OutputFixingParser, RetryOutputParserfrom langchain_core.output_parsers import JsonOutputParserfrom langchain_core.pydantic_v1 import BaseModel, Field# 读取env配置dotenv.load_dotenv()# 定义输出的对象结构class Poetry(BaseModel):    name: str = Field(description="古诗名字")    content: str = Field(description="古诗内容")    author: str = Field(description="古诗作者")llm4o = ChatOpenAI(model="gpt-4o")# 1.构建输出解析器base_parser = JsonOutputParser(pydantic_object=Poetry)fixing_parser = OutputFixingParser.from_llm(parser=base_parser, llm=llm4o)# 2.模拟错误的输出error_str = "{'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}"# 3.对比修复前后结果print(f"修复前的内容:{error_str}")print(f"修复后的内容:{fixing_parser.parse(error_str)}")

执行结果:

修复前的内容:{'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}修复后的内容:{'name': '登鹳雀楼', 'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}

除了错误修复机制,LangChain还提供了重试机制,使用示例如下,将大模型输出结果传递给retry_parser,内部会调用PydanticOutputParserparse()方法,与 OutputFixingParser 不同,RetryOutputParser 会在解析失败时,将原始提示词与输出一并传回模型,尝试重新生成符合格式的内容,如果parse_with_prompt没有报错,不会去触发重试的,同样重试也会多调用一次大模型。

import dotenvfrom langchain_openai import ChatOpenAIfrom langchain.output_parsers import RetryOutputParserfrom langchain_core.output_parsers import JsonOutputParserfrom langchain_core.pydantic_v1 import BaseModel, Fieldfrom langchain_core.prompts import ChatPromptTemplate# 读取env配置dotenv.load_dotenv()# 定义输出的对象结构class Poetry(BaseModel):    name: str = Field(description="古诗名字")    content: str = Field(description="古诗内容")    author: str = Field(description="古诗作者")# 1.定义提示模板prompt = ChatPromptTemplate.from_messages([    ("system", "你是一个资深文学家"),    ("human", "请你输出题目为:{name}这首诗的内容\n{format_instructions}")])llm4o = ChatOpenAI(model="gpt-4o")# 2.构建输出解析器base_parser = JsonOutputParser(pydantic_object=Poetry)retry_parser = RetryOutputParser.from_llm(parser=base_parser, llm=llm4o)# 3.生成prompt_valueprompt_value = prompt.invoke({"name": "登鹳雀楼", "format_instructions": base_parser.get_format_instructions()})# 4.模拟错误的输出error_str = "{'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}"# 5.对比重试前后结果print(f"重试前的内容:{error_str}")print(f"重试后的内容:{retry_parser.parse_with_prompt(error_str, prompt_value)}")

执行结果:

重试前的内容:{'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}重试后的内容:{'name': '登鹳雀楼', 'content': '白日依山尽,黄河入海流。欲穷千里目,更上一层楼。', 'author': '王之涣'}

六、总结

输出解析器是LangChain框架中不可或缺的组件,它解决了大语言模型输出格式不规范的问题。通过本文的介绍,我们学习了基础解析器的使用从简单的StrOutputParser到复杂的PydanticOutputParser

我们还了解了结构化数据处理,通过JsonOutputParserPydanticOutputParser,可以将模型输出转换为结构化的Python对象、JSON对象,便于后续处理。当LangChain提供的内置解析器无法满足需求时,可以创建自定义解析器来处理特殊格式的数据。

在实际项目中,选择合适的输出解析器能够大大提升开发效率和数据处理的准确性。建议根据具体的业务需求,选择最适合的解析器类型,并结合错误处理机制确保系统的稳定性。

下一篇文章我们将继续深入LangChain的其他核心组件,探索更多实用的开发技巧,敬请期待。

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

LangChain 输出解析器 大语言模型 数据处理 AI应用开发
相关文章