你睡觉时的代理:运行时很简单,流水线才难

·1 min read·Translated

每个用 AI 代理构建的开发者都有过同样的凌晨 3 点幻想。你去睡觉。一群代理翻看你的待办列表,修复 bug,构建功能,早上你审查一堆小的、经过测试、解释清楚的更改。糟糕的早上,你审查一场灾难,庆幸自己抓住了它。

我一直在努力让这成为现实,并且以艰难的方式学到了一件听起来显而易见的事:保持代理进程存活很简单。工作流水线才是真正的问题。

运行时是周末项目

有四种方式让代理全天候运行,没有一种很难:

  • tmux — 交互式代理能在断开连接和 SSH 注销后存活
  • cron + 打印模式 — 定时器上的 pi -p "check the failing tests",干净退出的一次性运行
  • RPC 模式 — 另一个程序与之对话的长生命周期进程
  • SDK 守护进程 — 把代理嵌入你自己的 Node 进程并循环处理队列

这些中的任何一种都能连续运行七十二小时而不抱怨。而且没有一种会产生哪怕一个有用的提交。因为问题从来不是「我如何保持进程存活?」而是:

  • 代理处理什么?
  • 完成意味着什么?
  • 工作如何落地?
  • 多个代理如何避免互相覆盖?

把这四样东西叫做任务源、完成定义、落地闸门和分配器。

大约 300 次运行教会我关于覆盖部分的东西

我在构建 gitaccord,一组 git hooks,让多个 AI 代理在一个仓库上并行工作。它的存在是因为我在实验中反复看到的失败:给多个有能力的代理同一个仓库,让它们自己挑选功能并用普通 git 落地自己的工作——没有中心人类合并权威。代理能很好地解决合并冲突。那不是危险。

危险是最后落地的代理悄悄重写另一个代理的功能以适应自己的,调整测试,并报告成功。在我们的实验中,用 Claude Code(Sonnet)和 pi(GLM)大约 300 次运行里,这在普通 git 上发生在 24–28% 的运行中。没有任何地方有恶意。每个代理都完全做了行为良好的独立代理应该做的事。失败是结构性的:代理看不到彼此的计划和推理,所以「merge」悄悄变成了「overwrite」。

gitaccord 的修复故意很无聊。每个代理一个分支。每个任务一个计划文件,每个代理都读。每个提交上有一行 Why: 解释推理。一个 pre-push 闸门拒绝落地任何破坏另一个代理功能的更改,除非它被声明为供人类审查的 Override:。在同样约 300 次运行中:静默覆盖降到 0%,main 从未被留下损坏,每个没有赢家的决定都被标记给人类而不是被静默解决。

所以在四块中,我会说落地闸门和分配器是可解决的——主要用约定和 hooks,而不是新平台。

哪些工作真正能在夜间完成

约束不是代理的能力。而是完成是否可由机器检查。一个睡着的人类不能在凌晨 3 点被问「这是你想要的功能吗?」

什么有效:

  • 有失败复现的 bug 修复。 红测试变绿,完整套件通过,diff 很小。
  • 在现有代码上扩展测试覆盖——覆盖率上升,行为被证明不变。
  • 完全指定的小功能从人类写的计划中切片出来。
  • 依赖升级,由套件决定。
  • 分诊——复现 bug 报告,写失败测试,在分支上起草修复。它甚至不需要落地。

夜间什么无效——这是许多 24/7 代理梦想悄悄死去的地方:

  • 「弄清楚下一步该构建什么。」 开放式方向没有机器可检查的完成。不过有一个正确的形状:代理在它的分支上写一份提案 + spike + 失败的验收测试并不落地它。你早上批准方向。落地自主性一直是更容易的问题;方向自主性是你应该保留的那个。

夜间循环

当它工作时整体看起来像这样:

晚上            夜间                               早上
─────────          ──────────────────────────────      ──────────────
人类写/修剪待办 ──▶ 代理挑选任务 N                    人类阅读摘要:
                   写它的计划                         ▸ 落地了什么
                   实现、测试、提交                    ▸ 标记的覆盖 &
                   合并 main,通过闸门                   没有赢家的决定
                   为任务 N+1 重复 …                  ▸ 等待方向的提案

让它活到早上的规则:

  • 小任务。 长自主运行因上下文漂移而腐烂。每个任务一个 bug,每个功能一个切片。
  • 有界自主。 每晚上限,每次运行预算,每代理分支。失败的任务被记录,循环继续而不是 thrashing。
  • 你必须读的一个输出: 标记队列。系统的工作是让那个队列短且高信号——Override: 和没有赢家的决定——这样你的早上审查是几分钟,而不是几小时。

不过注意真正的工程住在哪里。守护进程循环是一百行。待办格式、分配器、摘要生成器——人类方向和代理执行之间的那层胶水才是真正的构建。几乎没有人把它产品化,因为每个人(包括我)都一直卡在打磨代理运行时上。

我现在在哪里,老实说

我还没有夜间循环在运行。我有艰难的中间部分在进行中:当没有人类闸门时阻止代理破坏彼此工作的 hooks 和约定。运行时选项就在那里准备好了。缺失的部分是无聊的流水线——我的计划是先在 gitaccord 自己上运行它:把每个 hook 从实验移植到真实实现的待办会自己写出来,如果夜间代理弄坏了什么,我自己的落地闸门是学习这一点最便宜的地方。

我想从你那里听到什么

如果你试过无人值守运行代理——或决定不这么做——我想听听它在哪里坏了:

  • 你的任务源是什么?待办文件、GitHub issues,还是别的?
  • 你的完成定义是什么样的,代理有没有找到漏洞?
  • 你让工作直接落到 main 分支,还是排队等早上审查?
  • 有没有人发布过好的任务分配器 / 摘要工具,还是大家都在手搓?

运行时战争结束了。流水线才是赢或输的地方。

Share