Browse this library

Chinese source article

3 · 计划执行与系统:让长任务持续向目标收敛

从任务分解、滚动计划和工具交互出发,建立事实状态、进度验证、checkpoint、回滚与 Harness 之间的完整执行闭环。

View original Markdown ↗

模型会列计划,不等于它会完成长任务。列出十个步骤只发生在某一个时刻;真正的执行却要面对几十轮甚至几百轮环境变化。文件可能被别人改过,依赖可能安装失败,网页内容会更新,前一步的输出也可能只完成了一半。计划如果仍然停留在最初那张清单上,它很快就会从行动依据变成一段装饰文字。

这一章研究的对象是**「可持续执行」**:Agent 在一段长轨迹中,能够把目标拆成可验证的子目标,根据环境反馈修订下一步,并且始终知道哪些事实已经成立、哪些结论仍待确认、失败后应从哪里恢复。它关心的基本循环可以写成:

gt,st→decompose / planat→toolot+1→verifyst+1,pt+1→replanat+1.g_t, s_t \xrightarrow{\text{decompose / plan}} a_t \xrightarrow{\text{tool}} o_{t+1} \xrightarrow{\text{verify}} s_{t+1}, p_{t+1} \xrightarrow{\text{replan}} a_{t+1}.

这里 gtg_t 是当前有效目标,sts_t 是已经核实的事实状态,ata_t 是准备执行的动作,ot+1o_{t+1} 是工具和环境返回的原始观察,pt+1p_{t+1} 是经过验证的进度。verify 决定观察能否提交为事实。工具返回成功只表示调用完成;文件内容、测试覆盖和远端状态仍需独立检查。一次完整执行由「动作—观察—验证—状态提交」四步组成。

1. 从任务分解到滚动计划

任务分解给长任务建立结构。一个可执行子目标至少要包含四类信息:预期产物、完成判据、依赖条件和允许影响的范围。比如「修好构建」过于模糊;「定位当前构建错误,在不改变公开接口的前提下修复,并让相关类型检查与测试通过」才提供了可以检验的边界。粒度也不能无限缩小。若每次只计划一个字符级动作,协调成本会吞掉执行时间;若一个子目标覆盖数小时工作,Agent 又会失去中途校正的机会。

因此,长任务更适合采用滚动计划。系统保留较稳定的远期里程碑,只把眼前一小段展开成具体动作。每完成一个可验证切片,就用新状态重新计算后续路径:

Pt+1=Revise⁡(Pt,gt+1,st+1,et+1),P_{t+1}=\operatorname{Revise}(P_t, g_{t+1}, s_{t+1}, e_{t+1}),

其中 PtP_t 是旧计划,et+1e_{t+1} 表示新发现的约束、失败和外部变化。修订会保留仍然成立的依赖,删除已经失效的假设,并把阻塞项移出当前关键路径。计划由此承担决策作用:说明下一步为何值得做,以及完成后用什么证据判断是否继续。

计划还负责限制并行。多个子任务同时修改同一文件、共享同一个浏览器会话,或者争用同一外部资源时,并行会制造隐蔽冲突。依赖图应当区分三种边:数据依赖要求先后顺序,资源冲突要求互斥,信息独立才允许并行。执行槽是否满载不重要,系统需要提高的是有效进展的吞吐量。

1.1. 工具调用之后,状态由谁说了算

Agent 通过 shell、编辑器、浏览器、数据库或业务 API 获得局部观察, 再由这些观察逐步建立环境状态。原始观察进入上下文以后,还要经过解析和核实,才能成为事实状态。可以把状态拆成三层:

  • 意图状态记录目标、约束、计划和尚未回答的问题;
  • 事实状态记录已由环境证实的文件版本、测试结果、资源标识和外部返回;
  • 执行状态记录正在运行、已经完成、失败或等待的动作。

这三层不能互相冒充。计划里写着「已部署」属于意图或预测;只有部署接口返回、健康检查和目标版本共同吻合,它才进入事实状态。Agent 自己生成的摘要可以帮助压缩上下文,却不能覆盖环境里的真实文件。事实状态必须能够追溯到观察或产物,进度状态必须能够追溯到完成判据。

工具也需要有明确的读写语义。只读工具可以重复调用,用来确认状态;写工具可能产生外部副作用,必须记录目标、输入和返回;发送消息、支付、删除数据这类难以撤销的动作还要在执行前设置授权边界。对可重试操作,系统应当提供幂等键或先查询后写,避免一次超时造成两次真实提交。对不可幂等操作,「没收到成功响应」和「操作没有发生」是两件不同的事,恢复时必须先查事实状态。

2. 用可验证的不变量衡量进度

长轨迹很容易产生一种虚假繁忙:工具调用越来越多,日志越来越长,目标却没有明显接近。为此,系统需要把进度定义为一组逐步成立的不变量。设任务需要满足 mm 个完成条件 c1,…,cmc_1,\ldots,c_m,可以记录一个证据向量:

vt=(1[c1],…,1[cm]).v_t=(\mathbb{1}[c_1],\ldots,\mathbb{1}[c_m]).

向量中的一项只能在对应验证器通过后从 00 变为 11。某些修改会让旧条件重新失效,因此它也允许从 11 回到 00。这比「完成了 7/10 步」更可靠,因为计划中的步骤可以改变,而最终条件通常更稳定。单元测试、静态检查、页面截图、数据库查询和人工审批都可以成为验证器;关键是每个验证器只证明它实际覆盖的范围。

验证还要区分局部正确和全局一致。一个文件能解析,并不能证明站内链接都可达;一组单测通过,也不能证明真实浏览器路径没有问题。长任务每完成一个局部切片,可以运行低成本的近端检查;到里程碑处,再运行覆盖更广的回归检查。这样既避免每一步都支付全量验证成本,也避免把许多局部成功拼成一个未经证明的全局结论。

2.1. checkpoint、回滚与恢复

当轨迹足够长,失败一定会出现。恢复能力依赖 checkpoint,但 checkpoint 不是简单保存一段对话。一个可恢复检查点至少包括:目标与约束的当前版本、已核实事实、产物版本或提交标识、未完成动作、外部副作用记录,以及恢复后的第一项验证。上下文摘要只是其中一部分。

回滚也有两种含义。对本地文件和版本化配置,可以恢复到已知提交;对已经发送的邮件、已经创建的云资源,通常无法真正撤销,只能执行补偿动作。系统需要在写入前识别这一区别,并为副作用保留稳定标识。否则,Agent 在进程重启后只看见「上一步超时」,很可能再次发送或再次创建资源。

恢复流程应当先重新读取环境,再决定从哪一步继续。旧 checkpoint 提供候选状态,环境读数提供当前事实,二者之间的差异本身就是恢复输入。若文件已被外部修改,就基于新版本重算计划;若一个异步任务已经完成,就消费结果而不是重复启动;若验证条件已经失效,就把相应进度降级。可靠恢复的核心是重新建立事实,而不是忠实重放旧动作。

3. 计划何时应该重算

每得到一条观察就推倒整份计划,会让执行在多个方向间摆动;坚持旧计划直到失败,又会积累本可避免的成本。重算应由「决策相关变化」触发。设旧计划在新状态下的剩余代价为 J(Pt,st+1)J(P_t,s_{t+1}),重新求得的最好计划代价为 min⁡PJ(P,st+1)\min_P J(P,s_{t+1}),规划本身花费 CplanC_{\mathrm{plan}},那么全面重算至少应满足

J(Pt,st+1)−min⁡PJ(P,st+1)>Cplan.J(P_t,s_{t+1})-\min_P J(P,s_{t+1})>C_{\mathrm{plan}}.

实际系统很难精确求这个最小值,可以用几类信号近似:关键前提失效、关键路径改变、动作越过权限边界、验收条件被用户修改,或连续多步没有增加任何可验证证据。

局部偏差通常只需修补计划。十个相互独立的文件里有一个格式检查失败,修正该文件即可;如果失败暴露出共同使用的 schema 理解错误,九个后继产物都依赖这个假设,就要回到分解层重算。判断依据是依赖传播范围,并非错误消息看起来有多严重。

滚动计划还需要「承诺窗口」。窗口内的动作已经分配资源或产生准备成本,除非安全条件失效,否则不因微小评分波动频繁切换;窗口外只保留粗粒度里程碑,允许随证据调整。远期部分不假装掌握尚未出现的信息,近期部分又足够具体,可以直接执行和验收。

3.1. 并行执行的收益与证据合并

两个子任务没有文件冲突,也不代表它们适合并行。若任务 B 的方案选择依赖任务 A 的调查结论,提前执行 B 会产生大量返工。把子任务图记为 D=(V,Ed,Er)D=(V,E_d,E_r),EdE_d 表示结果依赖,ErE_r 表示资源互斥。候选集合 UU 只有在依赖前驱已经有可信证据、资源边互不冲突时才能同时启动:

∀u∈U, pred⁡Ed(u)⊆Qt,∀ui,uj∈U, (ui,uj)∉Er.\forall u\in U,\ \operatorname{pred}_{E_d}(u)\subseteq Q_t, \qquad \forall u_i,u_j\in U,\ (u_i,u_j)\notin E_r.

并行结果返回后还要合并证据。不同执行体可能依据不同时间点的文件、不同版本的目标或不同口径的测试得出结论。合并器先核对目标版本与输入版本,再检查产物是否重叠,收尾阶段运行覆盖交界面的验证。若两份结果都声称「测试通过」,但测试对应的提交哈希不同,它们无法直接证明合并后的状态正确。

协调不能只靠自然语言汇报。汇报可以说明做了什么,状态提交还需要机器可核对的对象:文件清单、版本标识、检查命令、退出状态和未覆盖范围。并行扩大搜索和生产吞吐量,也增加合并边界;如果验证成本超过节省的时间,串行执行会更快。

4. 失败预算与停止条件

长任务不能把「继续尝试」当作默认动作。同一路径连续失败时,系统要区分暂时性故障、方法错误和任务缺少必要条件。暂时性故障可以有限重试;方法错误要求换路线;缺少凭证、源数据或用户决策时,额外工具调用无法产生新信息。

设一次尝试成功的后验概率为 ptp_t,成功价值为 VV,再次尝试的时间与副作用成本为 CtC_t。只有 ptV>Ctp_tV>C_t 时,重试才有正期望。虽然这些量往往不能精确标定,系统仍可记录使 ptp_t 改变的证据:错误是否与上次相同、环境是否发生变化、替代端点是否可用、这次尝试是否加入了新的诊断。完全相同的输入、环境和动作,通常不会因为多执行几次突然成为正确方案。

停止也分层次。某个分支可以判定无望而不终止整个目标;一个外部源不可达时,可以记录缺口并继续独立部分;只有剩余验收条件都依赖同一缺失条件时,任务才真正阻塞。把阻塞绑定到具体完成条件,可以避免系统一遇到局部困难就宣告全局失败,也避免没有信息增益时继续制造忙碌日志。

4.1. 计划质量要看闭环,不看文案

计划写得细致,仍可能无法执行。评价一项计划可以沿四个问题展开:动作是否能由现有工具完成,动作结果是否可观测,观察能否由验证器判定,验证结果是否会改变后续选择。只要其中一环断开,计划就只是步骤清单。例如「调研并选择最佳方案」没有定义比较量;执行体即使收集很多材料,也不知道何时结束,更无法解释最终选择怎样由证据推出。

可以为每个计划节点记录五元组

ni=(ai,oi,vi,Δsi,bi),n_i=(a_i,o_i,v_i,\Delta s_i,b_i),

aia_i 是动作,oio_i 是预期观察,viv_i 是验证器,Δsi\Delta s_i 是通过后允许提交的状态变化,bib_i 是失败分支。这样,成功与失败都会产生下一步,而不会在异常返回后退回自由发挥。若 viv_i 只能验证局部性质,Δsi\Delta s_i 也必须保持局部,不能把一次语法检查通过升级成「功能已经正确」。

计划评测同样要进入真实闭环。仅比较模型生成的计划与参考文本,会惩罚有效的替代路径,也无法发现看似完整却不能被工具执行的步骤。更直接的指标包括:单位工具成本带来的验收条件增量、错误状态被提交前的拦截率、发生环境变化后的恢复步数,以及最终证据链中有多少结论能追溯到权威观察。它们测量的是计划推动任务收敛的能力。

还应报告「无效动作率」:没有改变事实、证据或可执行分支的调用占比。这个量持续升高,通常说明计划已经失去信息增益,需要缩小问题、换取新观测或停止当前分支。

4.2. Harness:把能力装进可执行的控制面

语言模型负责提出动作和解释观察,真正把长任务运行起来的是 Harness。它连接模型、工具、工作区、权限、状态存储和验证器,决定一次动作怎样被调用、结果怎样进入下一轮、何时保存 checkpoint,以及哪些状态变化可以提交。相同的模型放进不同 Harness,可能表现出明显不同的可靠性,因为模型能够使用的信息、动作边界和反馈质量都变了。

一个面向 Long-Horizon 的 Harness 至少需要承担五项职责:

  1. 将目标、事实和执行状态分开保存,避免自由文本摘要成为唯一真相;
  2. 为工具调用定义权限、超时、幂等和副作用记录;
  3. 在关键状态转移处触发验证,并把证据绑定到完成条件;
  4. 保存能够恢复的 checkpoint,进程中断后先校验再继续;
  5. 保留完整审计链,使错误能够定位到某次观察、决策或写入。

LongHorizon-Harness 将重点放在部署期的状态管理、审计和多轮执行闭环上,处理目标、事实和进度在长轨迹中的漂移。代码作为 Agent Harness 把代码执行看成控制层:Agent 可以用程序整理中间状态、调用工具、建立验证器,并把复杂流程固化为可检查的步骤。两篇材料共同描述模型策略、Harness 控制面和环境反馈如何组成 Long-Horizon 系统。

一条长任务轨迹可以拆成几个可检查的部件:目标是否保持,计划为何变化,工具结果是否被验证,事实由谁维护,失败从哪个 checkpoint 恢复,以及 Harness 在哪里阻止了局部错误继续传播。这套执行闭环也决定训练环境应收集怎样的轨迹、怎样定义 reward,以及 benchmark 究竟测模型还是整个 Agent 系统。