Bootstrap

LangChain实战(国内大模型)| Chains的四个核心模块实测——LLMChain、SimpleSequentialChain、SequentialChain和LLMRouteChain

简介

作为 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: 角色回答具体问题。
适合根据输入内容选择不同的处理逻辑当需要根据不同的输入选择不同的处理流程或模型时。

0.连接大模型

先选一个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,
)

1.LLMChain

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示例,指定llmprompt两个必要参数

  • llm:大模型
  • prompt:提问的模版prompt

步骤3】启动Chain,通过chain.run传递输入的变量product(同理,两个参数就是chain.run(product1,product2),跟传给函数的变量一样)
步骤4】输出结果

在这里插入图片描述

  • 实际输入:绿色字体Human后的文字,表示我们给大模型的完整输入(提问句),product的值 是不是 填到了中括号{}的位置!是的。
  • 实际输出:> Finished chain下面的内容,就是大模型的输出

先理解 LLMChain 这个链,后面都是基于这个链的复合应用。

2.SimpleSequentialChain

串联式调用语言模型链的一种,简单的串联每个步骤(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:{product}
  • 输出1:工厂名
  • 输入2:输出1的工厂名, 作为本次输入{company_name}
  • 输出2:广告语

使用 SimpleSequentialChain ,只需记住2个要点!!!
【1】一个输入,有顺序地做n件事
【2】将前一个Chain的输出,作为下一个Chain的输入

3.SequentialChain

序列中的每个 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示例,指定chainsinput_variablesoutput_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】的输出

四个任务的输入 & 输出变量关系如下

Task 1
翻译
Task 2
生成介绍
Task 3
语言检测
Task 4
生成概述
产品名称
product_name
英文产品名
english_product_name
英文介绍
english_introduce
产品语言
language
概述
summary

使用 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不仅能够处理线性的工作流,还能够适应更复杂的、需要多个步骤协同工作的业务场景。

再看两个示例
在这里插入图片描述

4.LLMRouterChain

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

参考

人工智能的黄金链条:LangChain核心模块Chains解析

;