快速开始
各组件如何协同工作
流式处理栈有两个主要层次:- 流式处理 从 Pregel 引擎发出原始的图执行事件。
- 事件流 对这些事件进行规范化,将它们通过流转换器运行,并暴露类型化投影。
Pregel 引擎
运行图的各个步骤
发出
原始 Pregel 事件
updates、values、messages、custom、checkpoints、tasks、debug发送到
事件路由器
将每个事件通过转换器管道进行路由
级联通过
流转换器
ValuesTransformer
MessagesTransformer
…
自定义转换器
产生
事件流
为应用程序代码投影的事件
stream.messages、stream.values、stream.subgraphs 和 stream.output。自定义转换器可以在 stream.extensions 下添加特定于应用程序的投影。
事件流提供的功能
运行流在底层事件流之上暴露了类型化投影:| 投影 | 用途 |
|---|---|
stream | 迭代每个协议事件。 |
stream.messages | 流式传输聊天模型消息和 token 增量。 |
stream.values | 迭代状态快照并等待最终值。 |
stream.output | 等待最终输出。 |
stream.subgraphs | 发现并观察嵌套图的执行。 |
stream.interrupts | 检查人机交互中断的有效载荷。 |
stream.interrupted | 检查运行是否因等待人工输入而暂停。 |
stream.extensions | 消费自定义流转换器投影。 |
stream.messages 不会消耗 stream.values、stream.subgraphs 或 stream.output 所需的事件。
事件流位于 streaming 之上,后者通过 stream_mode 模式(如 updates、values、messages、custom、checkpoints、tasks 和 debug)暴露原始的图执行事件。当你需要底层访问这些模式时,使用 streaming;当应用程序代码能从类型化投影中受益时,使用事件流。
流式传输消息
使用stream.messages 来获取聊天模型输出:
message.text 是可迭代的。迭代它可以逐 token 输出,或者调用 str(message.text) 获取完整文本。
message.reasoning 会暴露推理增量,message.tool_calls 会暴露工具调用参数片段。如果你需要文本、推理和工具调用片段按照确切的到达顺序,可以迭代消息流的原始事件,而不是分别迭代每个投影。
流式传输子图
使用stream.subgraphs 来观察嵌套图的工作,无需解析命名空间字符串:
subgraph.graph_name 是已编译图或代理的 name。一个从工具中调度的命名代理(例如,通过 Deep Agents 的 task 工具调用的 create_agent(name=...))会在此处按该名称呈现,并且打开该作用域的 lifecycle 事件会携带一个 cause,链接回调度的工具调用。更多信息请参阅 Lifecycle。
对于特定产品的流式处理,请参阅 Deep Agents 流式处理(针对子代理流),以及 LangChain 代理流式处理(针对工具调用和中间件事件)。
流式传输状态
使用stream.values 在每一步后流式传输完整的状态快照:
流式传输多个投影
在异步代码中并发消费时,将astream_events 与 asyncio.gather 结合使用:
stream.interleave(...) 以严格的到达顺序消费多个投影:
中断后恢复
当图因等待人工输入而暂停时,检查stream.interrupted 和 stream.interrupts,然后再次调用 stream_events(..., version="v3") 并传入 Command 来恢复运行。
恢复需要一个使用检查点存储器编译的图,以及一个携带线程 ID 的配置——请参阅 持久化。
流式传输所有协议事件
当你需要原始协议事件流时,直接使用运行对象本身:ProtocolEvent 信封,包装了特定于通道的有效载荷。转换器的 process(event) 接收的正是相同的形状。
namespace 是从根图到发出事件的作用域的路径。根是空数组 []。每个子执行会增加一个 "name:runtime_id" 段,因此子图中嵌套的工具调用看起来像 ["researcher:6f4d", "tools:91ac"]。: 之前的部分是稳定的图或节点名称;后缀是每次调用的运行时 ID。当你只关心特定子树时,可以自己按命名空间过滤原始事件——stream.subgraphs 已经为嵌套图执行完成了这项工作。
通道和事件生命周期
原始事件在通道上流动。通道名称作为事件的method 出现;每个通道发出特定形状的事件。
| 通道 | 用途 |
|---|---|
values | 完整的图状态快照。 |
updates | 每个节点的状态增量。 |
messages | 以内容块为中心的聊天模型输出。 |
tools | 工具调用开始、流式输出、完成和错误事件。 |
lifecycle | 运行、子图和子代理的状态变化。 |
checkpoints | 用于分支和时间旅行的轻量级检查点信封。 |
input | 人机交互输入请求和响应。 |
tasks | Pregel 任务创建和结果事件。 |
custom | 来自图代码的用户定义有效载荷。 |
custom:<name> | 应用程序定义的流转换器输出。 |
stream.messages、stream.values 等)正是基于这些通道构建的。当你直接迭代运行对象时,通道名称会作为原始事件上的 method 字段出现。
消息
messages 通道将输出建模为内容块。数据的 event 字段是以下之一:
message-startcontent-block-startcontent-block-deltacontent-block-finishmessage-finish
message-finish 可能包含 token 使用量;无法恢复的模型调用失败会作为消息错误事件到达。
要直接消费原始的内容块事件,而不使用 stream.messages 投影:
工具
tools 通道暴露工具的执行情况。数据的 event 字段是以下之一:
tool-startedtool-output-deltatool-finishedtool-error
messages 通道上的原始工具调用内容块关联起来。
生命周期
lifecycle 通道跟踪根运行、子图和子代理的状态。数据的 event 字段是以下之一:
startedrunningcompletedfailedinterrupted
event 之外,生命周期数据还可能包含可选的 graph_name、error 和 cause,用于描述子作用域启动的原因(父工具调用、扇出发送、边转换)。
构建自己的投影
流转换器是事件流中的投影层。它们观察协议事件,维护自己的状态,并暴露运行的派生视图——例如工具活动、token 总数、进度事件、工件或用于另一个协议的消息。StreamChannel 是转换器用于发布这些视图的投影原语。
内置投影(stream.messages、stream.values、stream.subgraphs、stream.output)和特定于产品的投影(LangChain 的 stream.tool_calls,Deep Agents 的 stream.subagents)本身就是使用相同契约的转换器。用户转换器通过编译时或调用时注册叠加在其上,它们的投影会出现在 stream.extensions 下。
当现有投影与应用程序所需的形状不匹配时,就可以编写一个。
转换器的工作原理
事件流从 LangGraph Pregel 引擎的流式输出开始。运行时会将这些数据块规范化为协议事件,然后流处理器将每个事件通过一个流转换器栈进行路由。 流处理器是一次流中的中央调度器。对于每个协议事件,它会:- 按顺序调用每个已注册转换器的
process(event)钩子。 - 将命名的
StreamChannel推送重新连接到协议事件流上。 - 将事件存储在运行流中,除非转换器抑制了它。
- 在运行结束时,对每个转换器调用
finalize()或fail()。
StreamChannel、Promise 或其他投影对象中。
转换器形状
转换器实现StreamTransformer 接口:
init()创建投影对象。用户转换器投影会出现在stream.extensions下。process()观察每个协议事件。关于ProtocolEvent的形状,请参阅 流式传输所有协议事件。仅当你故意想要抑制原始事件时才返回false。finalize()在流成功结束后关闭或解析非通道投影。fail()将错误传播到非通道投影。
声明所需的流模式
required_stream_modes 控制底层图在流式传输期间发出哪些 Pregel 流模式。运行时会取所有已注册转换器的 required_stream_modes 的并集,并将该并集作为 stream_mode 参数传递给图的 .stream() 调用。没有转换器请求的模式永远不会被发出——声明 ("custom",) 是使 custom 事件在运行中流动的原因。
process() 接收图发出的每个事件,并负责根据 event["method"] 进行过滤。声明会打开上游发出;它不会缩小 process() 看到的内容。有效值是 Pregel 流模式:"messages"、"tools"、"custom"、"values"、"updates"、"checkpoints"、"tasks"、"debug"。每个转换器都必须声明它所作用的每个模式——遗漏的模式不会被图发出,也永远不会到达 process()。
StreamChannel
StreamChannel 是转换器用于流式传输值的投影原语。它始终在 stream.extensions.<name> 上暴露一个可迭代流。构造函数参数决定每次 push() 是否也作为 custom:<name> 事件流入运行的主事件流——也就是说,投影的值在迭代原始协议事件时是否会显示。
| 需求 | 用法 |
|---|---|
| 仅侧通道投影 | StreamChannel() |
| 同时将每次推送流入主事件流 | StreamChannel(name) |
custom:<name> 协议事件。将 Promise、异步可迭代对象、类实例和其他进程内句柄保留在未命名通道中。
流处理器拥有通道的生命周期。一旦 init() 返回一个通道,处理器会在运行结束时为你关闭或标记失败。转换器只负责推送值。
示例:命名通道
将字符串名称传递给StreamChannel,可以通过 stream.extensions 暴露流式投影,并且 将每次推送的值作为 custom:<name> 协议事件转发到运行的主事件流中:
示例:未命名通道
没有名称时,该通道仅是一个侧通道投影——可在stream.extensions 上访问,但对迭代原始事件的消费者不可见。对于持有无法序列化到主事件流的进程内句柄(Promise、异步可迭代对象、类实例)的投影,这是正确的选择。
下面的示例将一个未命名通道与 get_stream_writer 配对使用,后者允许图节点发出 custom 通道事件,然后转换器将这些事件排入投影中:
示例:最终值投影
当投影不应流入主事件流时,使用未命名流、Promise 或其他进程内对象:在调用时或编译时注册
在调用时传递转换器以进行本地实验:内置:ToolCallTransformer
LangGraph 内置了 ToolCallTransformer。注册它可以在普通的 StateGraph 上暴露 stream.tool_calls:
相关
LangGraph 定义了流式处理原语。要将流式处理与 LangChain 或 Deep Agents 结合使用,请查看相关产品文档:- LangChain 代理流式处理 涵盖了 ReAct 风格的代理消息、工具调用和中间件更新。
- Deep Agents 流式处理 涵盖了子代理、嵌套消息和子代理工具调用。
- LangChain 前端模式 和 LangGraph 前端模式 展示了基于流式状态构建的 UI 用例。
- LangSmith 流式 API 涵盖了针对部署在 Agent Server 背后的图进行流式处理。
langchain-protocol(PyPI)和 @langchain/protocol(npm)来使用。
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

