Harness 竞速
第一次让两个 harness 跑同一个 brief 互拼,你做这件事是因为决不出 Codex 还是 Claude Code 在你的代码库上更好。第二次做,是因为 Aider 快了 40%、diff 也更干净——你想知道哪个 harness 在哪类任务上赢。到第十次,你跑竞速是因为它比靠猜便宜。
SprintLoop 里的harness 是执行 brief 的 agent 运行时:Claude Code、Codex CLI、Cursor Compose、Aider、Devin,或任意通过 harness adapter API 接入的 harness。竞速 指把同一个 brief 并行 dispatch 给两个或更多 harness,落进同级的若干 lane 中,让它们都跑完(或被首位 sign-off 一口气杀掉),再用 diff comparator 而不是直觉挑赢家。
为什么要跑竞速
经得起认真成本分析的三个理由:
- 质量。 不同 harness 犯的错不同。Claude 倾向于 commit message 解释过头、边界用例测得不够;Codex 倾向于注释不够、refactor 过度;Aider 又快又外科手术式,但碰到含糊的 brief 会卡住。winner picker 不在乎这些风格差异——它按 diff 大小、测试覆盖率变化、lint 通过、Review Committee 判定打分。在真正重要的那些 run 上,你拿到的是整组里最好的。
- 速度。 竞速 dispatch 在第一个产出过关 diff 的 harness 那里结束(CI 绿、没有阻塞判定)。在并行工作上,这通常比让 harness 串行跑、失败再 fallback 快 30–50%。
- 成本控制。 这是反直觉的一条。你会以为竞速代价是 N 倍。实际上第二名 harness 在它的预算被花掉大半之前就被杀掉了——我们遥测里被 cancel 的 lane 中位数只消耗赢家 18% 的 token。所以一场三路竞速通常是单次 dispatch 的 1.4–1.6 倍,而不是 3 倍。
反对竞速的情形是:brief 很 trivial(“重命名这个变量”)、或你对特定类工作就信某个 harness(“这个仓库里所有小 refactor 都是 Aider 赢”)。这没问题——竞速是 per-dispatch opt-in,工作区会记住哪些 brief 你跑了竞速、哪些没跑。
comparator 怎么选赢家
竞速里每条跑完的 lane 退出时带着一个分数。分数是这些信号的线性组合:
| 信号 | 权重 | 来源 |
|---|---|---|
| CI green | 0.30 | GitHub / GitLab status checks |
| Reviewer verdict | 0.25 | Review Committee (Architect, Security, QA) |
| Diff size delta | 0.15 | 相对 brief 估算的 LOC 增减 |
| Test coverage delta | 0.15 | 覆盖率工具输出 (jest, pytest, go test) |
| Lint clean | 0.08 | 仓库声明的任何 linter |
| Wall time | 0.07 | 首个完成的奖励(90 秒后衰减) |
权重可在 Settings → Racing 按工作区配置。上述默认值是基于约 14,000 场竞速、六个月的内部遥测调出来的;要把产品交付到受监管行业的团队,通常会把 reviewer verdict 权重调高、diff size 权重调低。
竞速里第一条 lane 一发出”ready for review”信号,comparator 就开始跑。打平(5% 之内)会浮出一个 picker —— 人类 dispatcher 拿到并排 diff 视图自己挑。平局区间之外,则自动晋升赢家、cancel 其他同级。
什么被 cancel,什么留下
comparator 选出赢家后,同级 lane 转入 canceled,其作用域 claim 立即释放。它们的 tool log 和签名条目永远留在审计台账上——没有纸面记录的竞速是最差形态的浪费——你可以打开任意一条被 cancel 的 lane 的 diff,看看输家试过什么。
关于被 cancel 的同级,两件事要知道:
- 它们的 commit 不会被 push。 一条被 cancel 的 lane 不会开 PR。它的分支留在 SprintLoop worker 本地,归档,30 天内若未打 tag 即被清理。
- 它们的 tool call 和模型支出仍计入账单。 cancel 阻止的是新的 token 消耗,不会追回已经花掉的。这就是 comparator 的”首个完成奖励”为什么有用——快的输家比慢的输家便宜。
常见竞速及其用法
我们最常见到的竞速组合:
- Claude Code vs. Codex 跑功能实现。 非 trivial 工作的默认。两个 harness 的强项有实质差异——Claude 强在架构,Codex 强在紧凑、地道的实现——comparator 多半能干净利落地破局。
- Aider vs. Codex 跑小 refactor。 知道工作是机械性的时候,Aider 更小的表面积常常在速度上赢,Codex 提供一道理智检查:refactor 没有跑偏。
- 三路跑难缠的 bug。 Claude Code、Codex、Cursor Compose。要省着用——通常是单 harness dispatch 已经失败之后才用。
- 同一个 harness、两个不同 prompt。 同 harness 不同 brief。主要用于 prompt 工程实验——有用,但一旦选定赢家 prompt 就关掉。
你会真正看到的成本
200 行规模功能的一场三路竞速,按现行模型价格通常落在 $0.40–$1.20 区间——具体看你拼哪几个 harness 以及 maxTokens 配得多激进。输方 lane 会在赢方 CI 信号产生后几秒内被 comparator 杀掉,所以 token 支出的长尾是有界的。
工作区设置里有每日竞速预算。超额后,后续竞速会降级为单 harness dispatch 并显示一条横幅。这是软性控制——可以内联覆盖——但它已经把好几个团队从一种失控循环里救出来:默认开着竞速,所有 brief 都被竞速。
启动你的第一场竞速
Cmd+N 打开 dispatch 对话框。在 harness picker 下面,把 Race 切开。挑两到三个 harness(每个都要有 key——见 Get started)。如果你的工作区设了预算上限,把它设进去。Dispatch。
dispatch 返回 N 个同级 lane ID。每条都在 Lanes 面板里渲染成自己的卡片;这些卡片在视觉上分组在一个 “Race” 头下,附带实时赢家指示。点任意一张卡,就能落到那条 lane 的 tool log 和 diff。
赢家选出后,竞速头会折叠进赢方的 lane 卡片,其余卡片归档到一个 “Canceled siblings” 折叠区。事后可以点进任意一条 inspect。