04 LangChain链的学习,让大模型更了解你的需求|豆包MarsCode AI刷题

219 阅读7分钟

如果要开发更复杂的应用程序,需要通过 “Chain” 来链接LangChain的各个组件和功能——模型之间彼此链接,或模型与其他组件链接。

LangChain中提供了很多种类型的预置链,目的是使各种各样的任务实现起来更加方便、规范。

image.png

LLMChain

LLMChain整合了PromptTemplate、语言模型(LLM或聊天模型)和 Output Parser,使用提示模板格式化输入,将格式化的字符串传递给 LLM,并返回 LLM 输出。

以生成花语为例来说,之前这个案例需要先设计提示模板根据模板创建提示,然后再创建并调用模型,返回结果。如果使用链,代码结构被简化。

# 导入所需的库
from langchain import PromptTemplate, OpenAI, LLMChain
# 原始字符串模板
template = "{flower}的花语是?"
# 创建模型实例
llm = OpenAI(temperature=0)
# 创建LLMChain
llm_chain = LLMChain(
    llm=llm,
    prompt=PromptTemplate.from_template(template))
# 调用LLMChain,返回结果
result = llm_chain("玫瑰")
print(result)

链的调用方式

直接调用

上文提到的方法就是直接调用链对象,如果提示模板包含多个变量,在调用链的时候,可以使用字典一次性输入它们。

通过run方法

run方法,也等价于直接调用_call_函数。

llm_chain("玫瑰")
# 等价于
llm_chain.run("玫瑰")

通过predict方法

predict方法类似于run,只是输入键被指定为关键字参数而不是 Python 字典。

result = llm_chain.predict(flower="玫瑰")
print(result)

通过apply方法

apply方法允许我们针对输入列表运行链,一次处理多个输入。

# apply允许您针对输入列表运行链
input_list = [
    {"flower": "玫瑰",'season': "夏季"},
    {"flower": "百合",'season': "春季"},
    {"flower": "郁金香",'season': "秋季"}
]
result = llm_chain.apply(input_list)
print(result)

通过generate方法

generate方法类似于apply,只不过它返回一个LLMResult对象,而不是字符串

result = llm_chain.generate(input_list)
print(result)
#输出是一个对象,里面包含模型生成文本过程中的一些相关信息,例如令牌数量、模型名称等。

Sequential Chain

Sequential Chain 相当于将几个LLMChain串起来,形成一个顺序链。

下面用一个示例来解释,假设大模型要经过三步:

  • 第一步,我们假设大模型是一个植物学家,让他给出某种特定鲜花的知识和介绍。
  • 第二步,我们假设大模型是一个鲜花评论者,让他参考上面植物学家的文字输出,对鲜花进行评论。
  • 第三步,我们假设大模型是易速鲜花的社交媒体运营经理,让他参考上面植物学家和鲜花评论者的文字输出,来写一篇鲜花运营文案。
#第一步,生成鲜花的知识性说明,省略单个LLMChain所需传输的参数
introduction_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="introduction")
#第二步,根据鲜花的知识性说明生成评论。
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review")
#第三步,根据鲜花的介绍和评论写出一篇自媒体的文案。
social_post_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="social_post_text")
#然后将以上三步连接起来
overall_chain = SequentialChain(
    chains=[introduction_chain, review_chain, social_post_chain],
    input_variables=["name", "color"],
    output_variables=["introduction","review","social_post_text"],
    verbose=True)

# 运行链,并打印结果
result = overall_chain({"name":"玫瑰", "color": "黑色"})
print(result)

最后的输出为如下:

image.png

RouterChain

当然一个AI助手ChatBot不可能只能解决一种问题。当遇到不同类型的题目,应该有的反应是,如果接到的是第一类问题,你要给ChatBot A指示;如果接到第二类的问题,你要给ChatBot B指示。 这就可以通过RouterChain来自动引导大预言模型选择不同的模板。

RouterChain,也叫路由链,能动态选择用于给定输入的下一个链。我们会根据用户的问题内容,首先使用路由器链确定问题更适合哪个处理模板,然后将问题发送到该处理模板进行回答。如果问题不适合任何已定义的处理模板,它会被发送到默认链。

下面用一个示例来解释:

鲜花运营智能客服ChatBot通常会接到两大类问题。

  1. 鲜花养护(保持花的健康、如何浇水、施肥等)
  2. 鲜花装饰(如何搭配花、如何装饰场地等)

思路

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

实现过程

构建提示信息时,用列表处理关键信息

# 构建提示信息
prompt_infos = [
    {
        "key": "flower_care",
        "description": "适合回答关于鲜花护理的问题",
        "template": flower_care_template,
    },
    {
        "key": "flower_decoration",
        "description": "适合回答关于鲜花装饰的问题",
        "template": flower_deco_template,
    }]

构建目标链,分别负责处理不同的问题

chain_map = {}
for info in prompt_infos:
    prompt = PromptTemplate(template=info['template'], 
                            input_variables=["input"])
    print("目标提示:\n",prompt)
    chain = LLMChain(llm=llm, prompt=prompt,verbose=True)
    chain_map[info["key"]] = chain

构建LLM路由链,负责查看用户输入的问题,确定问题的类型。

# 构建路由链
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE as RounterTemplate
destinations = [f"{p['key']}: {p['description']}" for p in prompt_infos]
router_template = RounterTemplate.format(destinations="\n".join(destinations))
print("路由模板:\n",router_template)
router_prompt = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),)
print("路由提示:\n",router_prompt)
router_chain = LLMRouterChain.from_llm(llm, 
                                       router_prompt,
                                       verbose=True)

将多个子链的key和description统一为router_template

这个路由模板可以根据输入选出最合适的模型提示。

  • 其中input_variables 指定模板接收的输入变量名,这里只有 "input"
  • output_parser 是一个用于解析模型输出的对象,它有一个默认的目的地和一个指向下一输入的键。
  • template 是实际的路由模板,用于给模型提供指示。这就是刚才详细解释的模板内容。
  • template_format 指定模板的格式,这里是 "f-string"
  • validate_template 是一个布尔值,如果为 True,则会在使用模板前验证其有效性。

输出:

image.png image.png 构建默认链:

除了处理目标链和路由链之外,我们还需要准备一个默认链。如果路由链没有找到适合的链,那么,就以默认链进行处理。

# 构建默认链
from langchain.chains import ConversationChain
default_chain = ConversationChain(llm=llm, 
                                  output_key="text",
                                  verbose=True)

构建多提示链

使用MultiPromptChain类把前几个链整合在一起,实现路由功能。这个MultiPromptChain类是一个多路选择链,它使用一个LLM路由器链在多个提示之间进行选择。

  • router_chain(类型RouterChain):这是用于决定目标链和其输入的链。当给定某个输入时,这个router_chain决定哪一个destination_chain应该被选中,以及传给它的具体输入是什么。
  • destination_chains(类型Mapping[str, LLMChain]):这是一个映射,将名称映射到可以将输入路由到的候选链。例如,你可能有多种处理文本输入的方法(或“链”),每种方法针对特定类型的问题。
  • default_chain(类型LLMChain):当 router_chain 无法将输入映射到destination_chains中的任何一个链时,LLMChain 将使用此默认链。这是一个备选方案,确保即使路由器不能决定正确的链,也总有一个链可以处理输入。
# 构建多提示链
from langchain.chains.router import MultiPromptChain
chain = MultiPromptChain(
    router_chain=router_chain,
    destination_chains=chain_map,
    default_chain=default_chain,
    verbose=True)

运行结果一:

image.png 运行结果二:

image.png

运行结果三: image.png