在现代应用中,特别是基于大语言模型(LLM)的智能系统,任务复杂性日益增加。单一的模型调用和提示生成方法已经无法满足复杂场景的需求。LangChain 提供了 “链” 的概念,以模块化和流程化的方式组织模型操作。这种方式让开发者可以更高效地处理多步骤任务。
以下是本文将要探索的链的类型和功能:
- LLMChain:将提示、模型调用和输出解析整合成单一链。
- SequentialChain:将多个链组合成串行的流程。
- RouterChain:动态分配任务,解决多任务场景的问题。
通过这些链的使用,开发者可以快速构建更智能、更复杂的应用程序。
什么是 Chain?
Chain 是 LangChain 的核心概念之一,它通过链接多个组件(例如提示模板、语言模型、输出解析器等),将复杂的任务分解并组织成模块化的链条。这个设计思路简单但功能强大,它具备以下优点:
- 简化复杂任务:将多步骤操作封装成单一的调用链。
- 模块化设计:便于调试、维护和扩展应用程序。
- 多功能组合:支持模型间的链接或与其他工具的结合。
LangChain 提供了多种预置链,帮助开发者快速构建各种类型的应用程序。
LLMChain:最简单的链
LLMChain 是 LangChain 中最常用的链之一,它将提示模板、语言模型以及输出解析器整合在一起,封装了 Model I/O 的整个流程。
使用链前的传统写法
如果不使用链,生成“鲜花花语”的代码可能如下:
# 创建提示模板
from langchain import PromptTemplate
template = "{flower}的花语是?"
prompt_temp = PromptTemplate.from_template(template)
prompt = prompt_temp.format(flower='玫瑰')
# 调用语言模型
from langchain import OpenAI
model = OpenAI(temperature=0)
result = model(prompt)
print(result)
输出:
玫瑰的花语是?
爱情、浪漫、美丽、永恒、誓言、坚贞不渝。
这种写法虽然清晰,但提示模板的构建与模型调用是分开的。对于更复杂的任务,代码可能变得冗长且难以管理。
使用 LLMChain
使用 LLMChain,我们可以将上述逻辑封装到一个链中:
from langchain import PromptTemplate, OpenAI, LLMChain
template = "{flower}的花语是?"
llm = OpenAI(temperature=0)
llm_chain = LLMChain(
llm=llm,
prompt=PromptTemplate.from_template(template)
)
result = llm_chain({"flower": "玫瑰"})
print(result)
输出:
{'flower': '玫瑰', 'text': '\n\n爱情、浪漫、美丽、永恒、誓言、坚贞不渝。'}
通过 LLMChain,我们将提示模板的构建和模型调用封装在一起,简化了代码结构。
链的调用方式
1. 直接调用
直接调用链对象时,实际上执行的是链内部的 __call__ 方法。例如:
llm_chain({"flower": "玫瑰"})
2. 使用 run 方法
run 方法等价于直接调用 __call__ 方法:
llm_chain.run("玫瑰")
3. 使用 predict 方法
predict 方法允许通过关键字参数传递输入变量,而非字典:
result = llm_chain.predict(flower="玫瑰")
print(result)
4. 使用 apply 方法
apply 方法支持批量处理输入数据:
input_list = [
{"flower": "玫瑰"},
{"flower": "百合"},
{"flower": "郁金香"}
]
result = llm_chain.apply(input_list)
print(result)
输出:
[{'text': '爱情、浪漫、美丽。'}, {'text': '纯洁、高雅、友谊。'}, {'text': '完美、胜利。'}]
5. 使用 generate 方法
generate 方法返回一个包含额外信息的 LLMResult 对象,例如令牌使用量:
result = llm_chain.generate(input_list)
print(result)
SequentialChain:串联多个链
SequentialChain 是一种顺序链,用于将多个链按照特定顺序组合在一起。
场景示例:生成鲜花文案
我们希望通过三个步骤生成一篇鲜花运营文案:
- 植物学家生成鲜花的知识性说明。
- 鲜花评论家基于说明撰写评论。
- 社交媒体经理根据评论撰写运营文案。
实现步骤
- 创建第一个链:生成鲜花的知识性说明。
llm = OpenAI(temperature=0.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")
- 创建第二个链:基于说明生成评论。
template = """
你是一位鲜花评论家。给定一种花的介绍,你需要为这种花写一篇200字左右的评论。
鲜花介绍:
{introduction}
花评人对上述花的评论:"""
prompt_template = PromptTemplate(input_variables=["introduction"], template=template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review")
- 创建第三个链:根据评论生成社交媒体文案。
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")
- 将三个链组合成顺序链。
from langchain.chains import 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)
输出:
{'name': '玫瑰', 'color': '黑色',
'introduction': '黑色玫瑰是一种...',
'review': '黑色玫瑰不仅是一种花...',
'social_post_text': '欢迎来到我们的平台...'}
RouterChain:动态任务分配的智能链
RouterChain 是 LangChain 中的高级链类型,专注于动态任务分配。它通过分析用户输入,将问题自动路由到最合适的处理链,尤其适合多任务、多场景的应用。
为什么需要 RouterChain?
在多任务场景中,直接使用单一链或顺序链无法满足需求。例如,一个鲜花运营 ChatBot 面临以下两种典型任务:
- 鲜花护理:如“如何为玫瑰浇水?”
- 鲜花装饰:如“如何为婚礼场地布置鲜花?”
传统方法需要手动判断任务类型并选择合适的链,而 RouterChain 可以通过大语言模型的能力动态完成任务分类,自动路由到对应的链。
RouterChain 的核心概念
RouterChain 的工作流程包含以下三个步骤:
- 任务分类:分析用户输入并判断其任务类型。
- 路由任务:将输入发送到合适的目标链。
- 默认处理:当输入无法分类时,调用默认链进行处理。
RouterChain 的实现步骤
我们以一个鲜花运营 ChatBot 为例,展示如何使用 RouterChain 实现动态任务分配。
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. 构建目标链
使用 LLMChain 为每种场景创建独立的目标链。
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
import os
# 设置 API Key
os.environ["OPENAI_API_KEY"] = '你的OpenAI Key'
llm = OpenAI()
# 构建目标链
chain_map = {}
for info in prompt_infos:
prompt = PromptTemplate(template=info['template'], input_variables=["input"])
chain = LLMChain(llm=llm, prompt=prompt, verbose=True)
chain_map[info["key"]] = chain
3. 构建路由链
使用 LLMRouterChain 实现输入分析和任务分类。
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE as RouterTemplate
# 构建路由模板
destinations = [f"{p['key']}: {p['description']}" for p in prompt_infos]
router_template = RouterTemplate.format(destinations="\n".join(destinations))
router_prompt = PromptTemplate(
template=router_template,
input_variables=["input"],
output_parser=RouterOutputParser(),
)
# 创建路由链
router_chain = LLMRouterChain.from_llm(llm, router_prompt, verbose=True)
路由链根据用户输入分析任务类型,并动态选择目标链。
4. 构建默认链
定义一个默认链,处理无法分类的问题。
from langchain.chains import ConversationChain
# 构建默认链
default_chain = ConversationChain(llm=llm, output_key="text", verbose=True)
5. 组合所有链
使用 MultiPromptChain 将路由链、目标链和默认链整合成一个完整的系统。
from langchain.chains.router import MultiPromptChain
# 构建多提示链
chain = MultiPromptChain(
router_chain=router_chain,
destination_chains=chain_map,
default_chain=default_chain,
verbose=True
)
测试 RouterChain 的功能
我们分别测试鲜花护理问题、鲜花装饰问题以及无关问题。
测试 1:鲜花护理问题
print(chain.run("如何为玫瑰浇水?"))
输出:
目标链:鲜花护理
回答:根据天气情况和土壤湿度,每次浇水约200ml,避免浇水过多导致根系腐烂。
测试 2:鲜花装饰问题
print(chain.run("如何为婚礼场地装饰花朵?"))
输出:
目标链:鲜花装饰
回答:可以选择白色玫瑰搭配满天星,以突出婚礼的浪漫氛围。
测试 3:无关问题
print(chain.run("如何考入哈佛大学?"))
输出:
目标链:默认链
回答:抱歉,我无法回答这个问题,但我建议你可以参考哈佛大学官网的申请指南。