将 Python 工作流检查点升级到 1.13.0

Agent Framework 1.13.0 包含针对 Python 工作流执行的少量破坏性更改。 大多数应用程序 不需要 更改。 这些更改会影响那些依赖精确超级步数或迭代次数、在收敛边界设置 max_iterations、检查初始消息源 ID,或对检查点的位置和顺序作出假设的应用程序。

背景

在 1.13.0 之前,检查点机制并未完全兑现其以下承诺:捕获从任何已记录边界恢复执行所需的工作流状态。 启动执行程序在超级步骤和检查点循环之前运行,因此最早的检查点包含启动执行程序的输出和更新状态,但不包含原始工作流输入。 同样,对请求事件的响应是在未首先记录在检查点中的情况下传递和处理的。 因此,任何检查点都无法基于原始输入重新执行起始执行器,也无法根据已返回的响应复现人工参与的后续流程。

行为变更

版本 1.13.0 会缩小这些差距。 启动执行器现在会在第一个超步中运行;入口检查点会在该超步开始前记录初始输入;响应入口检查点会在响应被处理之前记录已传递的响应。 这些更改一起使设有检查点的工作流完全可从其输入(包括人工干预延续)中重播。

Important

这些更改不会影响版本 1.13.0 之前创建的检查点。 现有检查点仍受支持,在升级后仍可还原。

可能需要采取措施的更改

Area 1.13.0 之前 在 1.13.0 及更高版本中 用户影响
启动执行程序 启动执行程序在超级步骤循环之前运行。 该输入会排队等待启动执行器处理,而启动执行器会在第一个超级步骤中运行。 每次重新运行都会额外发出一个 superstep_started 事件和一个 superstep_completed 事件。
迭代次数 迭代 1 表示启动执行程序运行后的第一个超级步骤。 迭代 1 运行启动执行程序。 以后的工作会通过一次迭代进行轮换。 以前需要 $N$ 迭代的工作流现在需要 $N + 1$。
输入消息源 初始消息具有硬编码的源 ID "Workflow" 初始消息通过启动执行程序的内部边缘传递,并具有源 ID INTERNAL_SOURCE_ID(start_executor.id) 读取或筛选初始消息源 ID 的代码必须使用新值。

可重播性改进

Area 1.13.0 之前 在 1.13.0 及更高版本中 改进
初始检查点 迭代 0 检查点是在启动执行程序运行后创建的。 它捕获执行程序的输出消息和更新状态,但未捕获原始输入。 在超级步骤 1 之前创建入口检查点。 它会记录排队等待启动执行器处理的原始输入。 还原入口检查点会重放整个运行过程,包括起始执行器。
响应检查点 对请求事件的响应在响应先记录到检查点之前就已传递。 响应入口检查点是在响应被传递之后、使用该响应的超级步骤运行之前创建的。 还原响应入口检查点会重播使用响应的延续。

更新超级步事件处理

现在重新运行一次工作流会额外产生一对超级步事件,因为起始执行器是在超级步 1 中运行的:

  • superstep_startediteration == 1
  • superstep_completediteration == 1

后续执行程序的工作会通过一个超级步骤进行轮换。 更新测试、遥测、进度指示器或其他代码,该代码假定确切的事件计数或将特定执行程序映射到固定迭代。

无需依赖事件类型计数或迭代即可响应事件类型的代码无需更改。

查看最大迭代限制

max_iterations 限制现在包括运行启动执行程序的超级步骤。 如果工作流以前使用了其完整限制,请将配置的值增加一个:

from agent_framework import WorkflowBuilder

workflow = WorkflowBuilder(
    start_executor=start_executor,
    max_iterations=previous_max_iterations + 1,
).build()

如果工作流在达到配置的限制之前已聚合,则无需更改。

更新初始消息源检查

如果起始执行器消费了初始消息的源 ID,请将硬编码的 "Workflow" 值替换为该起始执行器内部边的源 ID。

在 1.13.0 之前:

is_workflow_input = ctx.source_executor_ids != ["Workflow"]

在 1.13.0 及更高版本中:

from agent_framework import INTERNAL_SOURCE_ID

is_workflow_input = ctx.source_executor_ids != [INTERNAL_SOURCE_ID(self.id)]

INTERNAL_SOURCE_ID(executor_id) 当前返回 "internal:<executor_id>"。 使用帮助程序而不是构造此字符串,使代码遵循框架的源 ID 格式。

更新检查点处理方式

初始输入检查点

启用检查点后,现在每次全新运行都会在 iteration_count == 0 处创建一个入口检查点。 此检查点包含作为发送给启动执行程序的传输中消息的原始输入。 还原它会重新运行启动执行程序,并重现完整的工作流运行。

完成每个超级步骤后,框架将继续创建检查点。 对于包含 $N$ 个超级步的运行,预计会有 $N + 1$ 个检查点:即一个入口检查点,以及每个已完成超级步对应的一个检查点。

查看假设迭代 0 检查点包含由启动执行程序生成的状态的代码。 该状态现在显示在超级步骤 1 之后创建的检查点中。

请求响应检查点

使用 workflow.run(responses=...) 继续执行工作流时,框架现在会在将响应加入队列后、运行使用这些响应的超级步骤之前创建一个响应入口检查点。 还原此检查点会重新发送已记录的响应,并重放工作流的其余部分。

响应入口检查点与包含挂起请求的上一个检查点具有相同的 iteration_count。 它是一个独立的检查点,其 previous_checkpoint_id 指向该待处理请求检查点。

Important

在人工干预检查点历史记录中,并不保证 iteration_count 是唯一的。 按照 previous_checkpoint_id 链确定检查点顺序。 如果需要最新的检查点,请使用检查点存储 API,而不是选择最大的 iteration_count检查点。

迁移清单

  • 更新依赖于确切的超级步骤数或迭代数的断言和事件使用者。
  • 仅对达到前一限制的工作流将 max_iterations 增加 1。
  • 将针对 "Workflow" 的初始源 ID 检查项替换为 INTERNAL_SOURCE_ID(start_executor.id)
  • 将迭代 0 检查点视为执行前输入检查点。
  • 按谱系对人工参与的检查点进行排序,而不要假定 iteration_count 是唯一的。
  • 验证重播入口检查点和响应入口检查点是否会产生预期的输出和副作用。

有关实现细节,请参阅 允许工作流检查点完全重放