软件需要在生产环境中进行变更。新需求、错误修复和重构最终都会体现在你的图代码中。由于 LangGraph 会将最新部署的图代码应用于为现有线程持久化的状态,因此你发布的每一次更改,实际上都是针对现有检查点的一次向后兼容的 API 变更。 与那些将运行绑定到其启动时代码版本的 workflow 引擎不同,LangGraph 会立即将最新图应用于所有线程,无论是新线程还是从检查点恢复的线程。这很方便:错误修复无需仪式即可传播到进行中的对话和智能体中。这也意味着你必须考虑每次更改如何与在先前代码版本下启动的运行进行交互。 需要关注三类兼容性问题,大致按你将会遇到的顺序排列:
  1. 技术兼容性:最常见;新代码必须能够加载并针对现有 State 执行。
  2. 业务兼容性:较少见;即使代码已更改,现有运行应继续遵循旧的业务逻辑。
  3. 非确定性:仅适用于函数式 API。
关于运行时默认支持哪些图拓扑和状态更改的简要总结,请参阅图迁移。本页的其余部分涵盖了当更改超出该支持集时你可以应用的模式。

技术兼容性

技术兼容性相当于微服务中的 API 破坏性更改。此处的 “API” 是你的图代码与检查点库为现有线程已持久化的数据之间的契约。当线程恢复时,LangGraph 会反序列化保存的状态,按名称将其分派给一个节点,并期望该节点返回符合状态模式的值。 常见的技术性破坏包括:
  • 在线程暂停或即将进入某个节点时(例如在 interrupt 处或通过一个仍然路由到旧名称的检查点条件边),重命名或删除该节点。恢复时,LangGraph 无法通过其保存的名称找到该节点,运行将失败。恢复运行的起点是执行停止时所在节点的开头,因此缺少的节点将无法从任何地方恢复。
  • 重命名或删除 State 键,而旧的检查点仍然包含该键,或者下游节点仍然读取该键。
  • 收紧 State 字段,例如将 Optional 字段设为必填、收窄类型,或添加没有默认值的新必填字段。现有检查点将无法满足新模式。
边拓扑本身不会在检查点中持久化。在仍然存在的节点之间添加、删除或重新路由边对于进行中的线程是安全的。根据图迁移总结,唯一可能中断被暂停线程的拓扑更改是重命名或删除节点。

推荐模式

  • 将新 state 字段标记为可选(z.string().optional() 或 .nullish()),以便旧检查点仍然有效。
  • 将删除操作视为弃用:将字段保留在模式中至少一个 drain 周期,以确保现有检查点继续加载。
  • 通过先添加后删除进行重命名:将新字段或节点与旧的并列添加,在一个弃用窗口期内双写或同时路由到两者,一旦没有进行中的线程依赖它,再将其删除。
  • 使用时间旅行和 graph.getState 在发布前于暂存环境中针对新代码抽查现有线程。

检测进行中的线程

在你删除节点、重命名 State 键或进行其他旧线程无法容忍的更改之前,你希望了解是否有任何线程当前正停在你即将移除的代码版本上。LangGraph 本身不维护线程状态的搜索索引,因此答案取决于你的图运行在哪里。 如果你部署到 LangSmith。 使用 Agent Server 的线程搜索功能按状态筛选。status 字段接受 idle、busy、interrupted 和 error,因此你可以批量查询 interrupted 或 busy 的线程,可选使用元数据过滤器进行缩小范围。参见按线程状态筛选和列出线程。 LangGraph 运行的任何地方。 使用 LangSmith 追踪来监控生产环境中哪些节点正在被进入和退出。这是判断一个节点或 state 字段是否在任何活动代码路径中都不可达的最可靠信号。 当你已经有一个 thread_id 时。 直接检查该单个线程: 如有疑问,请保留已弃用的节点或字段,直到 Agent Server 的线程列表和追踪显示其上不再有任何活动。

业务兼容性

有时,一个更改在技术上是有效的(每个现有检查点仍然加载,每个节点仍然解析),但新图的含义与旧图不同。新行为对于新线程是正确的,而你不想将其追溯应用于在旧逻辑下启动的线程。 例如,假设你的图运行 intake → triage → respond,而你决定在 triage 和 respond 之间插入一个新的 policy_check 步骤:
  • 已经通过 triage 的线程应直接继续到 respond(旧流程)。
  • 新线程应运行完整的新流程。
推荐的模式是在线程开始时在状态上记录相关的行为版本,然后通过条件边对其分支: 在 triage 之后恢复的旧线程会从其保存的状态中读取 flow_version(或回退到 v1 默认值)并跳过 policy_check。新线程从 intake 开始,被标记为 flow_version=2,并运行新路径。一旦所有 v1 线程完成,你就可以移除版本标志和条件边。 此模式仅在你在线程开始时设置版本时有效,在任何需要进行版本控制的分支之前设置。稍后设置它意味着现有线程在需要时将没有该设置。

非确定性

此类别仅适用于函数式 API 和图 API 节点内的 tasks 或 interrupt 调用。普通的图 API 节点在恢复时会从节点函数的开头重新运行;请将副作用设计为幂等的,但除非你在该节点中使用 tasks 或 interrupt,否则你无需保留任务调用顺序。 函数式 API 的 entrypoint 被编译为一个单独的节点,当运行恢复时,它会从头开始重放 entrypoint 体,并使用缓存的 @task 结果来跳过已完成的工作。两类更改会破坏此模型:
  • 在恢复点之前添加、删除或重新排序 @task 调用或 interrupt 调用。LangGraph 根据重放中的位置将缓存结果和恢复值与调用进行匹配,因此移动该位置可能会导致错误的缓存值被重放到另一个调用上。
  • 在 @task 之外引入非确定性操作,例如 time.time()、random.random() 或在 entrypoint 体中内联的网络调用。在重放时,这些操作会产生与首次运行时不同的值,这可能会改变控制流。
更深入的示例处理,请参见函数式 API 指南中的确定性和常见陷阱。 如果你需要对具有进行中运行的 @entrypoint 进行重大代码更改,最安全的选择是:
  • 在部署更改前让进行中的运行 drain 完毕。
  • 将任何新逻辑包装在一个新的 @task 中,以便其结果被独立检查点。
  • 在 langgraph.json 中为新行为注册一个具有新图名称的 entrypoint,并将新线程路由到它。