所有文章 > 日积月累 > 掌握如何搭建高效的大模型任务流(一):LangChain任务流构建
掌握如何搭建高效的大模型任务流(一):LangChain任务流构建

掌握如何搭建高效的大模型任务流(一):LangChain任务流构建

前言

Chain(链)是LangChain框架的核心概念之一,通过将多个任务模块组合在一起,形成灵活的任务流,可以实现复杂的逻辑处理和自动化任务。在实际应用中,链式操作能够帮助我们高效地管理大模型的调用过程,使其不仅能够单步完成任务,还可以进行多步任务的协作与集成,从而满足更加复杂的业务需求。

那在本节课,我们将聚焦LangChain的链式操作,详细解析几种核心的链式结构,包括 LLMChainSimpleSequentialChainSequentialChain、Router Chain 以及其他类型的Chain。通过这些内容的学习,你将掌握如何搭建高效的任务流,如何在不同链式模块之间传递和处理数据,以及如何根据具体场景选择合适的链式架构。就让我们打开代码编辑器,跟着我一步步的完成学习吧!

环境准备

在深入了解各类链之前,我们还是要先确保运行环境就绪。大致步骤如下:

  1. 安装 langchain 与对应依赖
  2. 在 .env 或环境变量中配置 API Key,如果是自定义或其他私有大模型,也要做好相应的 SDK 设置。
  3. (可选)如果需要使用 ConversationTokenBufferMemory 等,需要额外安装 transformers 库和torch 库,以支持 token 计数。

那只要我们能够成功运行以下代码并得到大模型返回的结果即可认为环境已经配置好了。

import os
from langchain_community.chat_models.tongyi import ChatTongyi
# 设置 API 密钥 (替换为自己的API_Key)
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'
# 初始化 ChatTongyi 模型
llm = ChatTongyi()
# 给出问题
response = llm.invoke('你是谁?')
#获取回复
print(response.content)

LLM Chain

那我们要讲的第一个链就是最基础的——LLM Chain。这个链其实在使用上和我们第一节课聊到的非常类似,只是在具体的用法上更加灵活。比如我们能够直接使用LLM Chain就能把记忆模块以及结构化输出等模块直接链接在里面,下面我们就来一起学习一下这个模块吧!

基础用法

LLMChain 是 LangChain 提供的一个用于构建逻辑链的模块,它结合了大语言模型(LLM)和提示模板(Prompt Template),从而实现对模型交互逻辑的封装。通过 LLMChain,开发者可以:

  • 定义清晰的提示模板,确保每次与模型的交互具有明确的目标。
  • 通过链式调用,构建更复杂的逻辑,例如多轮对话或任务分解。

简单来说,LLMChain 是开发者与 LLM 交互的桥梁。


LLMChain 的核心组件:

在使用 LLMChain 时,需要理解以下三个核心组件:

  1. LLM(大语言模型): 这是实际处理任务的模型,如 OpenAI 的 GPT 或阿里的 ChatTongyi。
  2. Prompt Template(提示模板): 定义与模型交互的语言提示,例如问题格式、语境信息等。
  3. LLMChain(逻辑链): 将上述两者结合起来,提供一个封装的调用接口。

以下是一个完整的代码示例,展示如何使用 LLMChain 与 ChatTongyi 进行简单的对话:

import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate

# 设置 API 密钥
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'

# 初始化 ChatTongyi 模型
llm = ChatTongyi()

# 使用 ChatPromptTemplate 创建提示模板
prompt = ChatPromptTemplate.from_template("{question}")

# 构建对话链
conversation = LLMChain(
llm=llm,
prompt=prompt
)

# 输入对话内容
input_question = "你是谁?"

# 进行对话,使用 invoke 方法传递参数
response_1 = conversation.invoke(input_question)
print(response_1["text"]) # 打印模型的回答

首先,我们需要导入必要的模块并通过环境变量设置 API 密钥,这一步是为了与 ChatTongyi 模型建立连接。通过 os.environ["DASHSCOPE_API_KEY"],我们将密钥信息传递给系统,确保模型可以正常运行。

import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate

# 设置 API 密钥
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'

接下来是初始化模型。在代码中,ChatTongyi() 是一个用于创建大语言模型实例的方法。它负责加载并准备模型以供后续使用。

# 初始化 ChatTongyi 模型
llm = ChatTongyi()

然后,我们通过 ChatPromptTemplate.from_template("{question}") 创建了一个提示模板。在模板中,{question} 是一个占位符,用于动态填充用户输入的问题。这种模板化的设计,让与模型的交互变得更加灵活。

# 使用 ChatPromptTemplate 创建提示模板
prompt = ChatPromptTemplate.from_template("{question}")

接下来的核心步骤是构建对话链。通过 LLMChain,我们将大语言模型和提示模板结合在一起,形成一个可用的交互链条。这个链条封装了底层逻辑,开发者只需要专注于输入和输出。

# 构建对话链
conversation = LLMChain(
llm=llm,
prompt=prompt
)

最后,通过 invoke 方法,我们向对话链传递了用户的问题,即 input_question,模型根据提示模板生成回答。通过 print(response["text"]),我们可以直观地看到模型的输出结果。

# 输入对话内容
input_question = "你是谁?"

# 进行对话,使用 invoke 方法传递参数
response_1 = conversation.invoke(input_question)
print(response_1["text"]) # 打印模型的回答

调用完成后,我们就可以在终端里看到大模型给予我们的回复。

我是来自阿里云的大规模语言模型,我叫通义千问。

添加记忆模块

但是假如单纯只是这样将大模型和提示词结合起来并不能展示出langchian的价值,这是因为我们在通义千问官方平台的调用其实也已经能够做到这一点了,因此其实我们还可以往这个链里面加多一些特别的东西,比如说上节课学习的记忆模块!

为了将记忆模块引入,我们需要对代码进行一些调整。首先,提示词模板需要新增一个变量 {memory} 来承接记忆信息。示例如下:

# 创建对话模板,包含历史对话和当前问题
prompt = ChatPromptTemplate.from_template('''
过往对话:
{history}
用户的问题是:
{question}
''')

接下来,我们不需要在 .invoke() 方法中额外手动添加新变量,只需在创建 LLMChain 时,将 memory 设置为合适的记忆模块即可:

# 构建对话链,包含模型、提示模板和对话记忆
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory=ConversationBufferMemory(), # 存储上下文的对话记忆
verbose = True
)

那这个时候,langchian就会自然而然的把这个记忆部分的内容加入进去了!大家可以通过下面的案例进行尝试:

import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate
from langchain.memory import ConversationBufferMemory

# 设置 API 密钥
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'

# 初始化通义千问模型
llm = ChatTongyi()

# 创建对话模板,包含历史对话和当前问题
prompt = ChatPromptTemplate.from_template('''
过往对话:
{history}
用户的问题是:
{question}
''')

# 构建对话链,包含模型、提示模板和对话记忆
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory=ConversationBufferMemory(), # 存储上下文的对话记忆
verbose = True
)

# 第一次对话:用户告诉模型自己的名字
input_question1 = "我是李剑锋"
response_1 = conversation.invoke(input_question1)
print("模型回答:", response_1["text"])

# 第二次对话:用户询问模型的身份
input_question2 = "你是谁?"
response_2 = conversation.invoke(input_question2)
print("模型回答:", response_2["text"])

# 第三次对话:用户测试模型是否记住了自己的名字
input_question3 = "你还记得我叫什么吗?"
response_3 = conversation.invoke(input_question3)
print("模型回答:", response_3["text"])

我们从结果中可以得知,模型记住了我的名字!假如我们不希望打印中间的过程内容,我们可以把前面的verbose=False即可。

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:

用户的问题是:
我是李剑锋

> Finished chain.
模型回答: 你好,李剑锋!很高兴认识你。你可以问我任何问题,我会尽力回答它们。或者,如果你需要帮助,我也很乐意提供帮助。

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴认识你。你可以问我任何问题,我会尽力回答它们。或者,如果你需要帮助,我也很乐意提供帮助。
用户的问题是:
你是谁?

> Finished chain.
模型回答: 我是来自阿里云的大规模语言模型,我叫通义千问。

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴认识你。你可以问我任何问题,我会尽力回答它们。或者,如果你需要帮助,我也很乐意提供帮助。
Human: 你是谁?
AI: 我是来自阿里云的大规模语言模型,我叫通义千问。
用户的问题是:
你还记得我叫什么吗?

> Finished chain.
模型回答: 当然记得,你是李剑锋。

多变量提示词模版

那除了传入单一问题变量 {current_question} 外,我们还可以尝试加入其他变量。例如,如果希望大模型根据指定的语气 {tone} 回复,我们需要对提示词模板进行调整:

# 创建对话模板,包含多个变量(如历史对话、当前问题和语气)
prompt = ChatPromptTemplate.from_template('''
过往对话:
{history}
当前问题:
{current_question}
语气:
{tone}
''')

另外在调用 .invoke() 方法时,我们需要以字典的格式传入多个变量:

# 第一次对话:用户告诉模型自己的名字,语气为友好
input_question1 = "我是李剑锋"
input_tone1 = "友好"
response_1 = conversation.invoke({"current_question": input_question1, "tone": input_tone1})
print("模型回答:", response_1["text"])

# 第二次对话:用户询问模型的身份,语气为正式
input_question2 = "你是谁?"
input_tone2 = "正式"
response_2 = conversation.invoke({"current_question": input_question2, "tone": input_tone2})
print("模型回答:", response_2["text"])

# 第三次对话:用户测试模型是否记得自己的名字,语气为随意
input_question3 = "你还记得我叫什么吗?"
input_tone3 = "随意"
response_3 = conversation.invoke({"current_question": input_question3, "tone": input_tone3})
print("模型回答:", response_3["text"])

但是我们会发现程序无法正常运行,出现的报错信息为:

ValueError: One input key expected got ['tone', 'current_question'] 

报错的核心原因是 ConversationBufferMemory 仅支持单一的输入键,而代码中传递了多个输入键(tone 和 current_question),导致冲突。通过观察前面 ConversationBufferMemory 的工作方式可以发现,它只会将提示词中最关键的问题部分(即 current_question)保存为对话记忆,而不会处理其他额外的变量(如 tone)。

为了解决这个问题,可以采用以下两种方法:

  1. 合并多个输入变量:将 tone 和 current_question 合并为一个键值后再传入,避免多个输入键的冲突。
  2. 指定 Memory 的输入键:在 ConversationBufferMemory 中指定 input_key 参数,让其只保存 current_question,忽略语气变量的影响。

以下是调整后的实现代码,采用了第二种方式:

# 构建对话链,包含模型、提示模板和对话记忆
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory = ConversationBufferMemory(input_key="current_question"),
verbose=True
)

这样调整了以后我们就会发现程序能够正常运行了并给出合适的回复。

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:

当前问题:
我是李剑锋
语气:
友好

> Finished chain.
模型回答: 你好,李剑锋!很高兴认识你。有什么可以帮到你的吗?或者你只是想聊聊天?

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴认识你。有什么可以帮到你的吗?或者你只是想聊聊天?
当前问题:
你是谁?
语气:
正式

> Finished chain.
模型回答: 我是来自阿里云的大规模语言模型,我叫通义千问。

> Entering new LLMChain chain...
Prompt after formatting:
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴认识你。有什么可以帮到你的吗?或者你只是想聊聊天?
Human: 你是谁?
AI: 我是来自阿里云的大规模语言模型,我叫通义千问。
当前问题:
你还记得我叫什么吗?
语气:
随意

> Finished chain.
模型回答: 当然记得,你好,李剑锋!有什么事情我可以帮助你吗?

完整的代码如下所示:

import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate
from langchain.memory import ConversationBufferMemory

# 设置 API 密钥
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'

# 初始化通义千问模型
llm = ChatTongyi()

# 创建对话模板,包含多个变量(如历史对话、当前问题和语气)
prompt = ChatPromptTemplate.from_template('''
过往对话:
{history}
当前问题:
{current_question}
语气:
{tone}
''')

# 构建对话链,包含模型、提示模板和对话记忆
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory = ConversationBufferMemory(input_key="current_question"),
verbose=True
)

# 第一次对话:用户告诉模型自己的名字,语气为友好
input_question1 = "我是李剑锋"
input_tone1 = "友好"
response_1 = conversation.invoke({"current_question": input_question1, "tone": input_tone1})
print("模型回答:", response_1["text"])

# 第二次对话:用户询问模型的身份,语气为正式
input_question2 = "你是谁?"
input_tone2 = "正式"
response_2 = conversation.invoke({"current_question": input_question2, "tone": input_tone2})
print("模型回答:", response_2["text"])

# 第三次对话:用户测试模型是否记得自己的名字,语气为随意
input_question3 = "你还记得我叫什么吗?"
input_tone3 = "随意"
response_3 = conversation.invoke({"current_question": input_question3, "tone": input_tone3})
print("模型回答:", response_3["text"])

添加系统信息

如果我们希望像之前一样,在对话中加入 SystemMessage(系统信息),在 LangChain 中实现这一功能其实非常简单。

首先,我们需要从 langchain.prompts 中导入 SystemMessagePromptTemplate 和 HumanMessagePromptTemplate。这是因为我们不再使用单一的 ChatPromptTemplate,而是需要更细化地对 System 和 Human 两部分的输入分别进行设置:

from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate

接下来,利用 SystemMessagePromptTemplate 来定义系统角色(如希望模型扮演的身份或任务)。与此同时,将原来的提示词模板改为 HumanMessagePromptTemplate 的格式,尽管直接使用 ChatPromptTemplate 也可以完成基础功能,但这种方式更灵活和模块化。最后,通过 ChatPromptTemplate.from_messages 将系统信息和用户提示词组合到一起。以下是示例代码:

# 创建系统消息模板,用于设定模型的行为或角色
system_message = SystemMessagePromptTemplate.from_template("你是一个专业且友好的助手,请根据用户的语气调整回答风格。")

# 创建输入信息,包含多个变量(如历史对话、当前问题和语气)
human_message = HumanMessagePromptTemplate.from_template('''
过往对话:
{history}
当前问题:
{current_question}
语气:
{tone}
''')

# 合并系统消息和用户消息到最终提示模板
prompt = ChatPromptTemplate.from_messages([system_message, human_message])

我们运行一下代码就会发现SystemMessage确实加入进去了!并且调整后可以更加匹配我们的风格进行回复!这种方式让我们能够更加个性化地设计对话流,从而实现更精确的控制和更自然的交互效果。

> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业且友好的助手,请根据用户的语气调整回答风格。
Human:
过往对话:

当前问题:
我是李剑锋
语气:
友好

> Finished chain.
模型回答: 你好,李剑锋!很高兴见到你。有什么我可以帮你的吗?

> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业且友好的助手,请根据用户的语气调整回答风格。
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴见到你。有什么我可以帮你的吗?
当前问题:
你是谁?
语气:
正式

> Finished chain.
模型回答: 我是李剑锋的AI助手,负责提供信息和帮助解决问题。请问您需要了解什么?

> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业且友好的助手,请根据用户的语气调整回答风格。
Human:
过往对话:
Human: 我是李剑锋
AI: 你好,李剑锋!很高兴见到你。有什么我可以帮你的吗?
Human: 你是谁?
AI: 我是李剑锋的AI助手,负责提供信息和帮助解决问题。请问您需要了解什么?
当前问题:
你还记得我叫什么吗?
语气:
随意

> Finished chain.
模型回答: 当然记得,你是李剑锋!有什么事情需要我帮忙的吗,李剑锋?

这部分完整的代码如下所示:

import os
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain.chains import LLMChain
from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
from langchain.memory import ConversationBufferMemory

# 设置 API 密钥
os.environ["DASHSCOPE_API_KEY"] = 'YOUR_SECRET_KEY'

# 初始化通义千问模型
llm = ChatTongyi()

# 创建系统消息模板,用于设定模型的行为或角色
system_message = SystemMessagePromptTemplate.from_template("你是一个专业且友好的助手,请根据用户的语气调整回答风格。")

# 创建对话模板,包含多个变量(如历史对话、当前问题和语气)
human_message = HumanMessagePromptTemplate.from_template('''
过往对话:
{history}
当前问题:
{current_question}
语气:
{tone}
''')

# 合并系统消息和用户消息到最终提示模板
prompt = ChatPromptTemplate.from_messages([system_message, human_message])

# 构建对话链,包含模型、提示模板和对话记忆
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory = ConversationBufferMemory(input_key="current_question"),
verbose=True
)

# 第一次对话:用户告诉模型自己的名字,语气为友好
input_question1 = "我是李剑锋"
input_tone1 = "友好"
response_1 = conversation.invoke({"current_question": input_question1, "tone": input_tone1})
print("模型回答:", response_1["text"])

# 第二次对话:用户询问模型的身份,语气为正式
input_question2 = "你是谁?"
input_tone2 = "正式"
response_2 = conversation.invoke({"current_question": input_question2, "tone": input_tone2})
print("模型回答:", response_2["text"])

# 第三次对话:用户测试模型是否记得自己的名字,语气为随意
input_question3 = "你还记得我叫什么吗?"
input_tone3 = "随意"
response_3 = conversation.invoke({"current_question": input_question3, "tone": input_tone3})
print("模型回答:", response_3["text"])

小结

相比于上节课学到的 ConversationChainLLMChain 提供了更高的灵活性和扩展性,其核心价值在于对模型调用逻辑的精细化管理和模块化设计。通过结合提示模板(Prompt Template)、记忆模块(Memory)、以及多变量输入等功能,LLMChain 能够支持更复杂的场景,比如多轮对话、多任务链式调用、动态上下文传递等。而 ConversationChain 更适合快速实现基础的对话功能,局限于单一的输入和输出逻辑。使用 LLMChain,开发者可以轻松构建结构化的交互流程,将模型的能力与特定场景需求结合,尤其在需要个性化输出、多模块集成(如记忆、数据库、API 调用)时,LLMChain 显得更加不可或缺。因此,LLMChain 是一个更加通用且可扩展的工具,适合复杂项目中更细致的逻辑实现和任务处理。

本文章转载微信公众号@机智流

#你可能也喜欢这些API文章!