在 LangChain 框架中,Runnable 是一个最核心的“底层协议(Protocol)”或“标准接口”。

在 LangChain 框架中,Runnable 是一个最核心的"底层协议(Protocol)"或"标准接口"

简单来说,LangChain 里几乎所有的核心组件(如提示词模板、大模型、输出解析器、检索器、自定义函数等),在底层都继承或实现了 Runnable 接口。它的核心思想是:"任何组件,本质上都是一个'接受输入,经过处理,产生输出'的独立任务单元。"

1. 为什么设计出 Runnable?(统一接口)

在早期的 LangChain 中,调用不同组件的命令非常混乱。调用 LLM 用 llm("..."),调用 Chain 用 chain.run(),调用检索器用 retriever.get_relevant_documents()。这导致组件之间很难优雅地拼接。

为了解决这个痛点,LangChain 提出了 Runnable 协议。它强制规定:所有组件必须统一实现以下 6 个最核心的调用方法

同步方法 异步方法(Async) 核心作用
invoke() ainvoke() 传入单个 输入,等待并获取单个输出。
batch() abatch() 批量传入一组 输入,内部自动利用线程池并发处理,返回一组输出。
stream() astream() 流式传输,大模型吐出一个词,这里就立刻返回一个词,常用于打字机流式前端交互。

2. 谁实现了 Runnable 接口?

在现代 LangChain(LCEL)里,你会发现处处皆为 Runnable

  • PromptTemplate :它是一个 Runnable。输入是 dict(变量),输出是 PromptValue(格式化后的文本)。

  • ChatOpenAI / Ollama :它是一个 Runnable。输入是 PromptValue 或消息列表,输出是 AIMessage

  • OutputParser :它是一个 Runnable。输入是 AIMessage,输出是解析后的结构化数据(如 listdict)。

  • 甚至你用管道符 | 拼出来的整个 Chain :它也是一个全新的 RunnableSequence(依然是 Runnable 的子类)。

因为大家都是 Runnable,拥有完全相同的接口方法,所以它们才能用 | 像乐高积木一样完美咬合。

3. Runnable 协议带来的天然红利

由于整个大模型链条里的每个节点都严格遵循 Runnable,LangChain 自动赋予了你的应用三大极其强大的底层能力:

① 自动获得流式传输(Streaming)和并发(Batching)

即便你自己写了一个复杂的 Chain,只要里面所有的子组件都是 Runnable,你的整个 Chain 就会自动无缝支持 chain.stream()chain.batch(),不需要你手动去写复杂的异步多线程或生成器代码。

② 显式的数据校验(Input/Output Schema)

每个 Runnable 组件都内置了 input_schemaoutput_schema 属性。在运行时或调试时,你可以直接通过 Pydantic 结构查看这个组件期望接收什么格式的数据 以及会吐出什么数据,极大地降低了 Debug 成本。

③ 完美的异步支持

大模型应用包含大量的网络 I/O(等待大模型响应、等待数据库检索)。Runnable 原生自带的 ainvokeabatchastream 能够完美融入 Python 的 asyncio 生态,让你的高并发后端服务性能最大化。

一句话总结

Runnable 是 LangChain 世界的统一标准度量衡。有了它,框架才能实现"万物皆可连接";有了它,你拼装出来的 AI 工作流才能天然具备高并发和流式输出的能力。