LangChain实战课-10-Chain(下)玩转RouterChain | 豆包MarsCode AI刷题

69 阅读5分钟

任务设定

image.png 不同的输入=>走不同的提示模板,或者说链。根据这两个场景来构建两个不同的目标链。遇到不同类型的问题,LangChain会通过RouterChain来自动引导大语言模型选择不同的模板。路由链是用来选择链的

整体框架

在这里,我们会用LLMRouterChain和MultiPromptChain(也是一种路由链)组合实现路由功能,该MultiPromptChain会调用LLMRouterChain选择与给定问题最相关的提示,然后使用该提示回答问题。

具体步骤如下:

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

完整代码

""" 
本文件是【链(下):想学 “育花” 还是 “插花”?用 RouterChain 确定客户意图】章节的配套代码,课程链接:https://juejin.cn/book/7387702347436130304/section/7388069979649736754
您可以点击最上方的“运行“按钮,直接运行该文件;更多操作指引请参考Readme.md文件。
"""
import warnings
import os

warnings.filterwarnings("ignore")

# 设置OpenAI API密钥

# 构建两个场景的模板
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,
    },
]

# 初始化语言模型
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model=os.environ.get("LLM_MODELEND"),
)

# 构建目标链
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

# 构建路由链
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)

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

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

# 构建多提示链
from langchain.chains.router import MultiPromptChain

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

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

这里面最值得一提的是路由模板,通过构建路由链完成了路由提示词:

路由模板:
 Given a raw text input to a language model select the model prompt best suited for the input. You will be given the names of the available prompts and a description of what the prompt is best suited for. You may also revise the original input if you think that revising it will ultimately lead to a better response from the language model.

<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
    ```json
    {{
        "destination": string \ name of the prompt to use or "DEFAULT"
        "next_inputs": string \ a potentially modified version of the original input
    }}
    ```

REMEMBER: "destination" MUST be one of the candidate prompt names specified below OR it can be "DEFAULT" if the input is not well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input if you don't think any modifications are needed.

<< CANDIDATE PROMPTS >>
flower_care: 适合回答关于鲜花护理的问题
flower_decoration: 适合回答关于鲜花装饰的问题

<< INPUT >>
{input}

<< OUTPUT >>

通过前面那一套,最终构建了这样的提示模板。

构建多提示链

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

MultiPromptChain中有三个关键元素。

  • router_chain(类型RouterChain):这是用于决定目标链和其输入的链。当给定某个输入时,这个router_chain决定哪一个destination_chain应该被选中,以及传给它的具体输入是什么。
  • destination_chains(类型Mapping[str, LLMChain]):这是一个映射,将名称映射到可以将输入路由到的候选链。例如,你可能有多种处理文本输入的方法(或“链”),每种方法针对特定类型的问题。destination_chains可以是这样一个字典:{'weather': weather_chain, 'news': news_chain}。在这里,weather_chain可能专门处理与天气相关的问题,而news_chain处理与新闻相关的问题。
  • default_chain(类型LLMChain):当 router_chain 无法将输入映射到destination_chains中的任何一个链时,LLMChain 将使用此默认链。这是一个备选方案,确保即使路由器不能决定正确的链,也总有一个链可以处理输入。

它的工作流程如下:

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