有时下一跳取决于节点内部逻辑(刚调了外部 API 才知道去哪个子流程),单独抽 router 函数显得割裂。Command 让节点同时返回 state 更新 与 goto 目标,实现动态跳转。
1. 定位
| 维度 | 内容 |
|---|---|
| 角色 | 节点内声明下一节点(动态边) |
| 输入 → 输出 | 节点返回 Command(update=..., goto=...) |
| 核心 API | Command、goto |
| 依赖 LangChain | 无 |
2. 图拓扑
节点表
| 节点名 | 职责 | 读 State | 写 State |
|---|---|---|---|
dispatch |
决定分支 | mode |
mode, log |
path_a |
分支 A | — | log |
path_b |
分支 B | — | log |
边表
| 源 | 目标 | 类型 |
|---|---|---|
| START | dispatch | 固定 |
| dispatch | path_a / path_b | Command.goto(动态) |
| path_a | END | 固定 |
| path_b | END | 固定 |
使用 Command 时,dispatch 不必再
add_conditional_edges;但仍需注册 path_a、path_b 节点。
3. invoke 生命周期
1 | 1. dispatch 读 mode="b" |
Superstep:Command 在节点执行结束的同一 superstep 应用 update 并解析 goto。
4. 原理
4.1 Command 结构
1 | from langgraph.types import Command |
goto 可以是节点名、END 或 Send 列表(高级)。
4.2 与 conditional_edges 选型
- 分支逻辑简单、可读性优先 → conditional_edges
- 分支与节点副作用紧耦合 → Command
4.3 resume 场景
interrupt 恢复时也常用 Command(resume=...)(见中断专篇)。
5. 最小可运行示例
1 | import operator |
6. 执行追踪
mode=”b”
| 步骤 | 节点 | log |
|---|---|---|
| 1 | dispatch | ["goto:path_b"] |
| 2 | path_b | ["goto:path_b","ran_b"] |
mode=”a”:dispatch goto path_a,不会执行 path_b。
重要配置参数
| 参数 | 类型 / 默认 | 作用与影响 | 参考起点 | 配置指导 |
|---|---|---|---|---|
Command(update=...) |
dict | partial state | 与节点返回一致 | 可仅 goto |
Command(goto=...) |
str / END | 下一节点 | 动态名 | 必须已 add_node |
Command(resume=...) |
Any | 中断恢复 | HITL 篇 | 与 interrupt 成对 |
| 无 static 出边 | — | dispatch 靠 Command | 单入口 | path 仍要 add_edge→END |
| goto 无效节点 | — | 运行错误 | 单元测试 | 枚举目标名 |
| 与 Send 组合 | list[Send] | 动态并行 | map 场景 | 见 Send 篇 |
7. 易踩坑
- goto 目标未 add_node:invoke 失败。
- 同时写 conditional_edges 与 Command:可能冲突,择一。
- Command 未 import 正确路径:
langgraph.types.Command。
小结
- Command 把「更新 state」和「下一跳」合成一次返回。
- 适合节点内决策跳转;简单分支仍推荐 conditional_edges + path_map。
- 恢复流程用 Command(resume=…) 与 interrupt 配合。