在这里插入图片描述

文章目录


课程导读 & 学习目标

在前面的课程中,我们已经构建了完整的LangChain技术栈。第5-8课我们练就了精准的"提示词手艺",第9课我们理清了RunnableSequence的本质。但大多数真实业务永远不是"Prompt → LLM → 输出"这一刀切的线性流程——它可能同时包含"先总结后翻译"的多步传递,也可能根据用户意图分发给不同的处理路径。这些任务编排能力,才是LangChain区别于纯openai.Completion.create调用的核心竞争力。

本节课,你将站在LangChain 0.3.x的思维高度,从经典SequentialChain(旧版顺序链)到现代LCEL流水线,再到RunnableBranch智能路由,系统掌握LangChain中编排多条执行链的核心能力。我会带你亲身经历这些组件的历史演变,并在LCEL的基础上构建功能更强大、可观测性更强的多任务智能分发系统。

学完本节课,你将达到以下目标:

  1. 透彻理解顺序链的两种形态:掌握SimpleSequentialChain(单输入单输出)的适用场景、局限性,以及它与更通用的SequentialChain(多输入多输出)之间的对比。
  2. 精通LCEL的多步编排语法:用RunnableSequence实现顺序步骤,掌握RunnableParallel并行分组执行,熟练使用RunnableLambda完成中间数据映射。
  3. 彻底掌握路由链核心机制:理解RunnableBranch条件分发的工作原理,并掌握"先分类→后路由"的标准两段式架构。
  4. 理解废弃Chain类的迁移路径:掌握从旧版SimpleSequentialChainSequentialChainLLMRouterChainRunnableSequenceRunnableBranch的完整演进路径。
  5. 完成四个完整项目实战:从简单的顺序链、多依赖顺序链,到并行数据处理,再到大规模多任务智能分发路由链。

前置知识与环境准备

1.1 Python版本与开发工具

继续使用前几课的langchain_course虚拟环境,确保Python 3.10+。

1.2 依赖包安装

# 激活虚拟环境
source venv/bin/activate  # Mac/Linux
# venv\Scripts\activate   # Windows

# 基础依赖
pip install langchain==0.3.7 langchain-core==0.3.21 langchain-openai==0.2.8 python-dotenv==1.0.1

# 验证安装
python -c "from langchain_core.runnables import RunnableSequence, RunnableBranch, RunnableParallel, RunnableLambda; print('✓ LCEL组合组件导入成功')"

1.3 API密钥与模型选择

沿用前几课的.env配置(智谱GLM-4或Ollama本地模型)。本节课编排逻辑不涉及模型种类特殊限制,本地模型可流畅运行。

核心概念深度拆解

2.1 什么是Chain——LangChain中的"执行管道"

如果把PromptTemplateChatModelOutputParser比作AI应用工具箱里的三把"精密改锥"——它们功能单一但超好用。那么,本节课要介绍的Chain(链) 就是那把"多功能螺丝刀头":它允许你把多个改锥头串联成一个完整的工序流程,一次扭转一颗螺丝。

从LangChain 0.3.x的视角重新定义Chain,这句话最为精确:Chain就是一个RunnableSequence——由多个Runnable组件通过|管道符串联而成的线性数据管道。

这个定义揭示了现代Chain的两个本质特征:

  • 组件即Runnable —— Chain的每一个构成单元(提示模板、模型、解析器、自定义函数)都实现了Runnable接口,意味着它天生具备.invoke().stream().batch()三种标准调用方式。
  • |即拼接 —— 管道符|在底层对应RunnableSequence的构造,输出类型兼容是数据流转的前提,前一步的输出必须能被后一步的输入接收。

2.2 废弃的旧世界:SimpleSequentialChain与SequentialChain

LangChain早期版本,开发者往往通过SimpleSequentialChainSequentialChain这两个类来实现多步骤流水线。前者将多个LLMChain串联成一个单输入/单输出链,一条链的输出直接作为下一条链的输入。后者则更通用,允许多输入/多输出,需要在每个步骤中手动指定输入映射和输出映射,配置起来较为繁琐。

这两个旧式Chain的核心问题在于:

  • 继承自LLMChain体系 —— LLMChain本身已在v0.1.17被标记为废弃,将在v1.0中被彻底移除。
  • 灵活性与扩展性严重不足 —— 无法与现代LCEL生态无缝集成,难以实现条件分支、流式输出等先进特性。
  • 代码冗余且可读性差 —— 相比于prompt | model | parser,旧式写法需要大量样板代码。

2.3 现代的RunnableSequence——LCEL顺序编排范式

LCEL的出现重新定义了LangChain中的Chain构建方式。它通过管道符|以声明式描述数据流转,一条链的构建完全类比Unix Shell的管道操作——输入从最左端流入,从最右端流出。LangChain官方将LCEL称为"Unix pipes for AI"。

LCEL构建的链具备以下核心优势:支持流式输出、批处理、异步调用等高级功能,且与LangChain所有新组件无缝集成。

2.4 路由链(Routing)——根据上下文智能分发

当单一流水线无法满足多元化业务场景时,需要路由链来根据用户输入自动选择执行路径。典型的场景包括:

  • 意图分流:用户问数学题走"数学专家子链",问SQL查询走"数据库子链"
  • 成本控制:轻量级问题走廉价模型,复杂推理才调用高性能模型
  • 多用户角色匹配:普通用户走通用提示,VIP用户走定制化场景

RunnableBranch是LangChain官方提供的条件分发组件,它设计为链式的if/elif/else执行器。执行时从左到右依次评估各分支的条件函数,命中第一个返回True的分支即执行对应子链,无命中则执行默认分支。

2.5 并行执行链——多个独立任务同时处理

当流程中的某些步骤互不依赖时,可同时执行以提高效率。LCEL通过RunnableParallel实现这种并行模式,接收一个字典,键值各自对应独立的Runnable。执行时所有键值Runnable并发运行,结果合并为字典输出,然后将完整数据交给后续组件处理。

底层运行原理剖析

3.1 LCEL链的执行路径追踪

一条典型的prompt | model | parser链在执行invoke时具体发生了什么?前一个组件的原始输出不会直接流入下一个组件,数据经过的中间转换过程对于链式编排至关重要:

  • 提示模板 (Runnable):接收用户输入字典,按模板填充{variable}占位符,生成字符串格式的提示词。
  • 模型 (ChatModel):接收字符串提示词,发送HTTP请求,返回AIMessage对象。
  • 解析器 (OutputParser):接收AIMessage,提取.content属性,返回纯字符串。

RunnableSequence在这个链条中扮演"指挥者"的角色:接收到外部输入后,依次调用列表中的每个Runnable的invoke方法,并用前者的输出作为后者的输入。

3.2 RunnableBranch的条件匹配机制

RunnableBranch以闭包形式捕获条件函数和对应子链。执行时,invoke方法将输入逐一遍历条件函数,一旦某条件返回True,即调用对应子链的invoke,直接返回其结果,不再检查剩余分支。若无分支匹配,则调用默认子链。若未配置默认分支也无匹配,抛出异常。

3.3 RunnableParallel的并发调度

RunnableParallel初始化时接收一个字典,每个键值代表一个Runnable及其参数。当invoke被调用时,它会同时并发执行字典中所有的Runnable任务,待全部任务完成后,将所有结果按原键名合并为一个字典,并作为最终输出。此模式对于同时查询多个知识库、调用多个独立API等场景极为适用,可有效降低整体延迟。

核心API/组件源码解读

4.1 RunnableSequence——串联一切Runnable

RunnableSequence接收任意数量的Runnable对象,按顺序存入列表。

4.2 RunnableBranch——条件分发器

RunnableBranch接收条件函数+子链对列表,并附带一个默认子链。invoke执行时遍历所有条件函数,调用它们并传入当前输入,若函数返回True则立即调用对应子链并返回结果。若无匹配,执行默认子链。

条件函数可以是普通的Pythonlambda表达式,也可以是任何可调用对象。分支的顺序决定了优先级,因此通常应将最具体、最严格的条件放在最前面。

4.3 RunnableParallel——并发调度器

RunnableParallel将输入同时分发到多个可运行链中。初始化接收一个字典,定义多个任务,键名会在结果字典中保留。执行时所有任务并发运行,完成后将各分支的输出按字典形式合并输出。

4.4 RunnableLambda——纯函数转Runnable

RunnableLambda包装普通Python函数为Runnable对象。当输入数据需要清洗或数据格式转换时,这是一个轻量又灵活的办法,无需定义复杂的自定义类。

4.5 旧路由模块的废弃与演进

LLMRouterChainMultiRouteChain等旧路由类在LangChain v0.1中曾被广泛使用,现已被官方标记为deprecated,并在v1.0中彻底移除。现代路由标准方案是:用RunnableBranch实现条件路由,被路由到的子链即为LCEL风格的RunnableSequence

手把手项目实战教学

实战一:多步顺序链——“先大纲再写作”

目标:构建两级顺序链,第一步生成短视频脚本大纲,第二步基于大纲扩展出完整视频脚本。体验子链输入输出如何序列传递

实战二:顺序链中的多步数据映射——“先总结再翻译”

目标:先对长文本生成中文摘要,再将摘要翻译成英文。这是一条完全线性的两步链:第一步的输出作为第二步的输入,不需要额外的数据映射逻辑。

实战三:RunnableParallel并行执行——多源信息同时处理

目标:同时询问三个AI专家对"可再生能源"的看法,一次性并发获取所有专家的回答。通过RunnableParallel显式定义并行分支,将所有专家独立的推理任务并发执行。

实战四:RunnableBranch多任务智能客服路由链

目标:构建智能路由系统,根据用户问题的类别(技术/产品/售后/其他),自动将请求分发到不同的子链处理。架构清晰分为两个阶段:先调用分类器提取意图关键词,再通过RunnableBranch路由。

分类器本身就是一个极简单的prompt | model | parser链,输出意图类别。主路由组件接收分类结果后,根据类别执行相应的子链。这种设计使得路由逻辑与业务逻辑彻底解耦。

完整可运行Python代码

首次运行时,请确保激活虚拟环境并已安装依赖,同时配置好.env文件中的API密钥。

环境依赖安装命令

# 激活虚拟环境
source venv/bin/activate  # Mac/Linux
# venv\Scripts\activate   # Windows

# 核心依赖(确保0.3.x版本)
pip install langchain==0.3.7 langchain-core==0.3.21 langchain-openai==0.2.8 python-dotenv==1.0.1

# 仅当使用本地Ollama模型时才安装此包
pip install langchain-ollama

# 一键安装所有依赖
pip install langchain==0.3.7 langchain-core==0.3.21 langchain-openai==0.2.8 python-dotenv==1.0.1 langchain-ollama

常见报错坑点与避坑方案

坑1:TypeError: 'AIMessage' object is not callable 链组合出错

现象:链中出现TypeError,错误指向AIMessage不可调用。

原因:链中直接拼接了model对象和后续组件,但LCEL的|运算符要求右侧必须是Runnable。由于AIMessage不是Runnable,管道操作会失败。

解决:在model之后总是通过StrOutputParser()JsonOutputParser()将模型输出解析为基本类型。

坑2:路由链命中分支不符合预期

现象:条件函数明明匹配,却走了默认路径。

原因RunnableBranch的条件函数必须能接收当前输入作为唯一参数。多数错误都是传入方式不一致引起——输入是字符串时,条件函数应直接检查x,而不是从字典取值。

解决:仔细检查条件函数签名和返回值类型,在分支前使用RunnableLambda打印或调试输入内容,确认输入格式与条件判断逻辑匹配。

坑3:RunnableParallel中某一分支失败,整个链崩溃

现象:并行执行时,一个API调用错误引发整个链失败。

原因RunnableParallel默认是所有任务全成功才能返回结果。

解决:为关键分支配置RunnableWithFallback兜底逻辑,或使用RunnableRetry优化重试策略。

坑4:顺序链中输出格式不兼容导致链断裂

现象prompt | model | model_2时报错,第二个模型的输入不能接收AIMessage

原因:第一个model的输出是AIMessage对象,而第二个model期望的输入是字符串或消息列表。不添加解析器直接拼接第二个模型会中断自动适配链的流程。

解决:在第一个model后添加.invoke()并配合StrOutputParser(),或者用RunnableLambda显式做映射lambda x: x.content

坑5:LangChainDeprecationWarning 提示 LLMChain 被废弃

现象:导入langchain.chains.LLMChain或使用SequentialChain时看到废弃警告。

原因LLMChain在v0.1.17中被标记为废弃,将在v1.0中移除。任何建立在此之上的旧Chain类都会触发警告并官方推荐迁移。

解决:迁移到RunnableSequenceprompt | llm。若遗留代码必须兼容,继续使用旧API但接受警告;新项目严禁使用。

本节核心知识点总结

📌 顺序链的体系演进:旧版LangChain的SimpleSequentialChain和更强大的SequentialChain已随LLMChain被标记为废弃,现代版本推荐使用LCEL的RunnableSequence范式进行顺序编排。

📌 内部组件RunnableSequence —— 通过管道符|组装任意Runnable组件形成执行链,输入从左流入,从右流出,自动获取streambatchainvoke等高级能力。

📌 并行执行RunnableParallel —— 同时执行多个分支任务并将结果合并输出。适合向多个独立知识源发送同个问题的召回场景,能显著降低整体延迟。

📌 条件路由RunnableBranch —— 实现if/elif/else条件分发。构建"先分类→后路由"的两步架构:先用轻量分类链将输入分"类",再通过RunnableBranch将任务分发给不同的子链。

📌 数据映射RunnableLambda —— 将普通Python函数包装成Runnable嵌入LCEL链中,适合做清洗数据、格式转换等中间处理。

📌 废弃组件的迁移路线图SimpleSequentialChainRunnableSequence(顺序链);LLMRouterChainRunnableBranch(路由链);所有旧Chain类都在通往LangChain 1.0的路上被清理干净。

课后练习题

选择题

1. 在现代LangChain(v0.3.x)中构建顺序链推荐的写法是?
A. SequentialChain(chains=[chain1, chain2])
B. SimpleSequentialChain(chains=[chain1, chain2])
C. chain1 | chain2
D. Chain.compose([chain1, chain2])

答案及解析:【C】。LCEL通过管道符实现RunnableSequence的组合,是LangChain 0.3.x的推荐模式。SequentialChainSimpleSequentialChain属于旧版API,已被标记为废弃。

2. 以下哪个组件最适合实现“给话题,先写大纲,再扩充内容”的两步骤执行?
A. RunnableParallel
B. RunnableLambda
C. RunnableSequence
D. RunnableBranch

答案及解析:【C】。将两个Runnable顺序拼接,前一个处理完的数据直接用于第二个。RunnableParallel为并发设计,RunnableBranch用于多条件分发,不符合需求。

3. RunnableBranch的执行顺序是?
A. 同时执行所有分支,选择最快的结果。
B. 随机选择一个分支,随机后执行。
C. 从左到右依次评估条件,命中第一个就执行对应分支。
D. 从右到左依次评估条件,命中最后一个就执行对应分支。

答案及解析:【C】。RunnableBranch严格按照声明顺序评估条件,首个条件满足的分支被执行。

简答题

4. 请分别说明RunnableSequenceRunnableParallel的适用场景,并举例。

参考答案

  • RunnableSequence:适用于严格的顺序流程,例如先调用模型生成大纲,再调用另一个模型扩充内容;或先提取JSON字段,再将字段传递给新模板。
  • RunnableParallel:适用于多个独立、互不依赖的任务同时执行,例如同时向三个知识库检索同一问题、并行调用三个不同的API。

5. 描述RunnableBranch实现条件路由的两阶段架构。

参考答案:条件路由分为两阶段:第一阶段是"意图分类阶段",用一个简单的分类链(通常一个prompt | llm | parser)分析输入,输出意图关键词。第二阶段是"路由执行阶段",RunnableBranch接收该输出,通过条件函数匹配分支,将请求分发到针对性的子链。此架构的好处是分类器与业务链解耦。若新增业务场景,只需扩展分类器输出和RunnableBranch分支,无需修改已有子链。

实践题

6. 编写代码实现RunnableBranch多分支智能客服助手。要求:

  • 用户输入"天气查询:北京"时,走天气查询分支。
  • 用户输入"计算:100*0.85"时,走数学计算分支。
  • 默认分支走通用闲聊分支。
  • 必须使用RunnableBranch实现。

参考答案

from langchain_core.runnables import RunnableBranch, RunnableLambda

def classify_weather(x):
    return "weather" in x.lower()
def classify_calc(x):
    return "计算" in x or any(op in x for op in ['+', '-', '*', '/'])

weather_chain = RunnableLambda(lambda x: f"北京天气:晴天,24℃")
calc_chain = RunnableLambda(lambda x: f"计算结果:100 * 0.85 = {100 * 0.85}")
general_chain = RunnableLambda(lambda x: f"通用回答:我收到你的消息“{x}”')

branch = RunnableBranch(
    (classify_weather, weather_chain),
    (classify_calc, calc_chain),
    general_chain
)

print(branch.invoke("天气查询:北京"))
print(branch.invoke("计算:100*0.85"))
print(branch.invoke("你好"))

🔗《30节课 LangChain 从入门到精通》系列课程导航

去订阅

🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐