赞
踩
作为 LangChain 的核心模块之一,Chain 的重要性不言而喻。
它相当于是所有复杂逻辑的基础,负责将每个零散的逻辑连接起来,构建成一整个业务流程。
Chain 的设计非常巧妙,可以说是大模型应用的最佳实践之一。
Chain 的设计非常巧妙,也非常值得借鉴,也是为什么 LangChain 能火爆的主要原因之一。
Chain的主要功能是根据需要将各种能力进行拼接和整合。比如在上图中,LangChain内部包含多个模块,可以根据需求定制LLMChain只使用Prompt和LLM模块,也可以定制一个HogwartsChain,其中包含LLM、Parser和Agent模块。
Chains主要包含以下几个模块,接下来的实践演练,会分别演示这几个模块的使用。
先总结一下四个模块
模块名称 | 功能描述 | 示例应用场景 | 使用要点 | 适用情况 |
---|---|---|---|---|
LLMChain | 整合语言模型和提示模板的最简单链。 | Step1: 为产品生成工厂名称 Step2: 生成广告语。 | 适合简单的文本生成或查询任务。 | 当需要单一输出且不需要复杂逻辑时使用。 |
SimpleSequentialChain | 串联式调用语言模型链的一种,简单的串联每个步骤(Chain 实例),每个步骤都有单一的输入/输出,并且一个步骤的输入是下一个步骤的输出。 | Step1: 为产品起一个厂名 Step2: 为厂名写一段广告语。 | 适合串联简单任务,每个任务之间有明确的输入输出关系。 | 当需要按顺序执行多个任务,且每个任务的输出作为下一个任务的输入时。 |
SequentialChain | 序列中的每个 Chain 实例都支持多个输入和输出,最终 SequentialChain 运行时根据 Chains 参数和每个 Chain 示例中设定的参数,分析每个实例所需的参数并按需传递。 | Step1: 产品名称翻译成英文 Step2: 生成英文介绍文本 Step3: 找到产品名所属的语言 Step4: 生成概述。 | 适合处理需要多个输入和输出的复杂任务。 | 当任务之间存在多个输入输出,需要灵活传递数据时。 |
LLMRouteChain | 根据提示词的不同而选择不同的Chain进行执行,实现分支判断的作用。 | Step1: 输入问题 Step2: 根据问题选择“物理学家”或“数学家”角色 Step3: 角色回答具体问题。 | 适合根据输入内容选择不同的处理逻辑。 | 当需要根据不同的输入选择不同的处理流程或模型时。 |
先选一个llm,参考这篇博客选择一个国内大模型
LangChain连接国内大模型测试|智谱ai、讯飞星火、通义千问
from langchain_community.chat_models import ChatZhipuAI
import os
os.environ["ZHIPUAI_API_KEY"] = "xx.xx"
llm = ChatZhipuAI(
model="glm-4",
temperature=0.5,
)
LLMChain是一个整合语言模型和提示模板的最简单链。
是其他Chain的基础,务必掌握!
# LangChain相关模块的导入
from langchain import LLMChain
from langchain.prompts import ChatPromptTemplate
# 根据prompt模板生成prompt实例
prompt = ChatPromptTemplate.from_template(
"请给生产: {product} 的工厂起一个恰当的厂名,并给出一句广告语。"
)
# 组合大模型实例和prompt实例,生成LLMChain实例,将结构固定,方便复用
chain = LLMChain(
# 大模型实例
llm=llm,
# prompt实例
prompt=prompt,
# 开启详细模式,会将大模型调用细节输出到控制台
verbose=True
)
# 通过run方法,传入模版中需要的参数,调用大模型获取结果
product = "IPhone2014"
res = chain.run(product)
print(res)
<应用场景>
Step1: 为产品生成工厂名称
Step2: 生成广告语。
简单来讲就是
【步骤1】先写一个提问的模版
prompt
,其中中括号{}
表示你要填入的变量名称(本例中交product,表示会把product填入给定位置,组装成一个提问句,传给大模型,你就不用每次都敲 “请给生产xxx广告语” 这句话了,方便吧!!!)
【步骤2】:组建LLMChain示例,指定llm
、prompt
两个必要参数
llm
:大模型prompt
:提问的模版prompt
【步骤3】启动Chain,通过chain.run传递输入的变量
product
(同理,两个参数就是chain.run(product1,product2),跟传给函数的变量一样)
【步骤4】输出结果
{}
的位置!是的。先理解
LLMChain
这个链,后面都是基于这个链的复合应用。
串联式调用语言模型链的一种,简单的串联每个步骤(Chain 实例),每个步骤都有单一的输入/输出,并且一个步骤的输入是下一个步骤的输出。
from langchain.chains import SimpleSequentialChain
'''
###################
### 第一个Chain ###
###################
'''
# 第一个LLM请求的prompt模板
first_prompt = ChatPromptTemplate.from_template(
"请给生产 {product} 的工厂起一个恰当的厂名"
)
# 第一个Chain,接收外部输入,根据模版请求大模型获取输出,作为第二个Chain的输入
chain_one = LLMChain(llm=llm, prompt=first_prompt, verbose=True)
'''
###################
### 第二个Chain ###
###################
'''
# 第二个大模型请求的prompt模版
second_prompt = ChatPromptTemplate.from_template(
"为厂名写一段不少于20字的广告语: {company_name}"
)
# 第二个Chain,接收第一个Chain的输出,根据模版请求大模型获取输出
chain_two = LLMChain(llm=llm, prompt=second_prompt, verbose=True)
'''
##################################
### 组建SimpleSequentialChain ###
##################################
'''
# 将请求拆分成两个Chain,可以针对每段请求细化相应的prompt内容,得到更准确更合理的结果,并且也可以复用其中的每个Chain实例
# 使用SimpleSequentialChain将两个Chain串联起来,其中每个Chain都只支持一个输入和一个输出,根据chains列表中的顺序,将前一个Chain的输出作为下一个Chain的输入
overall_simple_chain = SimpleSequentialChain(
chains=[chain_one, chain_two],
verbose=True
)
# 第一个Chain需要的输入
product = "IPhone2014"
# 通过run方法,传入参数,逐个运行整个Chain后,获取最终的结果
res = overall_simple_chain.run(product)
print(res)
<应用场景>
Step1: 为产品起一个厂名
Step2: 为厂名写一段广告语。
本示例SimpleSequentialChain的逻辑是,我想给一个产品起一个公司名和广告语,分两个步骤:
一个chain只负责生成公司名,一个chain负责生成广告语。
- 第一个chain的输入就是 用户的输入
- 第二个chain的输入是 第一个chain的输出
即可实现,我输入一个产品,能同时得到两个东西。且第二个东西的生成可以节约我再次输入的成本。
当然,这里是比较简单的示例,稍复杂些的应用,SimpleSequentialChain是有用武之地的!
可以看到我们进入了 SimpleSequentialChain 的链,进行了两次对话
输出1的工厂名, 作为本次输入{company_name}
使用 SimpleSequentialChain ,只需记住2个要点!!!
【1】一个输入,有顺序地做n件事
【2】将前一个Chain的输出,作为下一个Chain的输入
序列中的每个 Chain 实例都支持多个输入和输出,最终 SequentialChain 运行时根据 Chains 参数和每个 Chain 示例中设定的参数,分析每个实例所需的参数并按需传递。
重点词汇!按需传递
from langchain.chains import SequentialChain
'''
######################################
### Chain1 给中文产品名称翻译成英文 ###
######################################
'''
# Chain1 语言转换,产生英文产品名
prompt1 = ChatPromptTemplate.from_template(
"将以下文本翻译成英文: {product_name}"
)
chain1 = LLMChain(
# 使用的大模型实例
llm=llm,
# prompt模板
prompt=prompt1,
# 输出数据变量名
output_key="english_product_name",
)
'''
##################################################
### Chain2 根据英文产品名,生成一段英文介绍文本 ###
##################################################
'''
# Chain2 根据英文产品名,生成一段英文介绍文本
prompt2 = ChatPromptTemplate.from_template(
"Based on the following product, give an introduction text about 100 words: {english_product_name}"
)
chain2 = LLMChain(
llm=llm,
prompt=prompt2,
output_key="english_introduce"
)
'''
###########################################
### Chain3 产品名的语言判定(中文or英文) ###
###########################################
'''
# Chain3 找到产品名所属的语言
prompt3 = ChatPromptTemplate.from_template(
"下列文本使用的语言是什么?: {product_name}"
)
chain3 = LLMChain(
llm=llm,
prompt=prompt3,
output_key="language"
)
'''
#########################
### Chain4 生成概述 ###
#########################
'''
# Chain4 根据Chain2生成的英文介绍,使用产品名称原本的语言生成一段概述
prompt4 = ChatPromptTemplate.from_template(
"使用语言类型为: {language} ,为下列文本写一段不多于50字的概述: {english_introduce}"
)
chain4 = LLMChain(
llm=llm,
prompt=prompt4,
output_key="summary"
)
'''
############################
### 组建SequentialChain ###
############################
'''
# 标准版的序列Chain,SequentialChain,其中每个chain都支持多个输入和输出,
# 根据chains中每个独立chain对象,和chains中的顺序,决定参数的传递,获取最终的输出结果
overall_chain = SequentialChain(
chains=[chain1, chain2, chain3, chain4],
input_variables=["product_name"],
output_variables=["english_product_name", "english_introduce", "language", "summary"],
verbose=True
)
product_name = "重庆小面"
res = overall_chain(product_name)
res
<应用场景>
Step1: 产品名称翻译成英文
Step2: 生成英文介绍文本
Step3: 找到产品名所属的语言
Step4: 生成概述。
简单来讲就是
【步骤1】n件事,先写n个
LLMChain
(提问的模版prompt
+ chain)
【步骤2】组建SequentialChain示例,指定chains
、input_variables
、output_variables
三个必要参数
chains
:n个chain,list格式input_variables
:输入变量,SequentialChain的最初输入output_variables
:所有的输出变量,SequentialChain的中间输出【步骤3】启动Chain,通过overall_chain传递输入的变量
product_name
【步骤4】输出结果,结果由所有参数构成,字典dict格式。(这种输出方式,有助于代码工程化时的正确取值,dddd)
梳理下4个任务的输入 & 输出变量
【任务1】
- 输入:product_name
- 输出:english_product_name
- 描述:
【任务2】
- 输入:english_product_name
- 输出:english_introduce
【任务3】
- 输入:product_name
- 输出:language
【任务4】
- 输入:language,english_introduce
- 输出:summary
n个任务都会执行!
【任务1】和【任务3】的输入只需要product_name,各输出一个变量
【任务2】的输入是【任务1】的输出
【任务4】的输入是【任务2】和【任务3】的输出
四个任务的输入 & 输出变量关系如下
使用 SequentialChain,也只需记住2个要点!!!
【1】1/n个输入,顺序地做n件事(不确定这样算不算乱序,任务2和任务3的输出输出没有交集,也没有先后顺序)
【2】参数按需传递,将之前Chain的输出,作为后面Chain的输入(可以是在SequentialChain中该子chain运行前,输入/生成的所有变量)
(上面表述的清楚吗?下面是AI整理的表达,可能有助于各位的理解)
使用SequentialChain的两个关键要点可以优化表达如下:
- 顺序执行: SequentialChain能够按照设定的顺序依次执行一系列任务(n件事)。
尽管任务之间可能没有直接的依赖关系(即任务2和任务3的输出没有交集,且执行没有严格的先后顺序),
但SequentialChain确保了任务按照既定的流程顺序进行。- 动态参数传递: SequentialChain支持智能的参数传递机制。
这意味着在执行过程中,一个Chain的输出可以动态地作为后续Chain的输入。
这种按需传递参数的能力,使得在SequentialChain中定义的子Chain能够在其运行前接收到所有必要的输入变量,从而实现复杂的业务逻辑。通过这种设计,SequentialChain不仅能够处理线性的工作流,还能够适应更复杂的、需要多个步骤协同工作的业务场景。
再看两个示例
LLMRouterChain + MultiPromptChain实现不同意图识别
LLMRouterChain 是根据提示词的不同而选择不同的Chain进行执行,实现分支判断的作用。
具体教程见博文 LLMChain使用 | RouterChain的使用 - 用本地大模型搭建多Agents
下面我贴上部分内容
我们以“园丁” 和 “插花大师”为例,子链DestinationChain分别是 园丁的chain
和 插花大师的chain
《代码流程》
1.【Step1】初始化语言模型("qwen:7b")
2.【Step2】构建提示信息(json格式),包括:key、description 和 template
- 【Step2.1】构建两个场景的模板
- 【Step2.2】构建提示信息
3.【Step3】构建目标链chain_map(json格式),以提示信息prompt_infos中的key为key,以Chain为value
4.【Step4】构建路由链router_chain
5.【Step5】构建默认链 default_chain
6.【Step6】构建多提示链 MultiPromptChain
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser
from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE as RounterTemplate
## 【Step1】初始化语言模型
# from langchain.llms import OpenAI
# llm = OpenAI()
# llm = AzureChatOpenAI(deployment_name="GPT-4", temperature=0)
ollama_llm = Ollama(model="qwen:7b")
## 【Step2】构建提示信息(json格式),包括:key、description 和 template
# 【Step2.1】构建两个场景的模板
flower_care_template = """
你是一个经验丰富的园丁,擅长解答关于养花育花的问题。
下面是需要你来回答的问题:
{input}
"""
flower_deco_template = """
你是一位网红插花大师,擅长解答关于鲜花装饰的问题。
下面是需要你来回答的问题:
{input}
"""
# 【Step2.2】构建提示信息
prompt_infos = [
{
"key": "flower_care",
"description": "适合回答关于鲜花护理的问题",
"template": flower_care_template,
},
{
"key": "flower_decoration",
"description": "适合回答关于鲜花装饰的问题",
"template": flower_deco_template,
}
]
## 【Step3】构建目标链chain_map(json格式),以提示信息prompt_infos中的key为key,以Chain为value
chain_map = {}
for info in prompt_infos:
prompt = PromptTemplate(
template=info['template'],
input_variables=["input"]
)
print("目标提示:\n", prompt)
chain = LLMChain(
llm=ollama_llm,
prompt=prompt,
verbose=True
)
chain_map[info["key"]] = chain
## 【Step4】构建路由链router_chain
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(
ollama_llm,
router_prompt,
verbose=True
)
## 【Step5】构建默认链 default_chain
from langchain.chains import ConversationChain
default_chain = ConversationChain(
llm=ollama_llm,
output_key="text",
verbose=True
)
## 【Step6】构建多提示链 MultiPromptChain
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("如何为玫瑰浇水?"))
示例代码中用的 ollama ,没装ollama工具的,把ollama_llm这个变量替换成前面的智谱ai,llm即可
ollama_llm 替换--> llm
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。