LangChain实战06-链|豆包MarsCode AI刷题

35 阅读9分钟

一.链

1.概念

链是链接LangChain的各个组件和功能——模型之间彼此链接,或模型与其他组件链接的工具。下面是链的具体的几种类型:

image.png

2.LLMChain:最简单的链

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)

我们可以看到,在这段代码中提示模板的构建和模型的调用被封装在一起了。于是我们不用再调用prompt_temp.format()方法来填充模板,而直接调用LLMChain,将要填充的内容输入到Chain中就可以直接生成输出了。

二.链的调用方式

1.直接调用

prompt = PromptTemplate(
    input_variables=["flower", "season"],
    template="{flower}在{season}的花语是?",
)
llm_chain = LLMChain(llm=llm, prompt=prompt)
print(llm_chain({
    'flower': "玫瑰",
    'season': "夏季" }))

这里我们就是先构造模板,然后构造链,最后调用Chain获取输出。

2.通过run方法

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

3.通过predict方法

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

这里的唯一不同点就是输入键被指定为关键字参数而不是 Python 字典。

4.通过apply方法

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

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

5.通过generate方法

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

generate方法类似于apply,只不过它返回一个LLMResult对象,而不是字符串。LLMResult通常包含模型生成文本过程中的一些相关信息,例如令牌数量、模型名称等。我们来看看结果:

屏幕截图 2024-11-24 221007.png

三.Sequential Chain:顺序链

Sequential Chain可以把几个LLMChain串起来,形成一个顺序链。

下面我们来看一个示例:

  • 第一步,我们假设大模型是一个植物学家,让他给出某种特定鲜花的知识和介绍。
  • 第二步,我们假设大模型是一个鲜花评论者,让他参考上面植物学家的文字输出,对鲜花进行评论。
  • 第三步,我们假设大模型是易速鲜花的社交媒体运营经理,让他参考上面植物学家和鲜花评论者的文字输出,来写一篇鲜花运营文案。

1.导库

import os
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains import SequentialChain

2.添加第一个LLMChain

第一个链我们来实现生成鲜花的知识性说明

# 这是第一个LLMChain,用于生成鲜花的介绍,输入为花的名称和种类
llm = OpenAI(temperature=.7)

template = """
你是一个植物学家。给定花的名称和类型,你需要为这种花写一个200字左右的介绍。
花名: {name}
颜色: {color}
植物学家: 这是关于上述花的介绍:"""

prompt_template = PromptTemplate(input_variables=["name", "color"], template=template)
introduction_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="introduction")

这里我们初始化模型,构造模板,然后生成模板提示。最后搭建成功第一条链。链中包括模型,提示模板和output_key="introduction" 参数,它定义了生成的鲜花介绍的输出键,也就是存储最后的输出结果。

3.添加第二个LLMChain

# 这是第二个LLMChain,用于根据鲜花的介绍写出鲜花的评论
llm = OpenAI(temperature=.7)

template = """
你是一位鲜花评论家。给定一种花的介绍,你需要为这种花写一篇200字左右的评论。
鲜花介绍:
{introduction}
花评人对上述花的评论:"""

prompt_template = PromptTemplate(input_variables=["introduction"], template=template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review")

步骤和搭建第一条链相同。

3.添加第三个LLMChain

# 这是第三个LLMChain,用于根据鲜花的介绍和评论写出一篇自媒体的文案
template = """
你是一家花店的社交媒体经理。给定一种花的介绍和评论,你需要为这种花写一篇社交媒体的帖子,300字左右。
鲜花介绍:
{introduction}
花评人对上述花的评论:
{review}
社交媒体帖子:
"""

prompt_template = PromptTemplate(input_variables=["introduction", "review"], template=template)
social_post_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="social_post_text")

依然同理。

4.添加SequentialChain

这步是关键,我们要用顺序链串起前三个链。

# 这是总的链,我们按顺序运行这三个链
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)

在这里,我们调用顺序链生成了一个总链,包括了几种链,输入参数,输出参数。verbose=True是为了让链在执行过程中打印详细的信息(比如子链的输入输出等等)。

我们来看看输出结果:

屏幕截图 2024-11-24 223246.png

四.RouterChain:路由链

0.引入路由链

这里假设咱们的鲜花运营智能客服ChatBot通常会接到两大类问题。

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

如果接到的是第一类问题,你要给ChatBot A指示;如果接到第二类的问题,你要给ChatBot B指示。我们可以根据这两个场景来构建两个不同的目标链。遇到不同类型的问题,LangChain会通过RouterChain来自动引导大语言模型选择不同的模板。

image.png

1.构建提示信息的模板

# 构建两个场景的模板
flower_care_template = """你是一个经验丰富的园丁,擅长解答关于养花育花的问题。
                        下面是需要你来回答的问题:
                        {input}"""

flower_deco_template = """你是一位网红插花大师,擅长解答关于鲜花装饰的问题。
                        下面是需要你来回答的问题:
                        {input}"""

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

这里我们首先构造了两个提示模板,分别对应两种遇到的两个问题。然后使用一个列表来组织和存储这两个处理模板的关键信息,如模板的键、描述和实际内容。

2.初始化语言模型

# 初始化语言模型
from langchain.llms import OpenAI
import os
llm = OpenAI()

3.构建目标链

# 构建目标链
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
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

这里我们遍历prompt_infos这个列表,根据这个列表中的信息生成提示后构造出了两条链,分别处理两个问题。

代码中chain_map = {}构造了一个空字典,chain_map[info["key"]] = chain是很重要的一步,将几个链中的key值联系在一起,为后面构建 MultiPromptChain 时,根据输入的不同,模型可以选择合适的 LLMChain 来处理输入并生成输出。

4.构建路由链

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)
  1. destinations = []:这段代码从prompt_infos列表中提取每个提示信息的keydescription,并将它们格式化为一个字符串列表。
  2. router_template = RounterTemplate.format():使用格式化字符串的方法,将上面构建的目的地描述字符串插入到路由模板中。
  3. router_prompt = PromptTemplate():创建了一个PromptTemplate对象,它使用路由模板作为提示,并指定了输入变量为"input",同时使用RouterOutputParser作为输出解析器。

简而言之,这个构造允许你将用户的原始输入送入路由器,然后路由器会决定将该输入发送到哪个具体的模型提示,或者是否需要对输入进行修订以获得最佳的响应。

5.构建默认链

from langchain.chains import ConversationChain

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

默认链是在模型没有找到合适的链去处理问题时,可以用默认链进行回答。

6.构建多提示链

我们使用MultiPromptChain类把前几个构造的链(路由链,两条目标链整合而成的chain_map,以及默认链)整合在一起,实现路由功能。它是一个多路选择链,它使用一个LLM路由器链在多个提示之间进行选择。

from langchain.chains.router import MultiPromptChain

chain = MultiPromptChain(
    router_chain=router_chain,
    destination_chains=chain_map,
    default_chain=default_chain,
    verbose=True)

观察代码,我们看到MultiPromptChain中有三个关键元素:

  • router_chain:用于决定目标链和其输入的链。
  • destination_chains:我们可以看到它的值是chain_map,而chain_map中包含的就是各个链的key,通过这条链我们实现的就是根据输入的不同,提供特定的回答或处理逻辑。
  • default_chain:当 router_chain 无法将输入映射到destination_chains中的任何一个链时,LLMChain 将使用此默认链。

它的工作流程如下:

  1. 输入首先传递给router_chain
  2. router_chain根据某些标准或逻辑决定应该使用哪一个destination_chain
  3. 输入随后被路由到选定的destination_chain,该链进行处理并返回结果。
  4. 如果router_chain不能决定正确的destination_chain,则输入会被传递给default_chain。

这样,MultiPromptChain就为我们提供了一个在多个处理链之间动态路由输入的机制,以得到最相关或最优的输出。

7.运行路由链

这里我们选择了三个问题:

# 测试1
print(chain.run("如何为玫瑰浇水?"))
# 测试2
print(chain.run("如何为婚礼场地装饰花朵?"))
# 测试3
print(chain.run("如何区分阿豆和罗豆?")

第一个回答:

屏幕截图 2024-11-26 210936.png 这里没有放完整的答案,我们可以看到这里成功调用了第一条链。

第二个回答:

屏幕截图 2024-11-26 211140.png 我们可以看到这里成功调用了第一条链。

第三个回答:

屏幕截图 2024-11-26 211245.png 我们发现模型的并没有准确的回答,因为这里没有找到合适的链来回答问题,所以最终使用了默认链进行了文本输出。

以上就是学习链的全部知识了。