LangGraph 04:流式、调试与生产运行
1、本篇任务:让图在用户和开发者眼中都可见
用户关心“正在检索、等待审批、答案到哪了”;开发者关心“哪个节点慢、state 如何变化、为何走了这条边”。两者需要不同流。不要把完整 state 或内部 trace 直接发给用户。
2、理解常用 stream mode
| 模式 | 看到什么 | 适用场景 |
|---|---|---|
values | 每步后的完整 state | 本地调试,小 state |
updates | 节点产生的局部更新 | 调试状态变化、构建事件适配 |
messages | 模型消息/token 与 metadata | 打字机输出 |
custom | 节点主动上报进度 | “已处理 4/10 个文档” |
debug | 更完整运行信息 | 开发排障,不对外 |
Python:
for chunk in graph.stream(input_state, config=config, stream_mode=["updates", "messages"]):
public_event = event_adapter.to_public(chunk)
if public_event:
yield sse_encode(public_event)
TypeScript 同样从 graph.stream() 异步迭代事件。事件适配器负责脱敏、增加 run ID/sequence、把节点名转换为稳定产品阶段。
3、不要把 private state 当作自动保密
input/output schema 可以限制 invoke 的输入输出,但某些 stream mode 可能看到内部 channel。真正的机密不要写 state;流式输出显式选择 output keys,并在适配器做 allowlist。工具堆栈、原始检索文本、用户 PII 和密钥不能发给前端。
4、调试一条错误回答的固定顺序
- 看输入和 graph/release 版本。
- 看实际经过的节点与条件路由。
- 看订单工具和 retriever 的结构化输出。
- 看 reducer 后的 state 是否丢失或重复证据。
- 看模型节点最终获得的上下文清单。
- 看输出校验和 UI 适配是否改变结果。
这样能区分路由、数据、state、模型和展示问题,而不是一看到差答案就改 prompt。
5、生产预算和 SLO
每个 run 设置 deadline、recursion limit、最大模型调用、最大工具调用、token 预算和并发上限。按节点观测 P50/P95、错误率和成本:
| 指标 | 暴露的问题 |
|---|---|
| 首事件/首 token 延迟 | 队列、模型连接、上下文过大 |
| 检索节点 P95 | 向量库、rerank、ACL filter |
| 每 run 工具次数 | 路由或循环失控 |
| 恢复成功率 | checkpoint、schema、幂等问题 |
| 拒答率与引用有效率 | 索引或生成回归 |
6、部署时的基本拓扑
API → run queue → stateless graph workers
├→ shared checkpointer/store
├→ domain services/outbox
└→ trace/logs/metrics
水平扩容时不能使用每进程内存保存 thread。worker 可重启,state 必须在共享持久层。取消 run 要阻止新节点派发,等待不可中断工具结束,并记录最终取消状态。
7、故障演练
向量库故障应拒答而非编造;一个并发分支超时应降级;流式连接断开不应重做副作用;模型连续 tool call 应被预算终止;旧 checkpoint 不兼容时转旧 worker 或人工处理;trace SDK 故障不应影响主请求。
每次事故都转成节点测试、完整图测试或评测案例。LangGraph 阶段的完成标准不是“图能画出来”,而是控制流可解释、状态可恢复、故障可验证。
下一阶段进入 Deep Agents:在 LangGraph 之上使用规划、文件系统和子 Agent 处理开放式长任务。
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录