前两篇讲了为什么把散装 AI 工具拼成小队、任务卡长什么样。这篇是实战篇:怎么让这支小队在你睡觉的时候自己干活,早上起来活已经干完了。讲两件事——无人值守流水线由哪几块拼成、真正跑起来踩过的坑。所有数据来自一次真实的夜间运行,不是设想。

一、先看一次真实的夜班

不画饼,先放战绩。某天晚上到第二天凌晨,这条流水线的实际运行记录:

时间 发生了什么
23:00 额度窗口开启,自动派发启动
01:27–02:02 第一批任务卡陆续收口
03:00–03:55 崩溃面扫描、无障碍走查等卡完成
04:39 最后一次模型调用,额度基本打光
08:30 晨间战报自动推送:完成 25 张、受阻 4 张、剩余待领 14 张

连续跑了约 5 小时 40 分钟,把 3 亿单位的夜间额度用到只剩万分之零点五,收口十几张任务卡,全程没有人干预。我早上起来看到的是一条汇总消息,而不是一堆待处理的报错。

这不是 demo。是每天都在跑的东西。下面拆它是怎么拼起来的。

二、流水线由哪几块拼成

四个角色,各管一摊:

块 谁 干什么
大脑 Hermes(本地常驻 AI 助手) 拆卡、调度、验收、汇总,不直接写代码
手 ZCode / Qoder / WorkBuddy 真正改代码、跑测试的执行者
协议 .ai-tasks/ 任务卡收件箱 卡和证据链,角色之间靠它通信
心跳 cron 定时任务 到点触发派发、盯梢、续派、战报

关键设计是大脑和手分开。Hermes 不写代码,它管”谁来做、做没做完、做得对不对”。执行者只管按卡干活。两者之间不靠聊天记录,靠一张张任务卡——卡上写清任务、文件锁、红线,执行者不看上下文也能干。

这套分工在《任务卡长什么样》里拆过,这里不重复。这篇的重点是:怎么让它在没人盯着的时候,自己转起来。

三、让它自己转的五个机制

1. 额度窗口:知道什么时候有活干

执行者的免费额度不是随时都有,是按时间窗口恢复的。我用的 ZCode 规则是:

  • 平日:晚上 23:00 到次日 9:00
  • 周末:周五 23:00 一直连到周一 9:00(周五晚 + 周六全天 + 周日全天,约 58 小时)

流水线必须知道这个规则,否则要么在没额度时空转,要么在有额度时没人派活。判断逻辑就是一个共享脚本,输入当前时间,输出”在不在窗口内”。十个边界 case 全测过:周五 22:59 不在、23:00 在、周一 8:59 在、9:00 不在。

2. 到点自动派发,失败自己重试

23:00 一个 cron 触发派发脚本。脚本做四件事:

  1. 数收件箱里有几张待领卡,没有就安静退出
  2. 检查执行者的调试端口通不通,不通就自动重启它
  3. 探一下额度恢复没有
  4. 有额度就发启动语,没额度就挂一个后台重试环(每 5 分钟探一次,最多 12 次)

这里有个原则:静默是美德。没有待领卡、额度没恢复这种”正常情况”,脚本一个字都不输出,不打扰人。只有真出错才报警。

3. 窗口感知续派:周末白天不浪费

这是后来补的最关键一块。最初只有 23:00 派一次,结果周五晚派完,周六周日白天额度明明恢复了,却没人续派——58 小时的大窗口白白浪费。

补法:一个每 30 分钟跑一次的续派脚本,四个条件全满足才派活:

  • 当前在额度窗口内
  • 收件箱有待领卡
  • 执行者空闲(没有正在跑的卡)
  • 额度还够

带一把锁防止重复派。这样不管是平日夜里做完一批剩的卡,还是周末白天恢复的额度,都能自己接上。

4. 探针读真实余额,不靠界面猜

一开始探针只看执行者界面上”有没有可用模型”。问题在于:额度刚耗尽时,界面可能还挂着模型标识,探针误判”有额度”,继续往一个发不出去的会话灌指令,空转。

改成直接读执行者日志里的真实余额数字。低于阈值(大约一张卡的消耗量)就判用尽,停派,并且只通知一次”剩 N 张卡留下个窗口”,立个标记防刷屏,余额恢复后自动重置。

5. 晨间战报:不用你主动问

早上 8:30 一个 cron 自动汇总昨夜战绩推过来:完成几张、受阻几张、剩几张、额度用到几点、当前余额。我不用起床先问”跑完没”,消息已经在那了。

四、执行者没额度了怎么办

免费额度总会用完。用完不是停摆的理由——换一支有额度的手。

实际这么干过:ZCode 额度凌晨打光,剩 7 张卡没跑。把这 7 张转给 Qoder:改卡号前缀(Z→Q,转派必改,不然编号体系乱)、重置为待领、把已有的进展附在卡上保留。Qoder 有额度就接着跑。

三个执行者各有通道:ZCode 走调试端口注入,Qoder 走它自己的调试端口,WorkBuddy 走一个本地网关。哪个通道挂了、哪个额度没了,诊断清楚就切。核心是卡是资产,执行者只是手——手断了换一只手,卡上的进度不丢。

五、踩过的坑(这部分最值钱)

每条都是真实事故,现象→排查→结论:

坑 1:探针说”没额度”,其实是输入框空的。
现象:额度明明恢复了,探针还报不可用。排查:执行者的发送按钮在输入框为空时也是禁用态,探针把”空输入框的禁用”误读成”额度耗尽的禁用”。结论:探针必须先注入一个字符再判按钮状态,判完恢复原样。假阴性差点让我以为额度没恢复。

坑 2:启动语发出去了,执行者没动。
现象:派发脚本显示发送成功,执行者却没领卡。排查:那是个 React 受控输入框,直接改 DOM 的值不触发状态更新,看着填上了其实没填上。结论:必须用原生 setter 加 input 事件,再校验输入框内容真的等于要发的文本。

坑 3:执行者读不到卡。
现象:执行者说”收件箱是空的”,但卡明明在。排查:它的会话工作区漂移到了别的目录,相对路径全错。结论:启动语里用绝对路径,再加一个工作区自愈脚本,发现漂移就纠正。

坑 4:整个派发任务报一个看不懂的解码错误。
现象:cron 报 utf-8 codec can't decode byte,24 张卡一张没派出去。排查:调度器解码脚本输出时没带容错,脚本输出混进一个非 UTF-8 字节就整个崩。结论:脚本头部统一设 PYTHONIOENCODING=utf-8 双保险。

坑 5:我自己把在跑的脚本弄断了。
现象:给脚本目录做 git 化时,我把一批一次性脚本归档移走,结果误移了两个正被 cron 引用的活跃脚本。排查:逐个核对启用 cron 的脚本路径,发现两个缺失。结论:立刻还原,改用 .gitignore 排除而不是移动文件——活目录里的文件一个都不动。这条记下来提醒自己:整理归整理,别碰正在跑的东西。

六、也有没啃下的骨头

只写光鲜面没意思,说几个真实的摩擦:

  • 桌面自动化天生脆弱。 有的执行者没有可用的命令行接口,只能驱动它的桌面窗口派活:找窗口、定位输入框、注入指令。界面一改版、元素一换位置,脚本就可能失效。这是用免费额度的代价——人家没义务给你稳定的 API。
  • 执行者会”自报完成”但没真做。 有的卡写着完成了,去查源码发现根本没提交。所以验收不能信自报,必须独立机检:编译门禁、证据文件存不存在、截图 md5 查有没有复用、diff 有没有越过文件锁。这套机检现在做成了脚本,但真机层面的验证仍然得人看。
  • 额度规则是别人定的,说变就变。 窗口时间、赠送额度都是平台说了算。流水线只能适应,不能假设它永远稳定。
  • 判断仍然不能外包。 流水线能自动派活、自动验收机检项,但”这个功能该不该做、这个方案对不对、要不要发版”——这些判断还是人的。AI 负责生成,人负责裁决。执行可以外包,判断不能外包。

七、优化方向(如实评估)

已经做到的:窗口感知续派、真实余额探针、通用启动语、脚本版本管理、验收机检、晨间战报。

还没做、值得做的:

  • 验收机检目前查的是证据存在性和查重,编译门禁和真机验证还没完全脚本化,仍占人力。
  • 多执行者之间的负载均衡现在是手动转派,理想状态是按各家额度余量自动分配。
  • 桌面通道的脆弱性没有根本解,只能靠自愈脚本兜底,治标。

写在最后

这套东西不复杂,难的是把一堆”会出错的小环节”拼成”出错也能自己爬起来”的整体。静默是美德、卡是资产、不信自报、判断不外包——这几条原则比任何具体脚本都重要。

现在还不急着把脚本和搭建手册放到 GitHub——它还在迭代,我想先把无人值守这条链路打磨得足够稳、足够通用,再整理成一份别人拿过去就能用的东西开源出来。到那一天会在这里更新。欢迎拍砖。

(文中项目信息已脱敏。涉及的 Hermes、ZCode、Qoder、WorkBuddy 均为真实使用过的工具。运行数据来自真实夜间日志,未包含任何私密配置与凭据。)



技术分享  

AI 效率工具 工作流

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!