又重构了 Workflow
最近整理自己的 Coding Agent Skills 时,我拿同一个需求试了两条执行路径:一条走 Quick,另一条从 to-spec 之后 fork 新对话,接着走 to-tickets 和 Graph Workflow。
Quick 用了 1 小时 12 分钟,Graph 用了 1 小时 37 分钟,后者的 Token 消耗是前者的 3 倍。相比多花的 25 分钟,我更在意 Token 的差距,想重新看看这些额外成本究竟换来了什么。
一次对比还不足以说明 Graph 普遍不划算,也不能直接把差额归到拆 Ticket 或多 Agent 上。交接、重复读取上下文、验证和返工各花了多少,还需要进一步记录。不过,这次执行留下的 Ticket 已经暴露了一个可以先处理的问题。
我原本想用 Ticket 的 Frontier 简化状态管理,结果打开最终产物,里面仍然放着 lifecycle、attempt、evidence、blocker 和 authority。一张 Ticket 同时写着要交付什么、如何验收,以及这次执行走到了哪里。每个字段都有保留的理由,放在一起,Ticket 却越来越像一份运行记录。
交付要求和执行进度的变化频率不同。Toast 应该在什么条件下显示、取消时是否触发完成回调,这些属于交付契约;当前是第几次 attempt、被什么问题阻塞、哪次检查支持了完成判断,这些属于执行状态。两者写在同一个文件里,更新进度时就得同时改动契约文件。
这次 v4 调整保留了 Frontier 的原有语义,把 lifecycle、attempt、evidence、blocker 和 authority 移到任务目录里的 .loop/state.json。Ticket 继续保存交付内容、约束、依赖和验收条件,普通状态流转只更新运行状态。
这些状态只用于本地这一次执行,不进入 Git,暂时不考虑跨机器同步。为了保存临时进度,再维护一套同步和恢复系统,这次简化又会重新变复杂。
临时状态仍然关系到执行正确性。状态文件丢失后,系统不能把已有 Ticket 当作从未执行过,直接再跑一遍,而要停下来告诉我进度已经丢失,由我确认是否重新初始化。
执行策略也一起明确了:默认 serial,需要时由我显式选择 swarm。
拆出多张 Ticket 可以帮助表达依赖和验收边界,但是否值得并行,还要看具体任务:共享文件、构建缓存、测试进程和未确定的接口,都可能让看起来独立的工作互相影响。Frontier 给出可执行候选,派发前仍要检查这些条件。
串行执行时,我会尽量复用同一个 worker 的上下文,但复用不能把两张 Ticket 的职责混在一起:当前任务、写入范围、验收条件和已有改动仍然要交代清楚,证据也要对应各自的 attempt。没有必要为了强行复用,再做一个 Agent 池或会话恢复层。
这些调整已经包含在 v4 的状态分离提交 (opens in a new window)中。契约和运行状态分开了,默认执行策略也明确了,但耗时和 Token 能减少多少,还要看实际运行结果。
下一轮对比,我会记录模型、起始代码、需求和验收标准,再一起看耗时、Token、返工和最终交付结果。Graph 多出的步骤如果能减少遗漏、保留可追溯的证据,就有它的价值;如果只是让 Agent 多读几遍同样的材料,就应该继续删。
我想保留一套足够小、足够稳定的工程流程。每增加一个状态或交接步骤,都应该说清楚它解决了什么问题,以及为什么值得长期维护。