系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
文章目录
前言
在自然语言处理(NLP)的世界里,任务需求的多样性和复杂性不断给开发者提出挑战。一个高效的 NLP 系统需要同时胜任多个任务,例如动态生成广告语、个性化推荐,甚至能回答跨学科的问题。然而,传统开发方法通常需要独立为每个任务设计逻辑模块,不仅耗时耗力,还极易导致代码的复杂性失控。
LangChain 以其模块化的设计为这一问题提供了解决方案。它不仅简化了开发流程,还通过强大的链条组合能力,使开发者能够快速搭建从单一任务到多任务分配的完整逻辑流。本篇文章将围绕 LangChain 的核心功能模块展开,从理论到实战,全面展示如何通过它实现自然语言处理任务的高效管理。
在本文中,您将学到以下内容:
- LangChain 的核心链简介:从基础模块(如
ChatPromptTemplate
和Pipe Operator
)入手,学习如何构建单任务处理链条,逐步扩展到多步骤的复杂任务链。特别是通过RunnableSequence
,我们将探讨如何在多步骤任务中实现数据流转和结果汇总。 - Router Chain:任务分配与动态路由:通过动态路由机制,将输入内容分配到最适合的处理链条,实现智能化的跨领域任务处理,如物理、数学、历史和计算机科学问题的解答。
不仅如此,文章还提供了详细的代码示例,涵盖从单一任务到复杂任务链条的完整实现过程,助力您快速上手并将其应用于实际项目。
为什么你需要关注这篇文章?
- 如果您是一名自然语言处理的新手:本文将带您快速入门,从基础到进阶,掌握 LangChain 的核心功能。
- 如果您是一名经验丰富的开发者:动态路由和复杂链条的设计方法,将大幅提升您的系统灵活性与开发效率。
本文不是一个纯理论的解读,而是一个贯穿实践的指南。无论是生成广告语、推荐餐厅,还是动态解决跨学科问题,LangChain 都能为您提供强大的技术支持。而本文正是您解锁这些潜能的第一步。
一、LangChain 的核心链简介
LangChain 提供了丰富的模块,帮助开发者高效构建自然语言处理任务的逻辑流。本章将介绍如何通过新的方法直接结合 ChatPromptTemplate
和 ChatOpenAI
来实现核心功能,并利用 Pipe Operator
和 RunnableSequence
实现从简单到复杂的任务链。
1.1 单任务的 Prompt 模型结合
通过 ChatPromptTemplate
和 ChatOpenAI
的结合,可以快速实现单一任务,例如生成广告语、回答问题或其他简单任务。
1.1.1 使用 Prompt 模型生成广告语
以下示例展示了如何结合提示模板与语言模型,生成一条针对产品的中文广告语:
import os
from dotenv import load_dotenv # 加载环境变量
from langchain_openai import ChatOpenAI # OpenAI 的语言模型支持
from langchain.prompts import ChatPromptTemplate
# 加载 .env 文件中的环境变量
load_dotenv()
# 从环境变量中获取 API Key 和 Base URL
api_key = os.getenv("ALIYUN_API_KEY")
base_url = os.getenv("ALIYUN_API_URL")
# 初始化语言模型
llm = ChatOpenAI(
openai_api_key=api_key,
model_name="qwen-plus", # 使用 Qwen-Plus 模型
base_url=base_url,
)
# 定义提示模板
prompt = ChatPromptTemplate.from_template(
"请为以下产品设计一句吸引人的广告语:\n\n产品:{product}"
)
# 创建链条
chain = prompt | llm
# 输入产品信息并运行链条
product = "健康无糖茶饮"
result = chain.invoke({"product": product})
print(f"生成的广告语:{result.content}")
(1)功能说明
- 模板动态化:
{product}
是占位符,运行时会被实际的输入内容替换。 - 输出示例:
"一口茶香,一份健康,享受无糖新生活!"
(2)适用场景
- 生成产品广告语。
- 处理单一任务,例如生成问候语或生成 FAQ。
(3)注意事项
- 提示模板需尽量明确,以提高输出结果的精准度。
- 调整
temperature
参数可控制生成结果的多样性。
1.2 管道组合:顺序执行的简单链条
管道组合(Pipe Operator
,即 |
)是一种高效的方式,可以将多个任务串联起来,每个任务的输出作为下一个任务的输入。这种方法适用于线性的多步骤任务。
1.2.1 使用管道组合生成品牌名称和简介
以下示例展示如何通过两步链条,生成一个中文品牌名称并为其撰写品牌简介:
# 定义第一个任务:生成品牌名称
first_prompt = ChatPromptTemplate.from_template(
"为一家主营{product}的公司起一个中文品牌名称。"
)
chain_one = first_prompt | llm
# 定义第二个任务:生成品牌简介
second_prompt = ChatPromptTemplate.from_template(
"为以下品牌撰写一段简介:\n\n品牌名称:{brand_name}"
)
chain_two = second_prompt | llm
# 通过管道组合两个任务
simple_chain = chain_one | chain_two
# 输入数据并运行链条
product = {"product": "智能家居设备"}
result = simple_chain.invoke(product)
# 输出最终结果
print(f"生成结果:{result.content}")
(1)输出示例
- 品牌名称:
"智家优选"
- 品牌简介:
"智家优选致力于提供智能化的家居解决方案,为家庭带来便捷与高科技体验。"
(2)适用场景
- 品牌命名与文案撰写。
- 需要简单线性逻辑的任务,例如分两步生成标题和内容。
(3)注意事项
- 管道链条适用于简单的线性任务,不适合复杂的逻辑。
- 输入格式需与提示模板一致,确保正确传递数据。
1.3 RunnableSequence:多步骤复杂任务链
RunnableSequence
是 LangChain 的高级功能模块,支持复杂任务链,例如需要多输入、多输出以及多步骤的数据流转。
1.3.1 使用 RunnableSequence 实现多步骤餐厅推荐
以下示例展示如何通过多步骤链条,处理用户餐厅推荐任务,包括分析用户偏好、推荐餐厅并总结结果:
from langchain_core.runnables import RunnableSequence
# 步骤 1:分析用户输入的餐厅偏好
gather_preferences_prompt = ChatPromptTemplate.from_template(
"用户输入了一些餐厅偏好:{preferences}\n"
"请将用户的偏好总结为清晰的需求:"
)
# 步骤 2:根据需求推荐餐厅
recommend_restaurants_prompt = ChatPromptTemplate.from_template(
"基于用户需求:{summarized_preferences}\n"
"请推荐 3 家适合的餐厅,并说明推荐理由:"
)
# 步骤 3:总结推荐内容供用户快速参考
summarize_recommendations_prompt = ChatPromptTemplate.from_template(
"以下是餐厅推荐和推荐理由:\n{recommendations}\n"
"请总结成 2-3 句话,供用户快速参考:"
)
# 将每个任务组合成链条
gather_preferences_chain = gather_preferences_prompt | llm
recommend_restaurants_chain = recommend_restaurants_prompt | llm
summarize_recommendations_chain = summarize_recommendations_prompt | llm
# 创建 RunnableSequence
restaurant_chain = RunnableSequence(
gather_preferences_chain,
recommend_restaurants_chain,
summarize_recommendations_chain
)
# 示例输入数据
input_data = {"preferences": "我喜欢安静的环境,最好有素食选项,并且价格适中。"}
# 执行链条
result = restaurant_chain.invoke(input_data)
# 输出最终结果
print(result.content)
(1)输出示例
- 总结偏好:
"用户偏好安静的餐厅,提供素食选项,价格适中。"
- 推荐餐厅:
- 素心小馆:环境安静,素食菜单丰富,价格合理。
- 自然味道:素食自助餐厅,空间宽敞,经济实惠。
- 绿叶咖啡馆:多样化菜单,氛围安静。
- 总结推荐:
"推荐素心小馆、自然味道和绿叶咖啡馆,均符合您的素食和安静需求。"
(2)适用场景
- 个性化推荐:餐厅、旅游路线、酒店等。
- 多步骤任务链:如从输入中提取信息、分析并生成总结。
(3)注意事项
- 每一步的输入和输出变量需保持一致。
- 数据格式需严格按照每步任务的需求定义。
二、Router Chain:任务分配与动态路由
在复杂的自然语言处理场景中,不同输入内容可能需要不同的处理逻辑。例如,物理问题、数学问题和历史问题的解决方式可能完全不同。Router Chain
提供了动态路由解决方案,可以根据输入内容自动选择适合的处理链条。以下内容将结合您修改后的代码,详细讲解如何实现动态路由及其应用场景。
2.1 Router Chain 的概念
Router Chain
是 LangChain 提供的一种动态任务分配机制。它通过路由逻辑分析输入内容,将其动态分配到最合适的任务链。如果输入无法归类,则会调用默认处理链。Router Chain
的核心优势是灵活适配多领域任务处理需求。
2.2 实现步骤
以下是基于您的代码实现的完整动态路由逻辑及任务链的步骤。
2.2.1 定义任务模板
首先为不同领域(物理、数学、历史、计算机科学)的问题定义任务模板。这些模板会根据输入内容动态生成回答。
from langchain.prompts import ChatPromptTemplate
# 定义物理任务模板
physics_template = ChatPromptTemplate.from_template(
"你是一位物理学教授,擅长用简洁易懂的方式回答物理问题。以下是问题内容:{input}"
)
# 定义数学任务模板
math_template = ChatPromptTemplate.from_template(
"你是一位数学家,擅长分步骤解决数学问题,并提供详细的解决过程。以下是问题内容:{input}"
)
# 定义历史任务模板
history_template = ChatPromptTemplate.from_template(
"你是一位历史学家,对历史事件和背景有深入研究。以下是问题内容:{input}"
)
# 定义计算机科学任务模板
computerscience_template = ChatPromptTemplate.from_template(
"你是一位计算机科学专家,擅长算法、数据结构和编程问题。以下是问题内容:{input}"
)
2.2.2 创建任务链
将上述模板与语言模型(ChatOpenAI
)结合,形成任务链条。
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
load_dotenv()
# 从环境变量中获取 API Key 和 Base URL
api_key = os.getenv("ALIYUN_API_KEY")
base_url = os.getenv("ALIYUN_API_URL")
# 初始化语言模型
llm = ChatOpenAI(
openai_api_key=api_key,
model_name="qwen-plus", # 使用 Qwen-Plus 模型
base_url=base_url
)
# 将模板与语言模型结合,形成各领域的任务链
physics_chain = physics_template | llm
math_chain = math_template | llm
history_chain = history_template | llm
computerscience_chain = computerscience_template | llm
2.2.3 定义动态路由逻辑
通过自定义的 RunnableLambda
定义路由逻辑,根据输入内容分配到不同任务链。
from langchain_core.runnables import RunnableLambda
# 定义动态路由逻辑
def route(input):
if "物理" in input["input"]:
return {"key": "physics", "input": input["input"]}
elif "数学" in input["input"]:
return {"key": "math", "input": input["input"]}
elif "历史" in input["input"]:
return {"key": "history", "input": input["input"]}
elif "计算机" in input["input"]:
return {"key": "computer_science", "input": input["input"]}
else:
return {"key": "default", "input": input["input"]}
# 创建路由逻辑的 Runnable
route_runnable = RunnableLambda(route)
2.2.4 定义默认处理链
当输入内容无法匹配任何任务链时,使用默认处理链处理问题。
# 定义默认处理链
default_chain = ChatPromptTemplate.from_template(
"输入内容无法归类,请直接回答:{input}"
) | llm
2.2.5 创建 RouterRunnable
将所有任务链和默认链条整合到 RouterRunnable
中,用于动态分配任务。
from langchain_core.runnables import RouterRunnable
# 创建 RouterRunnable
router = RouterRunnable(
runnables={
"physics": physics_chain,
"math": math_chain,
"history": history_chain,
"computer_science": computerscience_chain,
"default": default_chain
}
)
2.2.6 创建完整的 Router Chain
通过 RunnableSequence
将路由逻辑与任务链整合为一个完整的 Router Chain
。
from langchain_core.runnables import RunnableSequence
# 创建完整的 Router Chain
router_chain = RunnableSequence(route_runnable, router)
2.2.7 测试 Router Chain
为 Router Chain 提供示例输入,验证动态分配逻辑是否正确。
# 定义示例输入
inputs = [
{"input": "什么是黑体辐射?"}, # 物理问题
{"input": "计算 2 + 2 的结果。"}, # 数学问题
{"input": "介绍一次世界大战的背景。"}, # 历史问题
{"input": "如何实现快速排序算法?"} # 计算机科学问题
]
# 执行 Router Chain 并输出结果
for inp in inputs:
result = router_chain.invoke(inp)
print(f"问题:{inp['input']}\n回答:{result.content}\n")
2.3 完整代码
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.runnables import RouterRunnable, RunnableLambda, RunnableSequence
# 加载 .env 文件中的环境变量
load_dotenv()
# 从环境变量中获取 API Key 和 Base URL
api_key = os.getenv("ALIYUN_API_KEY")
base_url = os.getenv("ALIYUN_API_URL")
# 初始化语言模型
llm = ChatOpenAI(
openai_api_key=api_key,
model_name="qwen-plus", # 使用 Qwen-Plus 模型
base_url=base_url
)
# Step 1: 定义各领域的任务模板
# 定义物理任务模板
physics_template = ChatPromptTemplate.from_template(
"你是一位物理学教授,擅长用简洁易懂的方式回答物理问题。以下是问题内容:{input}"
)
# 定义数学任务模板
math_template = ChatPromptTemplate.from_template(
"你是一位数学家,擅长分步骤解决数学问题,并提供详细的解决过程。以下是问题内容:{input}"
)
# 定义历史任务模板
history_template = ChatPromptTemplate.from_template(
"你是一位历史学家,对历史事件和背景有深入研究。以下是问题内容:{input}"
)
# 定义计算机科学任务模板
computerscience_template = ChatPromptTemplate.from_template(
"你是一位计算机科学专家,擅长算法、数据结构和编程问题。以下是问题内容:{input}"
)
# Step 2: 将模板与语言模型结合,形成任务链
physics_chain = physics_template | llm
math_chain = math_template | llm
history_chain = history_template | llm
computerscience_chain = computerscience_template | llm
# Step 3: 定义动态路由逻辑
def route(input):
if "物理" in input["input"]:
return {"key": "physics", "input": input["input"]}
elif "数学" in input["input"]:
return {"key": "math", "input": input["input"]}
elif "历史" in input["input"]:
return {"key": "history", "input": input["input"]}
elif "计算机" in input["input"]:
return {"key": "computer_science", "input": input["input"]}
else:
return {"key": "default", "input": input["input"]}
# 创建路由逻辑的 Runnable
route_runnable = RunnableLambda(route)
# 定义默认处理链
default_chain = ChatPromptTemplate.from_template(
"输入内容无法归类,请直接回答:{input}"
) | llm
# Step 4: 创建 RouterRunnable
router = RouterRunnable(
runnables={
"physics": physics_chain,
"math": math_chain,
"history": history_chain,
"computer_science": computerscience_chain,
"default": default_chain
}
)
# Step 5: 创建完整的 Router Chain
router_chain = RunnableSequence(route_runnable, router)
# Step 6: 测试 Router Chain
# 定义示例输入
inputs = [
{"input": "什么是黑体辐射?"}, # 物理问题
{"input": "计算 2 + 2 的结果。"}, # 数学问题
{"input": "介绍一次世界大战的背景。"}, # 历史问题
{"input": "如何实现快速排序算法?"} # 计算机科学问题
]
# 执行 Router Chain 并输出结果
for inp in inputs:
result = router_chain.invoke(inp)
print(f"问题:{inp['input']}\n回答:{result.content}\n")
2.4 输出示例
根据输入内容,Router Chain 将问题分配到合适的任务链,并生成对应的答案。例如:
-
输入:
"什么是黑体辐射?"
输出:"黑体辐射是一个理想黑体发出的电磁辐射,其能量分布与温度相关。"
-
输入:
"计算 2 + 2 的结果。"
输出:"2 + 2 的结果是 4。"
-
输入:
"介绍一次世界大战的背景。"
输出:"一次世界大战的爆发是由于帝国主义竞争、民族主义以及萨拉热窝事件的直接影响。"
-
输入:
"如何实现快速排序算法?"
输出:"快速排序是一种分治算法,核心步骤包括选择基准值、分区操作和递归调用子序列排序。"
2.5 注意事项
-
路由逻辑的扩展性:
- 如果需要支持更多领域,可以在
route
函数中添加相应的逻辑,并新增任务链条。
- 如果需要支持更多领域,可以在
-
默认处理链的重要性:
- 确保所有输入都有处理结果,未分类问题可以通过默认链解决。
-
任务描述的清晰性:
- 确保每个模板内容精准描述其领域,避免交叉或冲突。
三、总结
本文全面解析了 LangChain 的两大核心功能模块:基础链条构建与动态任务分配,并通过具体示例演示了它们的强大应用。以下是本文的核心要点总结:
3.1 LangChain 的核心链简介
-
单任务 Prompt 模型结合:
- 使用
ChatPromptTemplate
和ChatOpenAI
快速构建单任务处理链条,例如生成广告语和回答简单问题。 - 示例代码展示了如何通过简单的输入实现动态化输出,体现了模块的灵活性。
- 使用
-
管道组合实现多步骤任务:
- 通过
Pipe Operator
(|
)将多个任务串联,构建线性任务链,实现如品牌命名与简介生成等复杂逻辑。 - 每个任务模块独立、清晰,可轻松扩展或修改。
- 通过
-
RunnableSequence 构建复杂链条:
- 借助
RunnableSequence
模块,将多步骤任务串联为更高级的复杂链条。 - 示例展示了如何根据用户输入偏好,动态生成餐厅推荐,并总结推荐内容,解决实际应用中的多步骤问题。
- 借助
3.2 Router Chain:任务分配与动态路由
-
动态任务分配的核心机制:
- 基于
RouterRunnable
和RunnableLambda
,实现输入内容的智能分类和任务分配。 - 自定义路由逻辑,根据输入内容将其路由到物理、数学、历史、计算机科学等不同领域的任务链。
- 基于
-
完整代码实现:
- 提供从任务模板定义到动态路由测试的完整代码,涵盖了任务链构建、自定义路由逻辑、默认处理链等所有步骤。
- 默认处理链的设计确保了所有输入都能得到合理的响应。
-
实际应用场景:
- 动态问答系统:支持多领域问题的高效解答。
- 个性化推荐系统:根据用户需求动态生成个性化内容。
- 跨学科任务处理:灵活适配复杂的自然语言处理场景。
标签:chain,任务分配,LangChain,ChatPromptTemplate,任务,template,input,链条,Router From: https://blog.csdn.net/Kiradzy/article/details/145143465