LangChain入门和应用#5 | 豆包MarsCode AI刷题

192 阅读8分钟

输出解析

LangChain提供的解析模型输出的功能,使你能够更容易地从模型输出中获取结构化的信息,这将大大加快基于语言模型进行应用开发的效率。

概述

大型语言模型 (LLM) 正在成为为信息提取应用程序提供动力的极其强大的技术。

经典的信息提取解决方案依赖于人员、(大量)手工制作的规则(例如正则表达式)和自定义微调的 ML 模型的组合。

这些系统随着时间的推移往往会变得复杂,维护成本越来越高,并且越来越难以增强。

LLM 可以通过为其提供适当的指令和适当的参考示例,快速适应特定的提取任务。

方法

使用 LLM 进行信息提取有 3 种主要方法

  • 工具/函数调用模式:某些 LLM 支持工具或函数调用模式。这些 LLM 可以根据给定的模式结构化输出。通常,这种方法最易于使用,预计会产生良好的结果。
  • JSON 模式:某些 LLM 可以被强制输出有效的 JSON。这类似于工具/函数调用方法,只是模式作为提示的一部分提供。通常,我们的直觉是,这比工具/函数调用方法表现更差,但不要相信我们,请验证您自己的用例!
  • 基于提示:可以很好地遵循指令的 LLM 可以被指示以所需格式生成文本。生成的文本可以使用现有的 输出解析器 或使用 自定义解析器 下游解析为结构化格式,例如 JSON。这种方法可用于不支持 JSON 模式或工具/函数调用模式的 LLM。这种方法适用范围更广,但可能比经过微调用于提取或函数调用的模型产生更差的结果。

输出解析器是帮助构建语言模型响应的类。输出解析器必须实现两种主要方法

  • "获取格式说明":一种方法,返回一个包含关于语言模型输出应如何格式化的说明的字符串。
  • "解析":一种方法,接收一个字符串(假定为来自语言模型的响应)并将其解析为某种结构。

还有一个可选的方法

  • "使用提示解析":一种方法,接收一个字符串(假定为来自语言模型的响应)和一个提示(假定为生成此响应的提示)并将其解析为某种结构。提示主要是在输出解析器想要重试或以某种方式修复输出时提供的,并且需要来自提示的信息才能做到这一点。

下面我将在代码中介绍这个基本的用法

# 导入结构化输出解析器和ResponseSchema
import os
​
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
​
# 从 langchain_core 中导入 PromptTemplate,用于创建自定义的提示模板
from langchain_core.prompts import PromptTemplate
​
# 导入智谱AI的模型接口
from langchain_community.chat_models import ChatZhipuAI
​
def set_api_key():
    os.environ["ZHIPUAI_API_KEY"] = "Your Key"
    """Set the ZhipuAI API key from environment variable or prompt the user."""
    if not os.getenv("ZHIPUAI_API_KEY"):
        os.environ["ZHIPUAI_API_KEY"] = input("Enter your ZhipuAI API key: ")
​
​
# 设置API Key
set_api_key()
# 初始化智谱AI模型
chat = ChatZhipuAI(model="glm-4", temperature=0.5)
# 创建原始提示模板prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
{format_instructions}"""
# 定义我们想要接收的响应模式
response_schemas = [
    ResponseSchema(name="description", description="鲜花的描述文案"),
    ResponseSchema(name="reason", description="问什么要这样写这个文案")
]
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
​
# 获取格式指示
format_instructions = output_parser.get_format_instructions()
# 根据原始模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(prompt_template,
                                      partial_variables={"format_instructions": format_instructions})
# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]
​
for flower, price in zip(flowers, prices):
    # 根据提示准备模型的输入
    putin = prompt.format(flower_name=flower, price=price)
​
    # 获取模型的输出
    output = chat.invoke(putin)
​
    # 解析模型的输出(这是一个字典结构)
    output.model_dump()
    parsed_output = output_parser.parse(output.content)
​
    # 在解析后的输出中添加“flower”和“price”
    parsed_output['flower'] = flower
    parsed_output['price'] = price
    print(parsed_output)

下面我们逐步看这段代码

# 初始化智谱AI模型
chat = ChatZhipuAI(model="glm-4", temperature=0.5)
  • 初始化智谱AI模型:使用 ChatZhipuAI 创建一个名为 chat 的模型实例。指定 model="glm-4" 表示使用 glm-4 模型,temperature=0.5 控制生成的文本的创造性程度。temperature=0.5 表示输出会有适度的多样性,而不是完全确定性。
# 创建原始提示模板
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
{format_instructions}"""
  • 创建原始提示模板:定义一个多行字符串 prompt_template 作为提示模板。模板中使用了占位符 {price}{flower_name},它们将根据实际输入替换成相应的鲜花价格和名称。此外,{format_instructions} 也会在稍后被替换为输出格式的说明。
# 定义我们想要接收的响应模式
response_schemas = [
    ResponseSchema(name="description", description="鲜花的描述文案"),
    ResponseSchema(name="reason", description="问什么要这样写这个文案")
]
  • 定义响应模式:定义 response_schemas 列表,包含两个 ResponseSchema 对象。ResponseSchema 用来描述模型输出的结构。第一个 ResponseSchema 用于描述鲜花的文案(description),第二个用于描述为什么要这样写文案(reason)。这些响应将用于输出解析时的格式化。
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
  • 创建输出解析器:通过 StructuredOutputParser.from_response_schemas 方法创建一个解析器 output_parser,该解析器根据 response_schemas 中定义的响应模式来解析模型的输出。解析器负责将模型返回的原始文本转换为结构化的输出格式(例如字典形式)。
# 获取格式指示
format_instructions = output_parser.get_format_instructions()
  • 获取格式指示:调用 output_parser.get_format_instructions() 方法获取模型输出的格式化指令。格式指令告诉模型如何将输出组织成结构化的数据格式,这样 output_parser 可以正确解析。
# 根据原始模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(prompt_template,
                                      partial_variables={"format_instructions": format_instructions})
  • 根据原始模板创建提示:使用 PromptTemplate.from_template 方法根据之前定义的 prompt_template 创建一个 PromptTemplate 实例。在这里,partial_variables 被用来替换模板中的 {format_instructions} 占位符,填入获取的格式指示。最终 prompt 将包含完整的提示模板,可以直接传递给模型。
# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]
  • 数据准备:定义两个列表 flowersprices,分别存储不同类型的鲜花和它们对应的价格。稍后将通过这些数据创建输入,以请求模型生成相应的文案。
for flower, price in zip(flowers, prices):
  • 遍历鲜花和价格:使用 zip(flowers, prices) 将两个列表打包成一个迭代器,并同时遍历 flowerspricesflower 变量代表当前鲜花的名称,price 变量代表对应的价格。
# 根据提示准备模型的输入
putin = prompt.format(flower_name=flower, price=price)
  • 准备模型输入:根据遍历到的 flowerprice,使用 prompt.format 方法将模板中的占位符 {flower_name}{price} 替换成实际值,生成模型的输入字符串 putin。该字符串即为模型的输入提示。
# 获取模型的输出
output = chat.invoke(putin)
  • 获取模型的输出:调用 chat.invoke(putin),将生成的输入字符串 putin 传递给智谱AI模型,得到模型的输出(通常为生成的文本或其他数据格式)。
# 解析模型的输出(这是一个字典结构)
output.model_dump()
  • 解析模型输出:调用 output.model_dump(),可能是用来打印或者获取 output 对象的详细内容,以便进一步处理。这里假设它会输出模型的原始响应,通常是一个包含生成文本的字典。
parsed_output = output_parser.parse(output.content)
  • 解析模型的输出内容:通过 output_parser.parse(output.content) 将模型的原始输出(output.content)解析为结构化的数据格式(如字典)。output_parser 根据之前定义的 response_schemas 模式来组织输出数据。
# 在解析后的输出中添加“flower”和“price”
parsed_output['flower'] = flower
parsed_output['price'] = price
  • 在解析后的输出中添加额外信息:将当前鲜花的名称 flower 和价格 price 添加到解析后的输出 parsed_output 中。这确保了每个输出字典包含了生成文案的鲜花信息和价格信息,便于后续处理或显示。
print(parsed_output)
  • 打印解析后的输出:将解析后的字典 parsed_output 打印出来。输出包含生成的文案、理由以及鲜花名称和价格等信息。每次迭代都会打印当前鲜花和价格的处理结果。

预期结果

image.png 现在,你应该能够对模型的响应进行基本的解析了,这在构建ai问答库时十分方便,我们可以将结构化的数据方便的存放到数据库里

下一节,我将介绍提示工程,你会明白在提示模板的构建过程中加入了partial_variables,也就是输出解析器指定的format_instructions之后,为什么能够让模型生成结构化的输出?