课程介绍
- 启程篇:从 0 到 1
- 内容:LangChain的安装流程和快速入门操作
- 实践:构建基于“易速鲜花”本地知识库的智能问答系统
- 目标:直观感受LangChain的强大功能
- 基础篇:深入 6 大组件
- 模型(Models) :各大语言模型的接口、调用细节以及输出解析机制
- 提示模板(Prompts) :提示工程流线化,进一步激发大语言模型的潜力
- 数据检索(Indexes) :建立和操作文档,返回相关文档以搭建知识库
- 记忆(Memory) :通过短时和长时记忆存储和检索对话数据
- 链(Chains) :封装功能的核心机制,灵活完成常见用例
- 代理(Agents) :另一个LangChain中的核心机制,使大模型自主调用工具,形成智能自主Agent
- 应用篇:积累场景中的智慧
- 内容:LangChain组件在实际场景中的应用
- 实践:嵌入式存储、数据库连接、异步通信、智能代理的角色扮演等
- 目标:通过实际案例展示组件了解如何共同完成复杂任务,提升实战能力
- 实战篇:动手!
- 项目:部署鲜花网络电商的人脉工具,开发易速鲜花聊天客服机器人
- 实践:从模型调用到数据连接,再到记忆的存储与检索,掌握构建智能系统的每个环节
- 目标:能够独立利用LangChain构建智能问答系统,适用于企业或个人需求
LangChain 中的输出解析器
一、输出解析器
语言模型输出文本供人类阅读,但有时需获取程序能处理的结构化信息,输出解析器便发挥作用。它是处理和构建语言模型响应的类,基本的输出解析器类通常要实现两个核心方法:
- get_format_instructions:返回字符串,指导语言模型如何格式化输出
- parse:接收语言模型输出的字符串,解析成特定数据结构或格式,确保符合预期以便后续处理 还有可选方法parse_with_prompt,它接收语言模型输出和提示,基于原始提示解析输出为特定数据结构,让信息更准确贴合要求。并给出了简单伪代码示例展示其类结构
二、LangChain 中的各类输出解析器
- 列表解析器:用于模型输出应为列表的情况,比如询问鲜花库存时,期望模型回答是列表形式
- 日期时间解析器:处理与日期、时间相关输出,保证格式正确
- 枚举解析器:处理模型输出应为预定义一组值之一的情况,如答案限定 “是” 或 “否” 时确保符合要求
- 结构化输出解析器:处理复杂、结构化输出,像生成报告、文章等情况可使用
- Pydantic(JSON)解析器:模型输出应为符合特定格式的 JSON 对象时使用,借助 Pydantic 库验证构建复杂数据模型,确保输出符合预期数据模型
- 自动修复解析器:能自动修复常见模型输出错误,比如纠正文本中的语法、拼写错误
- 重试解析器:在模型初次输出不符合预期时,尝试修复或重新生成正确输出,如日期格式不符时可重新提示模型生成正确格式
Pydantic(JSON)解析器实战
Pydantic解析器在诸多解析器中是常用且重要的一种。它依托于Python数据验证和设置管理库Pydantic,该库主要基于Python类型提示构建。虽然Pydantic本身并非专为JSON所设计,但JSON在现代Web应用以及API交互里属于常见的数据格式,所以Pydantic在处理与验证JSON数据方面有着特别的用处,可在相关程序重构等场景中发挥重要作用,比如用来重构鲜花文案生成程序
# ------Part 1
import os
# os.environ["OPENAI_API_KEY"] = 'Your OpenAI API Key'
# 创建模型实例
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model=os.environ.get("LLM_MODELEND"),
)
# ------Part 2
# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["flower_type", "price", "description", "reason"])
# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]
# 定义我们想要接收的数据格式
from pydantic.v1 import BaseModel, Field
class FlowerDescription(BaseModel):
flower_type: str = Field(description="鲜花的种类")
price: int = Field(description="鲜花的价格")
description: str = Field(description="鲜花的描述文案")
reason: str = Field(description="为什么要这样写这个文案")
# ------Part 3
# 创建输出解析器
from langchain.output_parsers import PydanticOutputParser
output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)
# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
# 打印提示
print("输出格式:", format_instructions)
# ------Part 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)
# ------Part 5
for flower, price in zip(flowers, prices):
# 根据提示准备模型的输入
input = prompt.format(flower=flower, price=price)
# 打印提示
print("提示:", input)
# 获取模型的输出
output = model.predict(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"))
- 模型实例创建(Part 1)
- 设置
OpenAI API密钥(示例中未给出真实密钥),从langchain_openai导入ChatOpenAI并创建名为model的模型实例
- 数据准备(Part 2)
- 导入
pandas库创建空的DataFrame用于存储结果,列名包含 “flower_type”“price”“description”“reason” - 定义鲜花种类列表
flowers和价格列表prices,同时利用pydantic.v1创建FlowerDescription类,规定了鲜花相关信息的数据格式
- 输出解析器相关操作(Part 3)
- 从
langchain.output_parsers导入PydanticOutputParser,基于FlowerDescription类创建output_parser - 获取输出格式指示
format_instructions并打印展示,用于指导后续模型输出的格式
- 提示模板创建(Part 4)
- 从
langchain导入PromptTemplate,构建prompt_template提示模板,内容围绕撰写鲜花店文案的要求,并融入输出格式指示 - 根据模板创建
prompt提示,然后打印展示该提示内容
- 循环处理与结果存储(Part 5)
- 循环遍历鲜花种类和价格列表,根据
prompt准备模型输入并打印,获取模型输出后,用output_parser解析输出,将Pydantic格式转换为字典形式 - 把解析后的输出字典添加到之前创建的
DataFrame中,最后打印DataFrame转换后的字典形式数据,即得到包含鲜花相关文案信息的数据结果
自动修复解析器(OutputFixingParser)实战
# 导入所需要的库和模块
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List
# 使用Pydantic创建一个数据格式,表示花
class Flower(BaseModel):
name: str = Field(description="name of a flower")
colors: List[str] = Field(description="the colors of this flower")
# 定义一个用于获取某种花的颜色列表的查询
flower_query = "Generate the charaters for a random flower."
# 定义一个格式不正确的输出
misformatted = "{'name': '康乃馨', 'colors': ['粉红色','白色','红色','紫色','黄色']}"
# 创建一个用于解析输出的Pydantic解析器,此处希望解析为Flower格式
parser = PydanticOutputParser(pydantic_object=Flower)
# 使用Pydantic解析器解析不正确的输出
# parser.parse(misformatted) # 这行代码会出错
# 从langchain库导入所需的模块
from langchain.output_parsers import OutputFixingParser
from langchain_openai import ChatOpenAI
# 设置OpenAI API密钥
import os
# os.environ["OPENAI_API_KEY"] = 'Your OpenAI API Key'
# 使用OutputFixingParser创建一个新的解析器,该解析器能够纠正格式不正确的输出
new_parser = OutputFixingParser.from_llm(
parser=parser,
llm=ChatOpenAI(
model=os.environ.get("LLM_MODELEND"),
),
)
# 使用新的解析器解析不正确的输出
result = new_parser.parse(misformatted) # 错误被自动修正
print(result) # 打印解析后的输出结果
- 导入所需库和模块,包括
langchain相关输出解析器、pydantic相关类以及typing模块等 - 利用
pydantic创建Flower类定义花的数据格式,含花名和颜色列表两个属性 - 定义查询语句
flower_query以及格式不正确的输出misformatted - 基于
Flower类创建PydanticOutputParser解析器,若直接用其解析错误输出会报错 - 从
langchain库导入相关模块,准备设置OpenAI API密钥(示例中未给出真实密钥) - 使用
OutputFixingParser结合已有解析器和ChatOpenAI创建新解析器,旨在纠正格式错误的输出
重试解析器(RetryWithErrorOutputParser)实战
OutputFixingParser 虽有一定作用,但仅能做简单格式修复。若出现如输出内容不完整、有缺失等更复杂的错误,仅凭输出与格式本身,该解析器无法修复。而 LangChain 提供的重试解析器,通过实现 parse_with_prompt 方法,可借助大模型的推理能力,依据原始提示找回相关信息
# 定义一个模板字符串,这个模板将用于生成提问
template = """Based on the user question, provide an Action and Action Input for what step should be taken.
{format_instructions}
Question: {query}
Response:"""
# 定义一个Pydantic数据格式,这个格式描述了一个"行动"类及其属性
from pydantic import BaseModel, Field
class Action(BaseModel):
action: str = Field(description="action to take")
action_input: str = Field(description="input to the action")
# 使用Pydantic格式Action来初始化一个输出解析器
from langchain.output_parsers import PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Action)
# 定义一个提示模板,它将用于向模型提问
from langchain.prompts import PromptTemplate
prompt = PromptTemplate(
template="Answer the user query.\n{format_instructions}\n{query}\n",
input_variables=["query"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
prompt_value = prompt.format_prompt(query="What are the colors of Orchid?")
# 定义一个错误格式的字符串
bad_response = '{"action": "search"}'
# parser.parse(bad_response) # 如果直接解析,它会引发一个错误
# 设置OpenAI API密钥
import os
from langchain_openai import ChatOpenAI
# 尝试用OutputFixingParser来解决这个问题
from langchain.output_parsers import OutputFixingParser
fix_parser = OutputFixingParser.from_llm(
parser=parser,
llm=ChatOpenAI(
model=os.environ.get("LLM_MODELEND"),
),
)
parse_result = fix_parser.parse(bad_response)
print("OutputFixingParser的parse结果:", parse_result)
# 初始化RetryWithErrorOutputParser,它会尝试再次提问来得到一个正确的输出
from langchain.output_parsers import RetryWithErrorOutputParser
retry_parser = RetryWithErrorOutputParser.from_llm(
parser=parser, llm=ChatOpenAI(model=os.environ.get("LLM_MODELEND"), temperature=0)
)
parse_result = retry_parser.parse_with_prompt(bad_response, prompt_value)
print("RetryWithErrorOutputParser的parse结果:", parse_result)
- 定义提问模板,含格式化指令与用户问题占位符,用于引导模型回复 “行动” 及 “行动输入” 相关内容
- 用 Pydantic 创建
Action类定义数据格式,约束输出结构 - 基于
Action类初始化输出解析器,确保模型输出符合格式要求 - 构建提示模板,结合解析器生成具体的提问内容
- 定义一个格式错误的字符串模拟不符合预期的模型输出
- 先使用
OutputFixingParser尝试修复错误格式的输出并查看结果 - 再用
RetryWithErrorOutputParser结合提示重新获取正确输出并查看结果,整体展示处理模型输出不符合预期情况的流程
写在最后
结构化解析器与 Pydantic 解析器用于获取大语言模型格式化输出,前者适配简单文本,后者能应对复杂数据结构;自动修复解析器可纠正小格式错误,较为 “被动”,重试解析器能处理如格式错误、内容缺失等复杂问题,靠重新与模型交互完善输出。选择解析器时需考量应用场景,仅存在格式问题可选自动修复解析器,若重视输出完整性和准确性则重试解析器更合适……无论如何,有一点毋庸置疑。我们正站在一个崭新的历史节点上。