跳转到主要内容

持久执行不等于持久推理:在不丢失意图的前提下为 Agent 状态做检查点

持久化 Agent 的步骤索引并不等于持久化它的任务状态。只对执行做检查点、而不对意图做检查点的系统,恢复后会进入一段流畅却前后不一致的运行。

服务器机架的近景,显示状态 LED 和接入交换机的带标签网线。

两种都叫「状态」的东西

Agent 运行时中的检查点通常记录一次运行的机械过程:图里的哪个节点执行了、调用了哪个工具、工具返回了什么、哪条边还在等待。这是执行状态。它足以回答「机器走到哪儿了」这个问题。

它不足以回答「机器想做什么,依据什么条件去做」。后者是意图状态:当前所理解的目标、这次运行接受的约束、已经承诺的假设,以及尚未履行的义务。执行状态是一个游标。意图状态是一份契约。

持久执行引擎擅长处理游标。它们重放一份步骤日志,跳过已完成的工作,在第一个未完成的步骤处交还控制权。对于一个含义在定义时就已固定的工作流来说,这是正确的行为。Agent 不是这样。它的含义在每一步都根据它能看到的 history 重新构建,而 history 并不等同于产生它的意图。只恢复游标而不恢复契约,运行不会崩溃。它会流畅地继续下去,朝着错误的方向,带着中断前那种同样自信的语气。

基于过时目标重新规划

一次运行在早期接受了一条约束:对生产数据集只做只读操作,或者把范围限制在单个租户内。运行中途,操作者扩大了范围,约束在编排器的配置中被更新。进程在下一步之前死掉了。恢复时,检查点里只有步骤索引和工具输出,没有当时生效的那条约束。Agent 从残留的 history 和当前配置中重新推导计划,而两者并不一致。transcript 里没有任何标记指出这道接缝。由此产生的计划内部自洽,对外却是错的。

重复的副作用

经典情形:最后一次工具调用成功了,但确认信息丢失了。一个在第一个未完成步骤处恢复的持久执行引擎会重新发起这次调用。如果这次调用是 charge_card、send_email 或 create_ticket,这次运行现在就有了两次。这不是推理失败,而是检查点契约失败。日志记录的是调用的意图,而不是效果的事实,而只有当效果本身携带一个下游系统能识别的键时,这两者才能被区分开。

假设漂移

Close-up of a modern building facade with geometric design and reflective windows

给定完全相同的历史,Agent 并不总会重新推导出完全相同的计划。采样、上下文截断和模型版本变化都会让分布发生偏移。一次重放历史并要求模型继续的恢复,会产生一个在给定历史下看似合理的计划,而不是当时正在进行中的那个计划。假设漂移是过时目标失效的安静版本:配置没有变,变的只是重建过程。运行看起来健康,却在偏离。

一份可用的检查点契约

解决办法是把检查点当作意图的序列化,执行状态只是其中若干字段之一。一份能被安全恢复的检查点应当原子地、一并携带:

  • 目标,以这次运行当前所承诺的形式,而不是它启动时的形式。
  • 已接受的约束,每一条都附带它在运行中被接受的时间点,以及断言它的来源。
  • 工具结果,以幂等键为索引,而不是以调用顺序为索引。
  • 未了结的义务:这次运行承诺要做但尚未做的事。
  • 一个 schema 版本,以便由旧版运行时写下的检查点能被识别出来。

让这套机制在实践中真正奏效的,是一个从稳定输入而非墙钟时间或序号推导出来的、以运行为作用域的幂等键:

key = hash(run_id, step_name, canonical_args)

每一个会产生副作用的工具调用都携带这个键。下游系统,或者它前面的一层薄适配器,会记录已经执行过的键,并在重放时返回先前的结果,而不是再次执行该效果。这个键必须在重试之间保持稳定,并在不同意图之间保持唯一;从步骤名和规范化参数而非计数器推导它,正是让重放在一次会重排或跳过步骤的重启之后仍然安全的原因。

第二个机制是拒绝。检查点携带一个 schema 版本,运行时拒绝跨不兼容版本恢复,而不是尝试尽力而为的迁移。意图的迁移就是一次重新![Colorful absIridescent swirls in a soap bubble texture, resembling an oil slickCircuit board macro

持久执行是一种默认做法,而不是普适的善。有三种情形主张重新进入,而不是继续。

跨越了授权边界的运行。 如果这次运行获得了某项权限、花掉了一笔预算,或者代表某个其授权被限定在某个会话内的主体行事,那么恢复就是在延续一项可能已不复存在的权限。这类运行应当重新进入审批。检查点可以作为证据保留;它不应被当作凭证使用。

长时间间隔。 外部事实是有半衰期的。一个价格、一个工单状态、一个部署状态、一个库存数量——每一个都是一次带隐式过期时间的缓存观测,而检查点并不记录这个过期时间。一次在间隔超过其工作集中最短半衰期之后恢复的运行,是在基于过时事实推理,却把它们当作当前事实呈现。诚实的做法是把过时当作重新规划的触发条件:让缓存的观测失效,重新获取下一步所依赖的那些,然后才继续。

不再成立的假设集。 如果任何一条已接受的约束在其来源处被撤回,这次运行就没有有效的延续。它有的是一次有效的重启。

权衡

持久化意图不是没有代价的。它意味着检查点会变大,意味着每条约束都需要一个来源字段,意味着运行时必须能区分「启动时的目标」和「修订后的目标」——而这又意味着目标修订必须是一次带日志条目的一等操作,而不是一次 prompt 编辑的副作用。它还意味着有些恢复会被拒绝,而一个天真的引擎本会完成它们;被拒绝的运行是可见的失败,而静默的延续则不是。

这种可见性正是关键所在。一个只对执行做检查点的运行时,会显得拥有极佳的恢复能力,直到第一次恢复进入一个自洽、自信却错误的计划——而到那时,失败已经在现实世界里,而不在日志里。

该记录什么

一条实用的规则:在写检查点函数之前,先写下一位新操作者要在不向原操作者询问任何问题的前提下中途接管这次运行,需要知道些什么。那份清单就是意图状态。步骤索引不在上面。上面的一切都应当放进检查点,带版本,并为这次运行可能对外部世界产生的每一个效果配上一个幂等键。持久推理是能在重启后存活下来的那个属性;持久执行只是让重启成为可能的机制。

封面照片:panumas nikhomkhai / Pexels。

分享XLinkedIn永久链接5 分钟阅读

相关阅读

这能回答的问题

What is the difference between execution state and intent state in an agent run?

Execution state is the cursor: which step ran, which tool returned what, what is pending. Intent state is the goal, the accepted constraints, the assumptions committed to, and the unresolved obligations. A checkpoint that stores only the cursor can resume the machine but not the reasoning.

Why do resumed agents produce duplicate side effects?

Because the journal records the intent to call a tool, not the fact of the effect. If the call succeeded but the acknowledgement was lost, replay re-issues it. Run-scoped idempotency keys derived from stable inputs let the downstream system recognise the replay and return the prior result instead of repeating the effect.

When should a run not be resumed?

When it crossed an authorisation boundary, when the gap since the last checkpoint exceeds the half-life of the external facts it depends on, or when an accepted constraint has been withdrawn at its source. These cases call for re-approval or re-planning, not continuation.

Should checkpoints be migrated across schema versions?

No. Migration of intent is a re-plan and should be an explicit, logged operation. The runtime should version the checkpoint schema and refuse to resume across incompatible versions rather than attempting a silent best-effort migration.