LangChain实战05-输出解析|豆包MarsCode AI刷题

186 阅读6分钟

一.解析器

1.解析器的方法

输出解析器是一种专用于处理和构建语言模型响应的类。一个基本的输出解析器类通常需要实现两个核心方法。

  • get_format_instructions:这个方法需要返回一个字符串,用于指导如何格式化语言模型的输出,告诉它应该如何组织并构建它的回答。
  • parse:这个方法接收一个字符串(也就是语言模型的输出)并将其解析为特定的数据结构或格式。这一步通常用于确保模型的输出符合我们的预期,并且能够以我们需要的形式进行后续处理。

还有一个可选的方法。

  • parse_with_prompt:这个方法接收一个字符串(也就是语言模型的输出)和一个提示(用于生成这个输出的提示),并将其解析为特定的数据结构。这样,你可以根据原始提示来修正或重新解析模型的输出,确保输出的信息更加准确和贴合要求。

2.解析器的类别

列表解析器(List Parser)
日期时间解析器(Datetime Parser)
枚举解析器(Enum Parser)
结构化输出解析器(Structured Output ParserPydanticJSON)解析器:这个解析器用于处理模型的输出,当模型的输出应该是一个符合特定格式的JSON对象时使用。它使用Pydantic库,这是一个数据验证库,可以用于构建复杂的数据模型,并确保模型的输出符合预期的数据模型。
自动修复解析器(Auto-Fixing Parser):这个解析器可以自动修复某些常见的模型输出错误。例如,如果模型的输出应该是一段文本,但是模型返回了一段包含语法或拼写错误的文本,自动修复解析器可以自动纠正这些错误。
重试解析器(RetryWithErrorOutputParser):这个解析器用于在模型的初次输出不符合预期时,尝试修复或重新生成新的输出。例如,如果模型的输出应该是一个日期,但是模型返回了一个字符串,那么重试解析器可以重新提示模型生成正确的日期格式。

本文就重点谈谈Pydantic(JSON)解析器、自动修复解析器和重试解析器

二.Pydantic(JSON)解析器实战

1.构造模型

import os

from langchain import OpenAI
model = OpenAI(model_name='gpt-3.5-turbo-instruct')

这部分代码我们选择text-davinci-003作为大语言模型。

2.定义输出数据格式

# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["flower_type", "price", "description", "reason"])

# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]

# 定义我们想要接收的数据格式
from pydantic import BaseModel, Field
class FlowerDescription(BaseModel):
    flower_type: str = Field(description="鲜花的种类")
    price: int = Field(description="鲜花的价格")
    description: str = Field(description="鲜花的描述文案")
    reason: str = Field(description="为什么要这样写这个文案")

首先这里引用了pandas库,为最后的输出结果做一个存储容器。然后通过一个名为FlowerDescriptionPydantic BaseModel类,定义了期望的数据格式,也就是输出结果的格式,其中包括鲜花种类,价格,描述以及理由。

在这里我们用到了负责数据格式验证的Pydantic库来创建带有类型注解的类FlowerDescription,它可以自动验证输入数据,确保输入数据符合指定的类型和其他验证条件。

3.创建输出解析器

# 创建输出解析器
from langchain.output_parsers import PydanticOutputParser
output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)

# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
# 打印提示
print("输出格式:",format_instructions)

先使用LangChain库中的PydanticOutputParser创建了输出解析器,传入的参数指定为FlowerDescription,这样解析器就能基于它的格式进行输出。然后使用解析器的get_format_instructions方法获取了输出格式的指示。

我们来看看输出的结果:

屏幕截图 2024-11-21 220809.png 这部分是通过output_parser.get_format_instructions()方法生成的,这是Pydantic (JSON) 解析器的核心价值。同时它也算得上是一个很清晰的提示模板,能够为模型提供良好的指导,描述了模型输出应该符合的格式。(其中description中的中文被转成了UTF-8编码。)

它指示模型输出JSON Schema的形式,定义了一个有效的输出应该包含哪些字段,以及这些字段的数据类型。例如,它指定了 "flower_type" 字段应该是字符串类型,"price" 字段应该是整数类型。这个指示中还提供了一个例子,说明了什么是一个格式良好的输出。

注释在理解这部分代码时,我碰到了一个疑惑的点:这里的代码已经给出了我们想要接受的数据格式,那为什么还要在解析器中获取输出格式提示,这两步有什么区别呢?下面是豆包给我的答案。

  • 定义数据格式FlowerDescription侧重于从程序处理数据的角度规定数据的结构,是为了方便后续的数据存储、传递和处理,让程序能够理解数据的类型和组成部分。
  • 获取输出格式提示format_instructions侧重于指导数据的生成过程,使得生成的数据能够符合预先定义的数据格式,主要是为了沟通(如人机交互或者程序之间传递生成要求)而提供的一种格式化的说明。

4.创建提示模板

# 创建提示模板
from langchain import PromptTemplate
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短中文描述吗?
{format_instructions}"""

# 根据模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(
    prompt_template, 
    partial_variables={"format_instructions": format_instructions}
) 

# 打印提示
print("提示:", prompt)

这段代码就是创建一个提示模板,这个提示模板是一个用于生成模型输入的工具,我们在模板中定义了输入变量prompt_template,以及模板字符串的格式和结构format_instructions,然后使用这个模板来为每种鲜花生成一个描述。

5.解析输出

for flower, price in zip(flowers, prices):
    # 根据提示准备模型的输入
    input = prompt.format(flower=flower, price=price)
    # 打印提示
    print("提示:", input)

    # 获取模型的输出
    output = model(input)

    # 解析模型的输出
    parsed_output = output_parser.parse(output)
    parsed_output_dict = parsed_output.dict()  # 将Pydantic格式转换为字典

    # 将解析后的输出添加到DataFrame中
    df.loc[len(df)] = parsed_output.dict()

# 打印字典
print("输出的数据:", df.to_dict(orient='records'))

这部分是程序的主体,我们循环来处理所有的花和它们的价格。对于每种花,都根据提示模板创建了输入,然后获取模型的输出。然后使用之前创建的解析器来解析这个输出,并将解析后的输出添加到DataFrame中。最后打印出了所有的结果。我们来看下运行结果:

屏幕截图 2024-11-21 230110.png

我们看到Pydantic的优点就是容易解析,而解析之后的字典格式的列表在进行数据分析、处理和存储时非常方便。每个字典代表一条记录,它的键即 "flower_type""price""description" 和 "reason"是字段名称,对应的值是这个字段的内容。这样一来,每个字段都对应一列,每个字典就是一行,适合以DataFrame的形式来表示和处理。

以上就是学习输出解析的内容了。