langgraph 后端发自定义数据,前端接收方法概括

0 阅读2分钟

image.png
有些自定义数据和状态流转,不能走messages通道,要走custom通道

一、整体流程图

Python 节点(search_node)
  │  get_stream_writer()({ type, ... })   ← 写入
  ▼
LangGraph Runtime (stream_mode="custom")
  │  产生 protocol event,method = "custom"
  ▼
CustomTransformer(required_stream_modes=("custom",))
  │  把 custom 事件原样保留 / 转发
  ▼
langgraph dev → 协议 v2 SSE
  │  event: custom
  │  data: { name?, payload }
  ▼
前端 useStream / useChannel(['custom'])
  │  event.params.data
  ▼
渲染 / 总结

二、四个关键点

1. 必须注册 CustomTransformer,否则事件不会产生

v2 事件流只在 graph 声明了stream_transformers 时,才会请求custom 流。没有它,get_stream_writer() 写了也白写。

# streaming.py
from langgraph.stream import CustomTransformer

def stream_transformers():
    return [CustomTransformer]
# graph.py — 必须 import 到图模块里,框架用 getattr 反射找这个名字
from agent.streaming import stream_transformers  # noqa: F401

关键点:函数 不能只写在别的文件里 ,必须作为属性出现在langgraph.json 指向的那个图模块的命名空间。

2. 用get_stream_writer() 写数据(后端)

from langgraph.config import get_stream_writer

def search_node(state):
    writer = get_stream_writer()
    writer({"type": "searching", "query": "..."})
    ...
    writer({"type": "search_done", "count": 3})
  • 写进去的是 任意可序列化对象 (dict/list/基本类型);
  • 没有type= 参数,传一个位置参数即可;
  • 只有在 v2 流的 run 里 调用才有效,本地graph.invoke() 里写不会推到前端。

3. 前端用useChannel 订阅(官方)

const events = useChannel(stream, ['custom'], undefined, { replay: true, bufferSize: 64 })

参数含义:

image.png 取数据:

const payload = computed(() => events.value.at(-1)?.params?.data)
// payload 就是后端 writer 传的原样对象:{ type, query, ... }

4. (补充)replay 和bufferSize 的取舍

  • replay: true :后订阅也能拿到 之前已发生 的事件,适合进度条、状态展示;
  • replay: false :只收 订阅之后 的事件,适合一次性通知(如"搜索完成"提示,避免重复弹);
  • bufferSize 控制回放窗口,太大占内存,太小可能漏;进度展示建议 32~128。

三、数据在各层的形状(对照排查)

image.png

四、一句话记忆

后端写 :`get_stream_writer()(payload)`
后端注册 :`stream_transformers() -> [CustomTransformer]` (放在图模块)
前端收 :`useChannel(stream, ['custom'], undefined, {replay:true, bufferSize:64})` ,读`.params.data`