LangGraph astream 七种流式模式完全指南
概述
LangGraph 图公开了 .stream()(同步)和 .astream()(异步)方法,以迭代器形式生成流式输出。这些方法支持七种不同的流式模式(StreamMode),每种模式适用于不同的场景。
StreamMode = Literal[
"values", # 完整状态值
"updates", # 状态更新
"checkpoints", # 检查点事件
"tasks", # 任务事件
"debug", # 调试信息
"messages", # LLM 消息流
"custom" # 自定义数据
]
一、values 模式
描述
在图的每个步骤之后,流式传输状态的完整值。
使用场景
- 需要查看每个步骤后的完整状态
- 调试状态变化
- 了解状态累积过程
示例
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
topic: str
joke: str
def refine_topic(state: State):
return {"topic": state["topic"] + " and cats"}
def generate_joke(state: State):
return {"joke": f"This is a joke about {state['topic']}"}
graph = (
StateGraph(State)
.add_node(refine_topic)
.add_node(generate_joke)
.add_edge(START, "refine_topic")
.add_edge("refine_topic", "generate_joke")
.add_edge("generate_joke", END)
.compile()
)
# 使用 values 模式
for chunk in graph.stream(
{"topic": "ice cream"},
stream_mode="values",
):
print(chunk)
输出:
{'topic': 'ice cream and cats', 'joke': ''}
{'topic': 'ice cream and cats', 'joke': 'This is a joke about ice cream and cats'}
二、updates 模式
描述
在图的每个步骤之后,流式传输状态的更新。如果同一步骤中有多次更新(例如运行了多个节点),这些更新将单独流式传输。
使用场景
- 仅关注节点返回的变化
- 需要知道哪个节点产生了什么变化
- 最常用的流式模式
示例
# 使用 updates 模式
for chunk in graph.stream(
{"topic": "ice cream"},
stream_mode="updates",
):
print(chunk)
输出:
{'refine_topic': {'topic': 'ice cream and cats'}}
{'generate_joke': {'joke': 'This is a joke about ice cream and cats'}}
三、checkpoints 模式
描述
当创建检查点时发出事件,格式与 get_state() 返回的格式相同。
使用场景
- 需要监控检查点创建
- 实现持久化状态的监听
- 调试检查点行为
示例
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "my-thread"}}
for chunk in graph.stream(
inputs,
config,
stream_mode="checkpoints",
):
print(chunk)
四、tasks 模式
描述
当任务开始和完成时发出事件,包括其结果和错误。
使用场景
- 监控任务执行状态
- 追踪任务开始/结束时间
- 处理任务级别的错误
示例
for chunk in graph.stream(
inputs,
stream_mode="tasks",
):
print(chunk)
典型输出结构:
{
'event': 'task', # 事件类型
'name': 'node_name', # 任务名称
'status': 'start', # start/complete/error
'result': {...}, # 任务结果
'error': None # 错误信息
}
五、debug 模式
描述
发出 checkpoints 和 tasks 事件用于调试目的。提供最详细的执行信息。
使用场景
- 深度调试图执行
- 分析性能瓶颈
- 理解完整的执行流程
示例
for chunk in graph.stream(
inputs,
stream_mode="debug",
):
print(chunk)
组合使用:
# debug 模式等价于组合使用 checkpoints 和 tasks
for mode, chunk in graph.stream(
inputs,
stream_mode=["debug", "updates", "values"],
):
print(f"[{mode}]", chunk)
六、messages 模式
描述
从调用 LLM 的任何图节点流式传输 2 元组(消息块,元数据)。
使用场景
- 实时显示 LLM 输出
- 逐令牌流式传输响应
- 过滤特定 LLM 调用的输出
示例
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START
llm = init_chat_model(model="openai:gpt-4o-mini")
def call_model(state):
llm_response = llm.invoke([
{"role": "user", "content": f"Generate a joke about {state['topic']}"}
])
return {"joke": llm_response.content}
graph = (
StateGraph(State)
.add_node(call_model)
.add_edge(START, "call_model")
.compile()
)
# 流式传输 LLM 令牌
for message_chunk, metadata in graph.stream(
{"topic": "ice cream"},
stream_mode="messages",
):
if message_chunk.content:
print(message_chunk.content, end="|", flush=True)
元数据结构:
{
"langgraph_node": "node_name", # 调用 LLM 的节点
"tags": ["tag1", "tag2"], # LLM 的标签
"run_id": "...", # 运行 ID
# ... 其他元数据
}
按 LLM 调用过滤
llm_1 = init_chat_model(model="openai:gpt-4o-mini", tags=['joke'])
llm_2 = init_chat_model(model="openai:gpt-4o-mini", tags=['poem'])
async for msg, metadata in graph.astream(
{"topic": "cats"},
stream_mode="messages",
):
if metadata["tags"] == ["joke"]:
print(msg.content, end="|", flush=True)
按节点过滤
for msg, metadata in graph.stream(
inputs,
stream_mode="messages",
):
if msg.content and metadata["langgraph_node"] == "write_poem":
print(msg.content, end="|", flush=True)
七、custom 模式
描述
使用 StreamWriter 从节点或任务内部流式传输自定义用户定义数据。
使用场景
- 发送进度更新
- 流式传输任意 LLM API 的输出
- 自定义实时数据推送
基本示例
from langgraph.config import get_stream_writer
from langgraph.graph import StateGraph, START
class State(TypedDict):
query: str
answer: str
def node(state: State):
writer = get_stream_writer() # 获取流写入器
writer({"custom_key": "Generating custom data inside node"})
return {"answer": "some data"}
graph = (
StateGraph(State)
.add_node(node)
.add_edge(START, "node")
.compile()
)
for chunk in graph.stream({"query": "example"}, stream_mode="custom"):
print(chunk)
工具中使用自定义流
from langchain_core.tools import tool
from langgraph.config import get_stream_writer
@tool
def query_database(query: str) -> str:
"""Query the database."""
writer = get_stream_writer()
writer({"data": "Retrieved 0/100 records", "type": "progress"})
# perform query
writer({"data": "Retrieved 100/100 records", "type": "progress"})
return "some-answer"
for chunk in graph.stream(inputs, stream_mode="custom"):
print(chunk)
流式传输任意 LLM
from langgraph.config import get_stream_writer
from openai import AsyncOpenAI
openai_client = AsyncOpenAI()
async def stream_tokens(model_name: str, messages: list[dict]):
response = await openai_client.chat.completions.create(
messages=messages, model=model_name, stream=True
)
async for chunk in response:
delta = chunk.choices[0].delta
if delta.content:
yield {"content": delta.content}
async def call_arbitrary_model(state):
writer = get_stream_writer()
async for chunk in stream_tokens("gpt-4o-mini", [
{"role": "user", "content": f"Tell me about {state['topic']}"}
]):
writer({"custom_llm_chunk": chunk})
return {"result": "completed"}
async for chunk in graph.astream(
{"topic": "cats"},
stream_mode="custom",
):
print(chunk.get("content", ""), end="|", flush=True)
组合多种模式
你可以将列表作为 stream_mode 参数传递,以同时流式处理多种模式。
async for mode, chunk in graph.astream(
inputs,
stream_mode=["updates", "custom"],
):
print(f"[{mode}]", chunk)
输出示例:
[custom] {'progress': 'Starting...'}
[updates] {'node1': {'foo': 'bar'}}
[custom] {'progress': 'Processing...'}
[updates] {'node2': {'baz': 'qux'}}
[custom] {'progress': 'Done!'}
Python < 3.11 的注意事项
在 Python < 3.11 版本中,asyncio 任务不支持 context 参数,这影响流式传输:
1. 必须显式传递 RunnableConfig
async def call_model(state, config): # 接受 config 参数
response = await llm.ainvoke(
[{"role": "user", "content": f"Write about {state['topic']}"}],
config, # 必须传递
)
return {"result": response.content}
2. 不能使用 get_stream_writer()
必须直接传递 writer 参数:
from langgraph.types import StreamWriter
async def my_node(state: State, writer: StreamWriter): # 接受 writer 参数
writer({"custom_key": "data"})
return {"answer": "done"}
子图流式传输
要在流式输出中包含来自子图的输出,设置 subgraphs=True:
for chunk in graph.stream(
{"foo": "foo"},
subgraphs=True,
stream_mode="updates",
):
print(chunk)
输出格式: (命名空间, 数据) 元组
((), {'node_1': {'foo': 'hi! foo'}})
(('node_2:task-id',), {'subgraph_node_1': {'bar': 'bar'}})
(('node_2:task-id',), {'subgraph_node_2': {'foo': 'hi! foobar'}})
((), {'node_2': {'foo': 'hi! foobar'}})
禁用特定模型的流式处理
对于不支持流式处理的模型,可以显式禁用:
from langchain.chat_models import init_chat_model
model = init_chat_model(
"anthropic:claude-3-7-sonnet-latest",
disable_streaming=True
)
或使用 ChatOpenAI:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="o1-preview", disable_streaming=True)
快速参考表
| 模式 | 输出内容 | 使用场景 |
|---|---|---|
values | 完整状态值 | 调试状态变化 |
updates | 节点返回的更新 | 最常用,关注变化 |
checkpoints | 检查点事件 | 监控持久化 |
tasks | 任务开始/完成/错误 | 任务级别监控 |
debug | checkpoints + tasks | 深度调试 |
messages | (消息块, 元数据) | LLM 令牌流 |
custom | 自定义数据 | 进度更新/任意数据 |
最佳实践
- 开发阶段:使用
debug模式获取完整信息 - 生产环境:使用
updates模式减少数据传输 - 用户界面:使用
messages模式实时显示 LLM 输出 - 进度显示:使用
custom模式发送自定义进度 - 状态监控:组合使用
["values", "custom"]获取完整状态和自定义数据