| 大家好,我是工藤学编程 🦉 | 一个正在努力学习的小博主,期待你的关注 |
|---|---|
| 实战代码系列最新文章😉 | C++实现图书管理系统(Qt C++ GUI界面版) |
| SpringBoot实战系列🐷 | 【SpringBoot实战系列】SpringBoot3.X 整合 MinIO 存储原生方案 |
| 分库分表 | 分库分表之实战-sharding-JDBC分库分表执行流程原理剖析 |
| 消息队列 | 深入浅出 RabbitMQ-RabbitMQ消息确认机制(ACK) |
| AI大模型 | 零基础学AI大模型之MultiQueryRetriever多查询检索全解析 |
前情摘要
1、零基础学AI大模型之读懂AI大模型
2、零基础学AI大模型之从0到1调用大模型API
3、零基础学AI大模型之SpringAI
4、零基础学AI大模型之AI大模型常见概念
5、零基础学AI大模型之大模型私有化部署全指南
6、零基础学AI大模型之AI大模型可视化界面
7、零基础学AI大模型之LangChain
8、零基础学AI大模型之LangChain六大核心模块与大模型IO交互链路
9、零基础学AI大模型之Prompt提示词工程
10、零基础学AI大模型之LangChain-PromptTemplate
11、零基础学AI大模型之ChatModel聊天模型与ChatPromptTemplate实战
12、零基础学AI大模型之LangChain链
13、零基础学AI大模型之Stream流式输出实战
14、零基础学AI大模型之LangChain Output Parser
15、零基础学AI大模型之解析器PydanticOutputParser
16、零基础学AI大模型之大模型的"幻觉"
17、零基础学AI大模型之RAG技术
18、零基础学AI大模型之RAG系统链路解析与Document Loaders多案例实战
19、零基础学AI大模型之LangChain PyPDFLoader实战与PDF图片提取全解析
20、零基础学AI大模型之LangChain WebBaseLoader与Docx2txtLoader实战
21、零基础学AI大模型之RAG系统链路构建:文档切割转换全解析
22、零基础学AI大模型之LangChain 文本分割器实战:CharacterTextSplitter 与 RecursiveCharacterTextSplitter 全解析
23、零基础学AI大模型之Embedding与LLM大模型对比全解析
24、零基础学AI大模型之LangChain Embedding框架全解析
25、零基础学AI大模型之嵌入模型性能优化
26、零基础学AI大模型之向量数据库介绍与技术选型思考
27、零基础学AI大模型之Milvus向量数据库全解析
28、零基础学AI大模型之Milvus核心:分区-分片-段结构全解+最佳实践
29、零基础学AI大模型之Milvus部署架构选型+Linux实战:Docker一键部署+WebUI使用
30、零基础学AI大模型之Milvus实战:Attu可视化安装+Python整合全案例
31、零基础学AI大模型之Milvus索引实战
32、零基础学AI大模型之Milvus DML实战
33、零基础学AI大模型之Milvus向量Search查询综合案例实战
33、零基础学AI大模型之新版LangChain向量数据库VectorStore设计全解析
34、零基础学AI大模型之相似度Search与MMR最大边界相关搜索实战
35、零基础学AI大模型之LangChain整合Milvus:新增与删除数据实战
36、零基础学AI大模型之LangChain+Milvus实战:相似性搜索与MMR多样化检索全解析
37、零基础学AI大模型之LangChain Retriever
38、零基础学AI大模型之MultiQueryRetriever多查询检索全解析
本文章目录
- 零基础学AI大模型之LangChain核心:Runnable接口底层实现
-
- 一、Runnable接口:LangChain组件的"统一通行证"
- 二、为什么必须懂Runnable?四大核心价值
-
- [1. 统一接口,消除兼容性壁垒](#1. 统一接口,消除兼容性壁垒)
- [2. 灵活组合,简化链式编排](#2. 灵活组合,简化链式编排)
- [3. 动态配置,提升系统鲁棒性](#3. 动态配置,提升系统鲁棒性)
- [4. 原生优化,适配高并发场景](#4. 原生优化,适配高并发场景)
- 三、底层实现原理:管道符`|`背后的秘密
-
- [1. 管道符的本质:`or`方法重写](#1. 管道符的本质:
__or__方法重写) - [2. 核心数据结构:RunnableSequence](#2. 核心数据结构:RunnableSequence)
- [3. 延迟执行机制](#3. 延迟执行机制)
- [4. invoke方法源码核心逻辑](#4. invoke方法源码核心逻辑)
- [1. 管道符的本质:`or`方法重写](#1. 管道符的本质:
- 四、Runnable核心方法:四种执行模式全覆盖
- 五、关键子类:Runnable的"功能扩展包"
-
- [1. RunnableSequence:顺序执行链](#1. RunnableSequence:顺序执行链)
- [2. RunnableBranch:条件路由链](#2. RunnableBranch:条件路由链)
- [3. RunnableParallel:并行执行链](#3. RunnableParallel:并行执行链)
- [4. RunnablePassthrough:数据透传组件](#4. RunnablePassthrough:数据透传组件)
- 六、实战:基于Runnable构建完整链路
-
- [1. 环境准备](#1. 环境准备)
- [2. 完整代码](#2. 完整代码)
- [3. 执行结果说明](#3. 执行结果说明)
- 七、总结:Runnable是LangChain的"灵魂"
零基础学AI大模型之LangChain核心:Runnable接口底层实现
一、Runnable接口:LangChain组件的"统一通行证"
Runnable接口是LangChain框架中所有可执行组件的核心抽象,相当于给所有功能模块制定了一套统一的"交互协议"。
无论是Prompt模板、大模型调用、输出解析器,还是自定义的数据处理逻辑,只要实现了Runnable接口,就能无缝融入LangChain的生态,参与链式调用。
其核心定义来自langchain_core.runnables模块,所有组件通过实现它的标准方法,实现了"即插即用"的模块化能力。
二、为什么必须懂Runnable?四大核心价值

1. 统一接口,消除兼容性壁垒
所有LangChain组件(PromptTemplate、ChatModel、OutputParser等)都遵循同一套Runnable规范,无需关心组件内部实现,只需关注输入输出格式。
2. 灵活组合,简化链式编排
通过管道符|就能快速串联多个Runnable组件,形成复杂的业务流程,类似数据流处理的方式,大幅降低代码复杂度。
3. 动态配置,提升系统鲁棒性
支持运行时参数绑定、组件热替换,还能通过with_retry()等机制实现错误恢复,让系统更灵活、更稳定。
4. 原生优化,适配高并发场景
内置异步方法(ainvoke)和并行处理能力(RunnableParallel),无需额外开发就能应对高并发、大数据量的使用场景。
三、底层实现原理:管道符|背后的秘密

1. 管道符的本质:__or__方法重写
LangChain的管道符|并非Python原生功能,而是通过重写Runnable类的__or__魔术方法实现的。
当我们写下prompt | model | output_parser时,实际是触发了__or__方法,将多个Runnable组件传入RunnableSequence的构造函数,最终形成一个线性执行的链。
2. 核心数据结构:RunnableSequence
RunnableSequence是Runnable的核心子类,专门负责管理顺序执行的组件链。
它会将串联的组件存储在内部的steps列表中,执行时按顺序遍历列表,调用每个组件的对应方法(如invoke),并将上一个组件的输出作为下一个组件的输入,形成单向数据流。
3. 延迟执行机制
链的构建过程(prompt | model | output_parser)仅定义了组件间的逻辑关系,不会立即执行。
只有当调用invoke、stream等执行方法时,才会触发整个链路的运行,支持动态传入参数和运行时配置。
4. invoke方法源码核心逻辑
python
def invoke(
self, input: Input, config: Optional[RunnableConfig] = None, **kwargs: Any
) -> Output:
# 遍历所有步骤,顺序执行
try:
for i, step in enumerate(self.steps):
# 为每个步骤标记子任务,便于日志和回调
config = patch_config(
config, callbacks=run_manager.get_child(f"seq:step:{i + 1}")
)
with set_config_context(config) as context:
# 第一个步骤传入原始输入和kwargs,后续步骤传入上一步输出
if i == 0:
input = context.run(step.invoke, input, config, **kwargs)
else:
input = context.run(step.invoke, input, config)
return input
except Exception as e:
# 错误处理逻辑
raise e
核心逻辑总结:
- 按顺序执行
steps列表中的每个组件 - 为每个步骤分配独立的配置和回调,便于追踪
- 第一个组件接收完整输入,后续组件接收前序输出
- 统一的错误捕获机制,确保链路稳定性
四、Runnable核心方法:四种执行模式全覆盖
Runnable接口定义了四种核心执行方法,适配不同的业务场景,所有实现类都需遵守该规范。
| 方法名 | 执行模式 | 适用场景 | 核心特点 |
|---|---|---|---|
invoke() |
同步执行 | 单次调用、简单链路 | 阻塞等待完整结果,代码简洁 |
ainvoke() |
异步执行 | 高并发场景、异步系统集成 | 非阻塞,支持异步await,提升吞吐量 |
stream() |
流式输出 | 实时响应、大文本生成 | 逐块返回结果,减少等待时间 |
batch() |
批量执行 | 数据集处理、批量推理 | 一次性处理多个输入,效率更高 |
方法使用示例(核心代码)
python
# 1. invoke():同步单次执行
result = chain.invoke({"question": "LangChain是什么?"})
# 2. ainvoke():异步执行(需在async函数中使用)
async def async_run():
result = await chain.ainvoke({"question": "LangChain是什么?"})
# 3. stream():流式输出
for chunk in chain.stream({"question": "LangChain是什么?"}):
print(chunk, end="", flush=True)
# 4. batch():批量执行
inputs = [
{"question": "LangChain是什么?"},
{"question": "Runnable接口的作用?"},
{"question": "如何串联LangChain组件?"}
]
results = chain.batch(inputs)
五、关键子类:Runnable的"功能扩展包"
除了基础的Runnable接口,LangChain还提供了多个实用子类,覆盖常见的业务场景,无需重复造轮子。
1. RunnableSequence:顺序执行链
- 核心作用:实现组件的线性串联,是
|管道符的默认实现 - 适用场景:按固定顺序执行的流程(如Prompt→模型→解析器)
- 特点:单向数据流,步骤不可跳过
2. RunnableBranch:条件路由链
- 核心作用:根据输入条件选择不同的执行分支
- 适用场景:多场景适配(如不同问题类型对应不同Prompt)
- 特点:支持动态分支选择,类似
if-elif-else逻辑
3. RunnableParallel:并行执行链
- 核心作用:多个组件并行执行,互不依赖
- 适用场景:多任务同时处理(如同时查询多个数据源)
- 特点:提升执行效率,结果以字典形式返回
4. RunnablePassthrough:数据透传组件
- 核心作用:透传输入数据,或添加固定参数
- 适用场景:补充额外上下文、保持输入结构不变
- 特点:不修改核心数据,仅做扩展或透传
六、实战:基于Runnable构建完整链路
下面通过一个完整案例,展示Runnable接口的实际应用,实现"Prompt构建→模型调用→结果解析"的全流程。
1. 环境准备
bash
pip install langchain langchain-openai pydantic
2. 完整代码
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from langchain_core.runnables import RunnableSequence
# 1. 定义输出格式(Pydantic模型)
class AnswerSchema(BaseModel):
question: str = Field(description="用户的原始问题")
answer: str = Field(description="大模型的回答内容")
summary: str = Field(description="回答的核心摘要(不超过50字)")
# 2. 初始化组件(均实现Runnable接口)
prompt = ChatPromptTemplate.from_messages([
("system", "请详细回答用户问题,并提炼核心摘要"),
("human", "{question}")
])
model = ChatOpenAI(model="gpt-3.5-turbo", api_key="你的API密钥")
parser = PydanticOutputParser(pydantic_object=AnswerSchema)
# 3. 构建Runnable链(两种方式等价)
# 方式1:管道符串联(推荐)
chain = prompt | model | parser
# 方式2:显式创建RunnableSequence
chain = RunnableSequence(steps=[prompt, model, parser])
# 4. 调用Runnable方法执行
if __name__ == "__main__":
# 同步执行
result = chain.invoke({"question": "Runnable接口的核心价值是什么?"})
print("同步执行结果:")
print(f"问题:{result.question}")
print(f"回答:{result.answer}")
print(f"摘要:{result.summary}\n")
# 流式执行
print("流式执行结果:")
for chunk in chain.stream({"question": "Runnable接口有哪些核心方法?"}):
if chunk:
print(chunk, end="", flush=True)
# 批量执行
print("\n\n批量执行结果:")
inputs = [
{"question": "invoke方法的作用?"},
{"question": "stream方法的适用场景?"}
]
results = chain.batch(inputs)
for idx, res in enumerate(results, 1):
print(f"\n第{idx}个结果:")
print(f"问题:{res.question}")
print(f"摘要:{res.summary}")
3. 执行结果说明
- 同步执行(
invoke):一次性返回完整的解析后结果,结构清晰 - 流式执行(
stream):逐块返回解析后的对象,适合实时展示 - 批量执行(
batch):一次性处理多个输入,效率高于多次invoke
七、总结:Runnable是LangChain的"灵魂"
Runnable接口通过统一的抽象定义,解决了LangChain组件的兼容性和组合性问题,是整个框架的核心基石。
核心要点回顾:
- Runnable是所有组件的统一接口,定义了标准的执行方法
- 管道符
|本质是__or__方法重写,背后由RunnableSequence支撑 - 四大核心方法(invoke/ainvoke/stream/batch)覆盖不同执行场景
- 丰富的子类(RunnableBranch/RunnableParallel等)降低复杂逻辑开发成本
理解Runnable的底层实现,能帮助我们更灵活地构建自定义组件、优化链路性能,为复杂大模型应用打下坚实基础。
如果这篇文章对你有帮助,别忘了点赞关注哦!😊