【LangGraph】 流式处理入门

【LangGraph】新篇章:LangGraph 流式处理入门 ------ 理解五种流模式与基本算法

  • 前言
    • 1、什么是流式处理?
    • [2、LangGraph 的五种流模式](#2、LangGraph 的五种流模式)
    • 3、环境准备:一个支持工具调用的天气助手
      • [3.1 定义状态和上下文](#3.1 定义状态和上下文)
      • [3.2 工具函数:使用 get_stream_writer() 发送自定义事件](#3.2 工具函数:使用 get_stream_writer() 发送自定义事件)
      • [3.3 LLM 节点:同样发送自定义事件](#3.3 LLM 节点:同样发送自定义事件)
      • [3.4 构建图并编译](#3.4 构建图并编译)
    • [4、updates 模式:观察节点状态更新](#4、updates 模式:观察节点状态更新)
    • [5、custom 模式:传输自定义事件](#5、custom 模式:传输自定义事件)
    • [6、values 模式:完整状态快照](#6、values 模式:完整状态快照)
    • 7、结合使用:处理混合输出
    • 8、总结

前言

当你构建的 AI Agent 需要处理复杂任务时,用户最讨厌的就是"等待"

LangGraph提供的流式处理能力,让你能够将执行过程的中间状态、节点更新、甚至 LLM 生成的每一个 token 实时推送给前端

本文是流式处理系列的第一篇,我们将介绍 LangGraph 的五种流模式,并通过一个天气查询助手的实例,带你掌握custom 和 updates 等模式的基本用法


1、什么是流式处理?

在传统的一次性调用中,graph.invoke() 会等待整个工作流执行完毕,然后一次性返回最终结果

这对于耗时较长的任务(比如多步推理、调用多个工具)来说,用户体验很差

流式处理(Streaming)允许你在图执行的过程中,逐步输出中间结果

例如:

  • 每执行完一个节点,就输出该节点对状态做了哪些更新

  • 在 LLM 生成回复时,逐 token 输出文字(类似 ChatGPT 的打字机效果)

  • 在长时间运行的工具内部,发送自定义的进度事件(比如"搜索中 30%")

LangGraph 对流的支持非常彻底:不仅支持图状态的变化流,还支持工具内部的自定义数据流,以及 LLM token 级别的流,理解这些模式,是构建高质量交互式 Agent 的基础


2、LangGraph 的五种流模式

LangGraph 的 stream() 方法(以及异步的 astream())接受一个 stream_mode 参数,可以传入单个模式名称,也可以传入一个列表同时启用多种模式

下表是五种模式的概览:

模式名 输出内容 典型使用场景
"values" 每个超级步骤后的完整状态(full state) 调试时查看状态的完整变化历史
"updates" 每个节点返回的状态更新(仅变更的部分) 实时显示哪个节点做了什么更新,节省带宽
"messages" 逐 token 输出的 LLM 消息(message_chunk, metadata)元组 聊天应用,实现打字机效果
"custom" 工具或节点内通过 get_stream_writer() 发送的自定义数据 进度条、中间日志、思考过程展示
"debug" 所有调试信息(包括每个步骤的详细信息) 开发阶段深度调试

注意:

你可以在一次调用中组合多种模式,例如 stream_mode=["custom", "updates"],LangGraph 会为每种模式分别输出一个元组 (mode_name, data)


3、环境准备:一个支持工具调用的天气助手

为了演示流模式,我们构建一个简单的 LangGraph 应用:

用户询问 "今天烟台莱山区的天气"

Agent 必须调用一个模拟的天气查询工具,然后返回结果

我们将在这个应用中同时启用 customupdates 模式

3.1 定义状态和上下文

python 复制代码
from dataclasses import dataclass
from langgraph.graph import MessagesState

class State(MessagesState):
    user_name: str = ""   # 扩展用户名字段

@dataclass
class Context:
    user_id: str

MessagesState 是 LangGraph 预定义的状态

它包含一个 messages: list[AnyMessage],并配置了 operator.add 合并策略,非常适合对话系统


3.2 工具函数:使用 get_stream_writer() 发送自定义事件

python 复制代码
from langgraph.config import get_stream_writer
from langgraph.prebuilt import ToolRuntime

def search(runtime: ToolRuntime[Context]) -> str:
    writer = get_stream_writer()
    writer({
        "type": "search_node",
        "status": "start",
    })
    user_id = runtime.context.user_id
    user_name = runtime.state["user_name"]
    writer({
        "type": "search_node",
        "status": "searching",
        "user_id": user_id,
        "user_name": user_name,
    })
    # 模拟查询数据...
    writer({
        "type": "search_node",
        "status": "end",
        "user_id": user_id,
        "user_name": user_name,
    })
    return f"user_id:{user_id},user_name:{user_name} 查询天气,晴天:15-20°"

get_stream_writer() 返回一个可调用对象,你可以在任何节点或工具中调用它,并传入一个 JSON 可序列化的字典

这些数据只有在 stream_mode 包含 "custom" 时才会输出


3.3 LLM 节点:同样发送自定义事件

python 复制代码
def llm_call(state: State):
    writer = get_stream_writer()
    writer({
        "type": "llm_call",
        "status": "start",
        "messages": "开始调用大模型",
        "content": state["messages"][-1].content,
    })
    messages = [SystemMessage(content="你是天气助手,必须调用工具查询天气")] + state["messages"]
    result = model_with_tool.invoke(messages)
    writer({
        "type": "llm_call",
        "status": "end",
        "messages": "结束调用大模型",
    })
    return {"messages": [result]}

3.4 构建图并编译

python 复制代码
from langgraph.constants import START, END
from langgraph.graph import StateGraph
from langgraph.prebuilt import ToolNode, tools_condition

builder = StateGraph(State, context_schema=Context)
builder.add_node(llm_call)
builder.add_node("tool_node", ToolNode([search]))
builder.add_edge(START, "llm_call")
builder.add_conditional_edges(
	"llm_call",
 	tools_condition,
  {
  "tools": "tool_node",
   "__end__": END
   })
builder.add_edge("tool_node", "llm_call")
graph = builder.compile()

4、updates 模式:观察节点状态更新

当我们调用 stream() 并指定 stream_mode="updates" 时,每次节点执行后都会输出一个字典,格式为 {node_name: state_update}

python 复制代码
for chunk in graph.stream(inputs, context=ctx, stream_mode="updates"):
    print(chunk)

输出示例:

text 复制代码
{'llm_call': {'messages': [AIMessage(content='', tool_calls=[...])]}}

{'tool_node': {'messages': [ToolMessage(content='...')]}}

{'llm_call': {'messages': [AIMessage(content='根据查询,天气晴朗...')]}}

每个 chunk 只包含该节点对状态的增量更新,而不是完整状态

这样可以减少传输的数据量,特别适合在 UI 上实时显示"当前正在执行哪个节点"以及该节点产生的新消息

实际应用:我们可以在前端实时显示"模型正在决定调用工具..."、"工具正在执行..."、"模型正在生成最终回复..."。


5、custom 模式:传输自定义事件

custom 模式与 updates 模式独立

当我们同时启用两者时,输出是一个元组 (mode_name, data)

bash 复制代码
for chunk in graph.stream(inputs, context=ctx, stream_mode=["custom", "updates"]):
    print(chunk)

输出示例:

text 复制代码
('custom', {'type': 'llm_call', 'status': 'start', 'messages': '开始调用大模型', 'content': '今天烟台莱山区天气怎么样'})
('updates', {'llm_call': {'messages': [AIMessage(tool_calls=[...])]}})
('custom', {'type': 'search_node', 'status': 'start'})
('custom', {'type': 'search_node', 'status': 'searching', 'user_id': '123', 'user_name': '小猫'})
('custom', {'type': 'search_node', 'status': 'end', 'user_id': '123', 'user_name': '小猫'})
('updates', {'tool_node': {'messages': [ToolMessage(...)]}})
('custom', {'type': 'llm_call', 'status': 'end', 'messages': '结束调用大模型'})
('updates', {'llm_call': {'messages': [AIMessage(content='最终答案')]}})

注意:custom 事件可以出现在任何时刻,甚至可以出现在工具执行期间(比如多步骤进度)

这正是我们将要介绍的下一篇文章的重点!!!


6、values 模式:完整状态快照

与 updates 不同,values 模式输出每个超级步骤后的整个状态

例如:

bash 复制代码
for chunk in graph.stream(inputs, context=ctx, stream_mode="values"):
    print(chunk["messages"][-1].content)

输出(略去细节)可能会看到状态逐步丰富的过程

values 模式适合调试或需要完整上下文的前端同步,但数据量较大

两者区别

在 LangGraph 中:

  • updates :类似 事件流(event stream)
  • values :类似 状态快照(state snapshot)

假设 state:

state = {

"messages": [...]

}

updates 模式返回:

{"messages": [AIMessage("hello")]} # 新增的

values 模式返回:

{"messages": [HumanMessage(...), AIMessage("hello")]} # 全部

我们可以这样记:

  • updates = git diff(改了啥)
  • values = git snapshot(现在啥样)

7、结合使用:处理混合输出

在实际应用中,你通常会同时接收 custom 和 updates 事件,分别处理:

python 复制代码
for chunk in graph.stream(inputs, context=ctx, stream_mode=["custom", "updates"]):
    mode, data = chunk
    if mode == "custom":
        # 处理自定义事件,例如更新进度条
        update_progress(data)
    elif mode == "updates":
        # 处理节点更新,例如显示最新消息
        for node, update in data.items():
            if "messages" in update:
                last_msg = update["messages"][-1]
                if hasattr(last_msg, "pretty_print"):
                    last_msg.pretty_print()

8、总结

本文介绍了 LangGraph 的五种流模式,重点解析了 updates 和 custom 模式,并通过一个天气查询代理的实例,展示了如何在实际中使用 get_stream_writer() 发送自定义事件,以及如何接收混合流数据

核心要点回顾

  • values:完整状态快照(调试/同步)

  • updates:节点增量更新(实时显示进度)

  • custom:任意自定义事件(进度条、思考日志)

  • messages:LLM token 流(实时展⽰ LLM ⽣成内容)

  • debug:全量调试信息(开发用)

在下一篇文章中,我们将深入 custom 模式的高级用法:

如何在工具内部模拟多步骤任务,发送进度百分比,构建"思考过程"可视化面板


okok,本期分享先到这里了,再见再见~

相关推荐
星辰徐哥1 小时前
人工智能:计算机视觉的基础与应用
人工智能·计算机视觉·ai·预处理·特征提取
发哥来了1 小时前
东莞AI培训课程横向对比:五家机构教学与就业质量评测
大数据·人工智能·机器学习·ai·aigc
AI医影跨模态组学1 小时前
(综述)J Transl Med 浙江大学医学院附属第二医院等团队:放射组学在胶质母细胞瘤复发中的应用:预测、定位及与治疗相关效应鉴别的进展
人工智能·深度学习·医学·医学影像·影像组学
神工坊2 小时前
新闻︱神工坊受邀出席无锡人工智能产业园“AI赋能研发设计”主题活动,共探算力与AI时代下的CAE范式革新
人工智能·ai·hpc·cfd·cae·求解加速·智能修模
计算机毕业编程指导师2 小时前
【Python大数据项目推荐】基于Hadoop+Django脑卒中风险分析系统源码解析 毕业设计 选题推荐 毕设选题 数据分析 机器学习 数据挖掘
大数据·hadoop·python·计算机·spark·毕业设计·脑卒中
我是发哥哈2 小时前
东莞AI培训主流方案横向评测:5大选型维度解析
大数据·人工智能·学习·机器学习·chatgpt·ai编程
千寻girling2 小时前
机器学习 | 感知机 | 尚硅谷学习
人工智能·学习·机器学习
南河的南2 小时前
RAG项目总结
人工智能
大模型真好玩2 小时前
LangChain DeepAgents 速通指南(八)—— DeepAgents流式输出详解
人工智能·langchain·agent