纲要
Runnable接口- 基于
Pydantic的输入输出类型约定 - 标准调用方法:
invoke、batch、stream、ainvoke、abatch、astream RunnableConfig:运行时动态配置(回调、标签、元数据、最大并发数)- 所有 LangChain 核心组件均实现该接口
- 基于
- LCEL(LangChain Expression Language)
- 管道操作符
|实现顺序组合 RunnableSequence与RunnableParallel- 并行编排与顺序编排的行为差异
- 惰性求值与流式传输支持
- 管道操作符
- 适用场景与选型建议
- 线性流程:LCEL 最佳实践
- 复杂分支/循环/多智能体:推荐
LangGraph - 旧版预制链(
LLMChain、ConversationChain等)迁移策略
- 完整可运行示例
- 使用
FakeListChatModel模拟大模型,无需 API Key - 顺序链与并行链的对比实现
- 使用
- 版本要求
langchain-core >= 0.1.0,langchain >= 0.2.0
引言
LangChain 的核心设计理念是将不同的处理单元(提示词模板、大语言模型、输出解析器等)串联为可组合的处理流水线。在 v0.2.0 版本之后,LangChain 引入了一套统一的组件协议——Runnable 接口,并基于该接口构建了声明式的编排语言 LCEL(LangChain Expression Language)。
Runnable 接口为所有组件定义了标准化的交互契约,而 LCEL 则通过管道操作符 | 提供了直观的链式组合能力。理解二者的设计哲学与实现细节,是高效编排 LLM 工作流的基础,也是将旧版预制链(如 LLMChain、ConversationChain)平滑迁移至现代链式开发框架的关键路径。
Runnable 接口:组件通信的标准协议
统一的输入输出约定
LangChain 中所有标准组件(提示词模板、聊天模型、LLM、输出解析器、检索器、工具等)均实现了 Runnable 接口。该接口对每个组件的输入类型和输出类型做出了明确约定,确保不同组件之间能够无缝衔接:
- 提示词模板(
ChatPromptTemplate、PromptTemplate):接受dict类型的输入(包含模板变量),输出PromptValue或其子类实例,可被聊天模型或 LLM 直接消费。 - 聊天模型(
BaseChatModel):接受BaseMessage、BaseMessage序列或PromptValue,输出BaseMessage或其子类(如AIMessage)。 - 输出解析器(
BaseOutputParser):输入为上一环节的输出(如AIMessage的文本内容),输出类型取决于具体解析器实现(str、dict、Pydantic模型等)。
上述类型约束基于 Pydantic 实现,能够在开发阶段提前捕获类型不匹配问题,避免运行时因数据格式错误导致的异常。
标准调用方法
Runnable 接口定义了一套统一的调用入口,所有实现该接口的组件均支持以下核心方法:
| 方法 | 说明 |
|---|---|
invoke(input, config=None) | 同步单次调用,返回计算结果 |
batch(inputs, config=None) | 同步批量调用,输入为列表,返回列表 |
stream(input, config=None) | 同步流式输出,逐块返回结果 |
ainvoke(input, config=None) | 异步单次调用 |
abatch(inputs, config=None) | 异步批量调用 |
astream(input, config=None) | 异步流式输出 |
这些方法使得任意 Runnable 组件都可以被统一调用、替换和组合,开发者无需关心底层实现差异,极大降低了模块间的耦合度。
RunnableConfig:运行时动态配置
每个 Runnable 方法均可接收一个可选的 RunnableConfig 参数,用于在调用时注入运行时配置信息,包括但不限于:
- 回调函数(
callbacks):支持在链的执行生命周期中插入自定义逻辑(日志、追踪、指标上报等)。 - 标签(
tags):为本次调用添加标签,用于过滤和分类追踪数据。 - 元数据(
metadata):附加自定义键值对,便于链路追踪与调试。 - 最大并发数(
max_concurrency):限制batch调用时的并发度。 - 可配置字段(
configurable):动态覆盖链中特定组件的参数(如提示词模板变量、模型温度等)。
RunnableConfig 为链式调用的可观测性和动态配置提供了标准化通道。
LCEL:简洁的链式编排语言
LCEL 是基于 Runnable 接口构建的领域特定语言(DSL),其核心目标是通过声明式语法将多个 Runnable 组件组合为可执行链,同时保留对流式传输、批量处理和异步调用的完整支持。
管道操作符与顺序组合
通过管道操作符 | 可以将任意两个 Runnable 串联为顺序执行链,数据从左至右依次流经每个组件:
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_community.chat_models import ChatOpenAI
model = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("用中文解释:{topic}")
parser = StrOutputParser()
# 管道组合
chain = prompt | model | parser
# 等价写法:RunnableSequence
# from langchain_core.runnables import RunnableSequence
# chain = RunnableSequence(first=prompt, middle=[model], last=parser)
# 等价写法:pipe 方法
# chain = prompt.pipe(model).pipe(parser)
无论链的长度如何,组合后的 chain 本身仍然是 Runnable 实例,可以继续与其他组件组合或直接调用其标准方法。
LCEL 组合的另一个关键特性是惰性求值:| 操作符仅构建计算图,不立即执行任何计算。实际执行发生在调用 invoke、batch、stream 等方法时,这使得链的构建与执行完全解耦。
并行组合
RunnableParallel 允许将多个分支并行执行,并将各分支的输出汇总为单一字典。它接受一个字典,其中每个键对应一个独立的 Runnable 子链。
同步模式下,RunnableParallel.invoke() 按字典序(Python 3.7+ 字典保持插入顺序)依次执行各分支,并非真正的多线程并行;异步模式(ainvoke)下则同时调度多个协程,可实现真正的并发执行。
from langchain_core.runnables import RunnableParallel
# 构建两个独立的顺序链
chinese_chain = chinese_prompt | model | StrOutputParser()
english_chain = english_prompt | model | StrOutputParser()
# 并行组合(同步模式下顺序执行各分支,异步模式下并发执行)
parallel_chain = RunnableParallel(
chinese=chinese_chain,
english=english_chain
)
# 同步调用
result = parallel_chain.invoke({"topic": "AI Agent"})
# 输出: {"chinese": "...", "english": "..."}
RunnableParallel 的典型应用场景包括:
- 同一输入需要多种不同处理方式(如多语言翻译、多模型投票)
- 数据增强(同时从多个检索器获取上下文)
- 监控与副流程(主链执行的同时记录日志或指标)
使用场景与选型建议
| 场景特征 | 推荐方案 | 理由 |
|---|---|---|
| 线性流程(提示词 → 模型 → 解析器) | LCEL | 代码简洁、原生支持流式和批处理 |
| 简单条件路由(if-else 分支) | LCEL 配合 RunnableBranch | 内置支持,但仅适合分支较少的情况 |
| 复杂循环、状态管理、多智能体协作 | LangGraph | 基于图的状态机,支持确定性循环和持久化 |
| 旧版预制链迁移 | LCEL 或 LangGraph 重写 | 获得完全的灵活性和可观测性 |
LCEL 在处理线性流程时表现最佳,代码可读性高且易于维护。当流程中包含嵌套循环、动态条件分支或多个智能体之间的消息传递时,LangGraph 提供了更强大的图编排能力,允许以状态图的方式精确控制执行流。两种方案均由 LangChain 官方维护,开发者可根据实际复杂度灵活选择。
API 速览
langchain_core.runnables.Runnable
所有 Runnable 组件的基类。
核心方法签名:
invoke(input: Any, config: Optional[RunnableConfig] = None) -> Anybatch(inputs: List[Any], config: Optional[RunnableConfig] = None) -> List[Any]stream(input: Any, config: Optional[RunnableConfig] = None) -> Iterator[Any]ainvoke(input: Any, config: Optional[RunnableConfig] = None) -> Awaitable[Any]abatch(inputs: List[Any], config: Optional[RunnableConfig] = None) -> Awaitable[List[Any]]astream(input: Any, config: Optional[RunnableConfig] = None) -> AsyncIterator[Any]pipe(other: Runnable) -> RunnableSequence
langchain_core.runnables.RunnableSequence
由 | 操作符或 RunnableSequence 构造器生成的顺序链。
构造方式:
from langchain_core.runnables import RunnableSequence
# 方式一:管道操作符
chain = step1 | step2 | step3
# 方式二:显式构造
chain = RunnableSequence(first=step1, middle=[step2], last=step3)
langchain_core.runnables.RunnableParallel
并行执行多个分支,汇总结果。
构造方式:
from langchain_core.runnables import RunnableParallel
parallel = RunnableParallel(
branch_a=chain_a,
branch_b=chain_b,
)
返回值类型:Dict[str, Any],键与构造时的参数名一致。
langchain_core.runnables.RunnableConfig
运行时配置对象。
主要字段:
callbacks: Optional[Callbacks]:回调处理器tags: Optional[List[str]]:标签列表metadata: Optional[Dict[str, Any]]:元数据max_concurrency: Optional[int]:最大并发数configurable: Optional[Dict[str, Any]]:可动态覆盖的字段
完整 Demo
以下示例使用 FakeListChatModel 模拟大模型行为,无需真实 API Key,可直接运行以体验 LCEL 的顺序链与并行链编排。
运行说明
- 安装依赖:
pip install langchain langchain-core langchain-community
-
将以下代码保存为
lcel_demo.py。 -
运行脚本:
python lcel_demo.py
完整代码
# lcel_demo.py
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableParallel, RunnableConfig
from langchain_community.chat_models.fake import FakeListChatModel
def main() -> None:
# ---------- 1. 准备模拟模型 ----------
# 预设回答列表:第一次调用返回中文,第二次返回英文
responses = [
"AI Agent 是能够感知环境并采取行动以实现目标的智能体。",
"An AI Agent is an intelligent entity that perceives its environment and takes actions to achieve goals."
]
model = FakeListChatModel(responses=responses)
# ---------- 2. 构建顺序链 ----------
chinese_prompt = ChatPromptTemplate.from_template("用中文简单解释:{topic}")
chinese_chain = chinese_prompt | model | StrOutputParser()
english_prompt = ChatPromptTemplate.from_template("Briefly explain in English: {topic}")
english_chain = english_prompt | model | StrOutputParser()
# ---------- 3. 并行链:中英文同时解释 ----------
parallel_chain = RunnableParallel(
chinese=chinese_chain,
english=english_chain
)
# ---------- 4. 调用并行链 ----------
result = parallel_chain.invoke({"topic": "AI Agent"})
print("并行输出:")
print("中文:", result["chinese"])
print("英文:", result["english"])
# ---------- 5. 单独调用顺序链 ----------
print("\n顺序链单独调用:")
print(chinese_chain.invoke({"topic": "Runnable 接口"}))
if __name__ == "__main__":
main()
代码说明
FakeListChatModel按顺序返回预设的响应列表,第一次调用返回第一个元素,第二次返回第二个,以此类推。在并行链中,chinese_chain和english_chain分别调用模型,故模型按顺序依次返回中文和英文预设内容。RunnableParallel将输入{"topic": "AI Agent"}同时传递给两个子链,最终汇聚为包含chinese和english键的字典。- 该示例展示了 LCEL 的声明式组合能力,无需显式编写循环或条件语句,即可实现多路并发处理。
技术点总结
Runnable接口的统一调用协议RunnableParallel的多分支并发编排FakeListChatModel的模拟测试用法- LCEL 的惰性求值特性(
|仅构建图,不执行)
参考文档
官方文档
- LangChain Runnable 概念文档
- LangChain LCEL 概念文档
- LangChain Runnable API 参考
- LangChain RunnableParallel API 参考
参考链接
总结
本文系统阐述了 LangChain 中 Runnable 接口与 LCEL 的设计原理与使用方法。Runnable 为所有组件提供了标准化的输入输出类型和统一调用方法(invoke、batch、stream 及其异步版本),并支持通过 RunnableConfig 实现运行时动态配置。
LCEL 基于 Runnable 构建,通过管道操作符 | 实现顺序组合,通过 RunnableParallel 实现并行编排,其惰性求值特性使链的构建与执行解耦,同时保留了完整的流式和批处理能力。
对于线性流程,LCEL 提供了最简洁的实现方式;对于复杂的分支、循环或多智能体场景,LangGraph 可作为补充工具。掌握这一套组合拳,将显著提升 LLM 应用开发的效率与可维护性。
1674



被折叠的 条评论
为什么被折叠?



