Loop 工程:让长时间运行的 agent 工作变得可持久

AI agent 擅长一个有界的回合。它不擅长「帮我盯这个一周」——因为那个请求活在聊天历史里,而聊天历史恰恰是会被压缩、被重启、被丢掉的那个东西。

future-loop 是 FutureOS 的答案。它把一个长时间运行的目标从对话里抽出来,变成一个可持久的目标:一张 todo 图、人工闸门、每步证据,以及一个可验证的「完成」定义,全部持久化到磁盘上、不依附任何会话。agent 仍然一次只执行一个有界的回合——但现在决定下一步做什么的是一个确定性的内核,而不是对话。

上一篇里跑 Matilda 铺砖用的就是这套机制。这篇讲这台机器本身是怎么工作的。

一次运行的形态

objective(目标)
   │
   ├─ todo 图(推进类 / 用户闸门 / 监控,--blocks 依赖)
   │
   ├─ 需要人工判断? ──▶ 问一个具体的问题并等待(用户闸门)
   │
   ├─ 可以继续吗? ──▶ 内核决策:跑这个 todo / 等待 / 重规划 / 停止
   │
   ▼
agent 执行一个有界回合 → 写下证据 → 内核决定下一个回合

要紧的心智模型是:编排者是一个 AI agent;loop 是它的看板和它的控制杆。 loop 不是驱动 agent 的规则引擎。它是 agent 对着工作的那块可持久看板,外加那些让人——或编排者——能把一次长运行拉回正轨的控制杆(steer、闸门、verify、租约)。

状态存在 <cwd>/.future/loop/,事件溯源、可重放。因为状态在项目里、而不在任何客户端里,一个在 TUI 里开启的目标可以从飞书聊天里驱动、在重启后捡起、或在本地 web 仪表盘里观察——都对着同一份账本。

承重的那些部件

目标与 todo。 一个目标分解成带优先级、依赖(--blocks)和类别的 todo——推进类(真正的工作)、用户闸门(一个人工决策)、监控、阻塞、协调。依赖构成一张 DAG,所以独立的工作并行跑,有依赖的等待。

Verify 闸门与证据——「完成」是被检查的,不是被声称的。 这是承重的想法。两个机制:

  • todo complete --evidence "..." —— 关闭一个 todo 必须说明到底落地了什么(路径、尝试 id、测量值)。空证据会被拒绝--force 是显式的、被记录的绕过。
  • todo add --verify "cmd"--acceptance "tok1,tok2" —— 内核在一个回合后运行该命令,只有退出码 0 才让该 todo 完成;或要求证据包含每一个 token。对确定性的交付物(编译通过、文件存在、验证器通过)的机器可检查闸门。

效果是:一个模型说「我做完了」不算完成。闸门跑过、证据非空,内核才接受这次交接。

租约(lease)。 谁持有一个 todo、到什么时候。持有者的 pid 被记录,所以死掉的进程的租约会被自动回收——杀掉一个 worker 后重启它不需要手动清理。

闸门(gate)。 一个开着的闸门挡住它的依赖项;独立的工作继续跑。闸门是一个决策点,不是工作项——你不「完成」它,而是 gate resolve 它,决策被记录。一个有作用域的闸门只冻结它的依赖项;全局闸门冻结一切。

交付闭环。 完成落在一个待定的 delivered 状态;操作员把它裁决为 verified / failed / rework。未验证的交付在几个回合后会自动派生一个跟进项,所以没有任何东西悄悄滑走。

should-run 内核。 调度、拒绝理由和花费都是确定性、可审计的(quota should-run/usage/spend/decisions)。给定状态,内核决定是跑一个 todo、等待、重规划还是停止——并且它能告诉你为什么

可观测性与 steer。 worker tail 流式输出一个 worker 的实时回合日志——它在调哪些工具、token/成本烧到哪了——这样编排者能在打断前先看一眼。supervisor steer 向 worker 注入可持久的引导;常规引导等到回合边界生效,--interrupt 中止进行中的会话以做紧急纠正。

故障恢复。 在回合边界写回之前退出的 worker(传输丢失、重试预算耗尽)会报告一条 infra_stopped 备注。彻底死掉的 worker 由一个独立的看门狗通过它死掉的租约发现——不需要花付费回合。这些是可恢复的:会话保留、上下文重放、运行恢复,且不消耗这次运行的错误预算。

skill 负责驾驶,CLI 是底层机制

你很少亲手敲这些命令。你说 /future-loop 帮我盯一下 X,agent 加载 future-loop skill——一份维护中的驾驶手册——并替你编排 future loop 命令:先查是否已有目标(绝不重复)、确认计划、带依赖和硬检查地分解、派发分离式回合、steer 跑偏的 worker、为不可逆决策开用户闸门、最后以经过验证的闭环收尾。

这个分工是刻意的。skill 拥有「什么时候做什么、怎么分解、怎么驾驶」——编排层。CLI 是底层机制——状态内核、硬检查、决策。skill 可以改变驾驶方式而不碰内核的保证。

一次具体的运行:Matilda

铺砖案例就是这套机器在负载下的样子。用户的提示以一条硬约束结尾——本会话内不要解任何东西——所以编排者只分解、调度、裁决、记账。全部数学都发生在四个 worker 会话里。

这些部件是如何显现的:

  • 一卡一 worker。 每个任务有唯一属主,所以四个并行模型从不去抢彼此的活。
  • Verify 闸门让「完成」可验证。 15 个交付物里 13 个过了闸门;一个被它挡住(下一轮补齐了工作);一个出错进入失败又恢复了。终审者重跑了验证器,而不是相信摘要。
  • Steer 救回了一个卡住的 worker。 glm 第一轮空转了约 40 分钟什么都没写盘;一次 steer 把它拉回来,9 分钟就交付了。
  • 共享板是唯一的跨 worker 通道。 worker 把简短结论追加到一个文件;各自有独立的产物目录,所以没人覆盖别人。
  • 故障恢复吸收了真实失败。 三次基础设施断连(glm 第一轮、gpt 第二、三轮)都自动恢复;重试成本约 ¥4.75,而不是一次丢失的运行。
  • 目标闭合了它的验证环。 最终答案——21,由一个构造和两个独立求解器对 20 的排除支撑——只有在终审者重跑通过后才成为「完成」。

结果在那篇里。这里的重点是:没有任何协调、验证或恢复是在聊天里即兴出来的——而是控制平面在 4.5 小时、15 轮里可持久地做了它的工作。

它是什么、不是什么

future-loop 是给一个 agent 编排者的看板加控制杆,带可持久状态和机器可检查的完成。它不是全自动规划器,也刻意不是取代 agent 判断的规则引擎——agent 仍决定每个回合怎么做;loop 决定下一个是什么是否安全、以及「完成」是不是真的

它也如实说明自己的局限:--verify 闸门检查确定性交付物,而不是研究的正确性;光有 token 不能确立事实;排队中的外部请求不是已验证的结果。这套机器的存在是为了让一次长 agent 运行可审计、可恢复——而不是假装把判断里难的部分变没。

完整的操作模型、每条命令和架构取舍在 FutureOS 仓库的 loop 控制平面文档里。把这一切都用了一遍的那次铺砖运行,是上一篇