关键设计决策和原因
本章用决策表归纳 LangGraph 为何这样设计,细节见 02–07,不贴源码。
1. 为何选 Pregel / BSP
| 考量 | 选择 |
|---|---|
| Agent 多为 DAG + 条件分支 | 超步批量执行天然匹配 |
| 多节点并行 | 同超步并行,步末同步 |
| 可复现、可 checkpoint | 离散超步边界好快照 |
| 代价 | 非低延迟点对点;环需 recursion_limit |
2. 节点为何不直连
| 直连 | 经 Channel |
|---|---|
| 拓扑硬编码在调用栈 | 订阅/边声明依赖 |
| 难合并多写 | reducer 在步末统一 |
| 难持久化 | checkpoint 按 channel 存 |
3. 版本控制(channel version)
超步末 channel 版本递增;调度根据「自上次读后是否有更新」决定激活哪些节点。
保证:同一超步内读的是一致快照,避免数据竞争。
4. 分层架构
| 层 | 可替换性 |
|---|---|
| Channels | 新 reducer 类型 |
| Checkpointer | Memory / SQL / 云 |
| Pregel | 调度策略演进 |
| Graph | API 稳定面 |
上层不感知 saver 具体实现。
5. Checkpoint 而非纯事件溯源
| Checkpoint | 事件溯源 |
|---|---|
| 恢复快、实现简单 | 重放成本高 |
| 存储步级快照 | 日志无限增长 |
| 适合 Agent 状态机 | 适合审计型系统 |
LangGraph 以 快照 + 可选 Store 为主。
6. Graph 为何要 compile
- 校验图结构,早失败。
- State → Channel 映射一次完成,运行时无反射构图。
- 生成不可变 Pregel 配置,便于缓存与类型推断。
7. 多种 Stream 模式
不同消费者需要不同粒度:UI 要 token(messages),仪表盘要 state diff(updates),调试要超步(debug)。单模式无法满足。
8. interrupt 后为何重跑节点
resume 从 checkpoint 恢复 后,引擎按 Pregel 语义 重新调度该节点(函数从头执行),以保证与未 interrupt 路径相同的合并逻辑。
实践:副作用放 interrupt 之后,或根据 resume 参数跳过。
9. TypeScript 优先
与 LangChain JS 生态一致;类型化 State/Annotation 减少图配置错误。
10. 多种 Checkpointer
| 场景 | 实现 |
|---|---|
| 单测 / 本地 | Memory |
| 生产多实例 | Postgres 等 |
| 长期记忆 | Store API 与 checkpoint 分工 |
总结
LangGraph 的设计主轴:BSP + Channel 中介 + 超步 checkpoint + 声明式 Graph。排错时沿这条链逐层查。