LangChain中链的使用 | 豆包MarsCode AI刷题

97 阅读7分钟

什么是链?

学习这么多节课,LangChain带一个Chain,那么链在LangChain中到底是如何呈现的,又在一个应用程序中起到什么作用呢,本篇笔记就来探索一下。

  • 首先LangChain通过设计好的接口,实现一个具体的链的功能。
  • 实现了链的具体功能之后,我们可以通过将多个链组合在一起,或者将链与其他组件组合来构建更复杂的链。

链在内部把一系列的功能进行封装,而链的外部则又可以组合串联。链其实可以被视为LangChain中的一种基本功能单元。

常用的链有以下几个类型:

  • LLMChain: 是基于大模型构建的最简单、最基本的链。它包含提示模板,能根据用户输入对其进行格式化,把格式化好的提示传入模型,然后返回 LLM 的响应,同时解析输出。LLMChain 广泛用在整个 LangChain 中,包括其他链和代理中都经常出现它的身影。

  • SequentialChain(顺序链): 一个应用程序通常不会只调用一次语言模型,当你想要获取一个调用的输出并将其用作另一个调用的输入时,顺序链就特别有用。SimpleSequentialChain 是顺序链的最简单形式,其中每个步骤都有一个单一的输入/输出,并且一个步骤的输出是下一步的输入。而 SequentialChain 是更通用的顺序链形式,允许多个输入/输出。

  • RouterChain(路由链): 包含条件判断和一系列的目标链。通过调用 LLM,路由链能动态判断条件,以确定调用后续哪一个目标 Chain。

LLMChain

LLMChain是最简单的链,它可以把提示模板、语言模型和输出解析整合到一起,使得格式更加规范,代码更加简洁。

链的调用也有多种形式,可以直接调用、通过run方法调用、通过predict方法调用,这三种调用方式的输入是单个的;通过apply方法调用和通过generate方法调用则可以输入链表,一次性处理多个输入。不过随着LangChain的版本更新,这些调用方式和课程给的代码也有所不同,需要实际情况实际分析。

SequentialChain:顺序链

顺序链在我的理解中,就用定义多个LLChain链,然后定义每个LLChain的输出字典名,每个链的提示都可以不一样,然后前一个链的结果可以作为下一个链的输入。最后可以把多个链用SequentialChain串起来,然后就会按照顺序执行这几个链。

通过顺序链,可以很好的让几个串行的LLChain进行协作,进而得到我们想要的结果。

RouterChain: 路由链

当客户有两个或更多个不同领域的问题时,为了得到更加准确的结果,就需要路由链。路由链可以动态选择下一个链,它会根据用户的问题,首先确定使用哪个链更适合用户的问题,然后将问题发送给该模板进行回答,如果几个链都不合适,就会发送给默认链。一般一个简单的使用路由链的程序珲用到LLMRouterChain和MultiPromptChain 组合实现路由功能。

具体步骤如下:

  1. 构建处理模板:为要处理的多个任务定义字符串模板。
  2. 提示信息:使用一个列表来组织和存储这几个处理模板的关键信息,如模板的键、描述和实际内容。
  3. 初始化语言模型:导入并实例化语言模型。
  4. 构建目标链:根据提示信息中的每个模板构建了对应的LLMChain,并存储在一个字典中。
  5. 构建LLM路由链:这是决策的核心部分。首先,它根据提示信息构建了一个路由模板,然后使用这个模板创建了一个LLMRouterChain。
  6. 构建默认链:如果输入不适合任何已定义的处理模板,这个默认链会被触发。
  7. 构建多提示链:使用MultiPromptChain将LLM路由链、目标链和默认链组合在一起,形成一个完整的决策系统。

思考题

1.在第4课中,我们曾经用提示模板生成过一段鲜花的描述,请你使用LLMChain重构提示的format和获取模型输出部分,完成相同的功能。

这一部分就用LLMChain的apply方法,替换for循环的代码,并且修改一下输入列表的格式,具体代码如下:

# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
import os

# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)

# 创建模型实例
model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))

llm_chain = LLMChain(llm=model, prompt=prompt)

# 多种花的列表
# flowers = ["玫瑰", "百合", "康乃馨"]
# prices = ["50", "30", "20"]
# 生成多种花的文案
# for flower, price in zip(flowers, prices):
#     # 使用提示模板生成输入
#     input_prompt = prompt.format(flower_name=flower, price=price)

#     # 得到模型的输出
#     output = model.invoke(input_prompt)

#     # 打印输出内容
#     print(output)
input_list = [
    {"flower": "玫瑰", "price": "50"},
    {"flower": "百合", "price": "30"},
    {"flower": "郁金香", "price": "20"},
]

result = llm_chain.apply(input_list)
print(result)

2.上一道题目中,我要求你把提示的format和获取模型输出部分整合到LLMChain中,其实你还可以更进一步,把output_parser也整合到LLMChain中,让程序结构进一步简化,请你尝试一下。

这题的要求就是在上一个题的基础上加上一个输出解析器,在前面定义好输出解析器的格式,然后在定义LLMChain的时候传入output_parser=output_parser这个参数即可。

# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain
from langchain.output_parsers import StructuredOutputParser, ResponseSchema

import os

# 创建原始模板
prompt_template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短描述吗?
{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}
)
# 创建模型实例
model = ChatOpenAI(model=os.environ.get("LLM_MODELEND"))

llm_chain = LLMChain(llm=model, prompt=prompt, output_parser=output_parser)

# 数据准备
input_list = [
    {"flower": "玫瑰", "price": "50"},
    {"flower": "百合", "price": "30"},
    {"flower": "郁金香", "price": "20"},
]

result = llm_chain.apply(input_list)
print(result)

3.通过verbose=True这个选项的设定,在输出时显示了链的开始和结束日志,从而得到其相互调用流程。请你尝试把该选项设置为False,看一看输出结果有何不同。

在 LangChain 等库中,verbose 参数常用于控制链(Chain)或模型(Model)的输出详细程度。当设置为 True 时,程序通常会输出更多的中间步骤、调试信息或模型内部的工作原理。而当设置为 False 时,程序将只输出最终结果或关键信息,减少不必要的输出,使程序运行更加简洁。

下面两张图,第一张是设置verbose=True的情况,可以看出,它会输出一些中间步骤和一些内部信息;第二张是设置verbose=False的情况,输出就只有最后的运行结果。

image.png

image.png

4.在这个例子中,我们使用了ConversationChain作为default_chain,这个Chain是LLMChain的子类,你能否把这个Chain替换为LLMChain?

LLMChain替换ConversationChain,就需要自己定义一个默认的提示模板default_prompt,然后定义default_chain的时候加上参数prompt=default_prompt即可。

'''
# 构建默认链
from langchain.chains import ConversationChain

default_chain = ConversationChain(llm=llm, output_key="text", verbose=True)
'''

# default_prompt
default_prompt = PromptTemplate(
    input_variables=["input"],
    template="{input}",
)
default_chain = LLMChain(llm=llm, prompt=default_prompt, output_key="text", verbose=True)