概述

LangGraph 通过检查点支持时间旅行:
  • 重放:从一个先前的检查点重试。
  • 分支:从一个先前的检查点创建分支,并通过修改状态来探索替代路径。
两者的工作原理都是从一个先前的检查点恢复执行。检查点之前的节点不会被重新执行(结果已保存)。检查点之后的节点会重新执行,包括任何 LLM 调用、API 请求和中断(这些操作可能产生不同的结果)。

重放

使用一个先前检查点的配置来调用图,即可从该点开始重放。
重放会重新执行节点——它不仅仅是从缓存中读取。LLM 调用、API 请求和中断会再次触发,并且可能返回不同的结果。从最终检查点(没有 next 节点)重放是一个空操作。
重放 使用 get_state_history 来查找你想要重放的检查点,然后使用该检查点的配置调用 invoke:

分支

分支从一个过去的检查点创建一个新的分支,并修改其状态。对先前的检查点调用 update_state 以创建分支,然后使用 None 调用 invoke 以继续执行。 分支
update_state 不会回滚线程。它会创建一个新的检查点,该检查点从指定的点分支出来。原始的执行历史记录保持不变。

从特定节点开始

当你调用 update_state 时,值会使用指定节点的写入器(包括规约器)来应用。检查点会记录该节点产生了更新,并从该节点的后继节点处恢复执行。 默认情况下,LangGraph 会根据检查点的版本历史推断 as_node。从特定检查点进行分支时,这种推断几乎总是正确的。 在以下情况下需要显式指定 as_node:
  • 并行分支:多个节点在同一步骤更新了状态,LangGraph 无法确定哪个是最后一个(会抛出 InvalidUpdateError)。
  • 无执行历史:在一个新线程上设置状态(在测试中很常见)。
  • 跳过节点:将 as_node 设置为一个后续节点,让图认为该节点已经运行过。

中断

如果你的图使用了 interrupt 来实现人在回路中的工作流,那么在时间旅行期间中断总是会被重新触发。包含中断的节点会重新执行,interrupt() 会暂停以等待新的 Command(resume=...)。

多个中断

如果你的图在多个点收集输入(例如一个多步表单),你可以从两个中断之间进行分支,以更改后续答案,而无需重新询问先前的问题。

子图

与子图一起使用时间旅行取决于子图是否有自己的检查器。这决定了你可以进行时间旅行的检查点的粒度。
默认情况下,子图会继承父图的检查器。父图将整个子图视为一个单一的超步骤——对于整个子图的执行,只有一个父级检查点。从子图之前进行时间旅行会使其从头开始重新执行。在默认子图中,你无法时间旅行到节点 之间 的点——你只能从父级进行时间旅行。
有关配置子图检查器的更多信息,请参阅子图持久化。