派单 10 分钟就被回收:我们给 Hive 加了第四种 Agent 模式 accept,让定时任务也能接住卡
派单 10 分钟就被回收:我们给 Hive 加了第四种 Agent 模式 accept,让定时任务也能接住卡
发布摘要(粘到 CSDN「摘要」框):多机 AI Agent 协同里,「发布任务」只是第一步。本文复盘 Hive 一次真实翻车:主控把 23 张并行任务卡发布到 Git 协调仓、派给三台 Windows 机器,结果 9 张派单在 10 分钟内被 watchdog 全部回收——而接单的定时任务每小时才醒一轮。根因不是
manual模式,是「派单」与「接单」之间缺独立语义与等待窗口。新增的accept模式、180 分钟接单窗口、hive accept命令与 MCPhive_accept工具,以及 store 后端下派卡必须「双写」的坑,全部来自实跑现场。附 185 项回归测试与有序重启清单。零第三方依赖,开源。
写在前面:这不是一篇「五分钟搭建多智能体框架」的爽文,也不复述功能清单。Hive 是我们每天真在用的任务总线,这次把「发布任务」这条链路从头到尾压了一遍,值得把为什么这么设计和哪些坑是真踩过的写下来。文中的时间、提交号、命令、状态都来自实跑快照,不是示意图。
一句话矛盾:主控按小时级节奏派单,接单方也按小时级节奏醒来,可系统默认只给这张单留 10 分钟。
一、先把「发布任务」这件事说清楚
Hive 里没有任务队列服务,也没有中央数据库。一张任务卡就是协调仓库里的一个 Markdown 文件:
发布任务 = 写卡 + git push。领取靠 git push 的原子性:两个 worker 抢同一张卡,只有一个 claim/<tid> 分支能推上去。总控只做三件事:写卡、分派、验收合流。
这次一口气发了两批、共 23 张并行卡:
| 批次 | 卡号 | 覆盖 | 并行度 |
| 六仓整改(现成任务书落卡) |
| registry 默认源断链、CI 徽章对齐、版本号一致性、清临时物、治理补齐、六仓交叉验收 | 第 1 批 6 路 |
| light 语言本体缺陷(新制卡) |
| 归约段落实参发射、单行段落静默空跑、linter 假内置名、原生腿 argv、地板门禁漂移、回归探针、缺陷账终态 | 5 路 + 1 收尾 |
并行不是「多开几个 agent」就行,拆卡时有三条硬规则:
- 文件锁优先于目录锁。每张卡写
locks(精确到文件),不只写paths(目录前缀)。按(repo, path)分组校验,23 张卡零冲突——否则land时必然撞在一起。
- 依赖分批。
T-0269 ← T-0263、T-0272 ← T-0265、T-0282 ← T-0277..T-0281,收尾卡T-0275依赖整批,先不派。
- 判据是真跑过的命令。每张卡的
verify都带pytest之类的强验收;hive draft lint会拦住「全是grep/test -f」的弱判据——agent 靠改个字符串就能糊弄过去的卡,不该转正。
发布完成那一刻:hive status 从 0 张待领卡(136 done + 2 shelved)变成 23 张 ready,三个远端 origin / github / gitcode 对齐到同一个提交。
看起来一切就绪。然后它翻车了。
二、第一次翻车:派出去的卡,10 分钟就没了
2.1 时间线
更麻烦的是,回收只改了 Git 卡面,store 里这 9 张仍是 assigned/owner=X——两个真相源分叉了。
2.2 一个 agent 自己把根因查出来了
我把其中一台(workbuddyai-win)的疑问丢回去,让它自己查。它翻了配置提交历史和 hive.py 的 mode 处理逻辑,给出的结论里有一句很关键:
「那三次 miss 跟 manual 模式无关,改 mode 也修不了。真正决定『有没有人接』的是这台机器上有没有常驻 worker,或者我有没有手动
take。」
它是对的。当时 15 个 agent 清一色 mode: manual、没有一台标 dispatchable,可 dispatch-mark 根本不校验 mode,手动 assign 也不受限制。把 manual 改成 exec 只会让 doctor 报「exec 没有 command」,卡照样被回收。
2.3 真根因:三条时间线一起卡住
看门狗里有三个彼此独立的窗口,全都是为「常驻 worker」设计的:
| 通道 | 默认值 | 作用 |
|
| 10 分钟 | 派出去没人 claim → 记一次 |
|
| 30 / 45 分钟 | 「领过但死了」的孤儿回收 |
|
| 60 分钟 | 刚推过的卡不重复派 |
外加一条熔断:dispatch_miss 累计到 2 就转 blocked,彻底退出流水线。
于是「派单 → 10 分钟回收 → TTL 压着不重派 → 再派再回收 → 转人工」,而接单方每小时才醒一轮。卡永远在 agent 醒来之前被收走。
结论很反直觉:缺的不是第四种 mode,是「派单」和「接单」之间的一段合法等待期。系统把 assigned 当成「已经有人接了」,实际上它只是「主控把单放在了收件箱里」。
三、accept:把「派单」和「接单」拆成两件事
3.1 四种模式,各管一种机器
| 模式 | 那台机器需要 | 谁接单 | 需要 |
|
| AI 的 headless CLI | 常驻 worker 立刻调 CLI | 必须 |
|
| 只要能跑命令 | 不接改代码的卡,只跑验收 | 否 |
|
| 只有 GUI IDE | 人在 IDE 里点一下 | 否 |
|
| 一个能定时唤起 AI 的计划任务 | AI 定时任务自己来接 | 否 |
accept 的语义很窄,也很明确:
四条设计取舍:
- 天然参与
dispatch --apply。不需要dispatchable: true、不需要command/launch/ 常驻 worker。机器上只有定时任务,也配得上「能被派单」。
- 接单窗口按派单对象逐卡取。
accept_window_minutes(默认 180 分钟,可用HIVE_ACCEPT_WINDOW_MINUTES覆盖),必须 ≥ 定时任务唤醒周期;其它模式仍是 10 分钟。
- 超时不等于派发失败。窗口用尽只把卡退回
ready、保留dispatched_to与 inbox 便条,不累加dispatch_miss、不转blocked,卡体写一条「接单窗口超时」。下一轮定时任务照样能接。
- 接单校验派单对象。
hive accept只认dispatched_to(或owner)是自己的单,不抢无主单、不碰别人的单,并在卡面写accepted_at留痕。
3.2 命令长什么样
MCP 侧同步加了 hive_accept 工具;hive_next 对 accept agent 只推荐派给它的单,不再从公共池里挑。工具数从 15 → 16(controller 视角 22 → 23)。
3.3 为什么没有新增一个任务状态
这是最想强调的取舍:我们没有引入 offered / awaiting_accept 之类的新 state。
Hive 的状态机里 STATES、IN_FLIGHT_STATES、HANDOFF_STATES 三处耦合,加一个状态会牵动 dispatch、worker、看板、MCP 的筛选逻辑。所以复用 assigned 表示「已派单、待接单」,靠三样东西把语义补回来:
- agent 的
mode: accept决定 watchdog 用哪个窗口;
- 卡面
accepted_at标记「真的接过单了」;
hive accept的派单对象校验,挡住「谁都能领」的旧行为。
顺带说明为什么必须挡:旧 prompt 用
hive take接单,而take不校验 owner。现场真出现过take T-0261 -> trae-win——把派给doubao-win的卡领走,还把dispatched_to覆盖成自己。加了accept之后,同一张卡用错身份接会直接报错:T-0261 派给了 doubao-win,不是 trae-win;不能接别人的单,且卡面零改动。
四、三个后门是一起堵的(最容易被漏的一处)
第一版实现只把「10 分钟」换成「180 分钟」,新增测试当场就红了——卡还是被回收了。
原因在 cmd_watchdog 里还有一条 elif:
accept 单放宽了快速通道,却仍会被 45 分钟的 orphan_assigned 兜底从后门收走。再往外一层,还有 60 分钟的推送 TTL 压着不重派。
所以最终要同时处理三条:
- 快速回收窗口按 agent 配置放宽;
orphan_assigned兜底对 accept 单显式跳过;
- 超时后保留派单关系,不让 TTL 把单「压死」在无人区。
tests/test_accept_mode.py 用 7 条判据把这三条钉住:mode 合法性与 doctor、dispatch 天然可派、60 分钟不回收、200 分钟超时不记 miss 不转 blocked、抢单被拒、接单写 accepted_at、窗口可按 agent 覆盖。
这条经验比功能本身更值钱:改一个「等待窗口」时,先列出系统里所有会判定「等太久」的地方。只改最显眼的那一个,后门会替你把它改回去。
五、双写坑:store 后端下,assign 根本不写 Git 卡面
这是发布链路里最容易踩、也最隐蔽的一处。
本机 ~/.hive/cluster/config.json 是 claim_backend=store。看 Hive.cmd_assign:
而 Windows 定时领取读的是 Git 卡面 + inbox/。只跑一次 assign,卡在 store 里是 assigned,Git 卡面还是 ready、收件箱是空的——agent 完全看不到派单。
所以给「读 Git 卡面」的领取者派单,两条都要跑:
验证要查三处:tasks/T-xxxx.md 的 state/owner、inbox/X/T-xxxx.md、store 表里的 state/owner。少一处,迟早分叉。
5.1 还有一层:常驻进程加载的是旧代码
13:13 提交 accept 代码后,13:29 又出现了一轮 dispatch-miss——8 张卡再次被回收。查进程才发现:
代码提交了、测试过了、文档写了,跑着的进程还停在昨天。 这条已经写进文档(docs/主控与分发.md §4.6「部署生效边界」)。
有序重启清单(顺序错了会踩第二个坑):
如果省略「停主控 → 确认无残留」,cluster restart 和 orchestrate 的 cluster_ensure() 会各拉一个节点进程抢 8788、同时打开同一个 SQLite,日志里留下 store: 打开失败(忽略): database is locked——health 仍是 200,但 store 已经静默失效,所有 /api/cluster/store/* 返回 503。这个故障形态非常难查:表面全绿,写操作全废。
六、数字与验证
| 项 | 实测 |
| 发布任务卡 | 23 张(六仓整改 17 + light 缺陷 6), |
| 按 | 0 对 |
|
| 18 文件 / |
| 文档全量口径对齐 | 14 文件 / |
| 回归测试 | accept 7 + dispatch_miss/watchdog/orchestrate 26 + MCP 33 + docs/tracking 74 + core 分批 45 = 185 项全绿;文档复测 46 项 |
| 派单三处一致 | 9 张卡 Git 卡面 / inbox / store 全部一致 |
|
| 回收候选 0(只剩 1 条 |
| 三远端 |
|
几个诚实的数字:
- T-0260 已经由 doubao-win 做完并自动 land:真的给两台 agent 登记了
lighthive/lightplugin、给fb88-dsh开了dispatchable。
- T-0262 已交
failed结果,没有合并。agent 在结果里明确写「未修好默认源可达性,只修了错误可读性,勿标『修好了』」——验收闸门判红就是判红,不因为「有结果」就合。
- 集群仍有一个遗留:
state.json的leader_id反复被 104 节点的心跳带回一个节点表里不存在的幽灵身份,两节点都停在 follower、无 leader。此时 orchestrate 会空转(no-leader,跳过写动作)——不会误回收卡,但自动派卡/自动合入也停了。根治要在那台 Windows 机器上清state.json并重启 hived,本机没有远程执行通道。把它写出来,比假装一切正常有用。
七、有哪些「故意不做」
- 不加新任务状态。复用
assigned,用 mode +accepted_at+ 派单对象校验补语义,避免牵动整套状态机。
- 不给 accept agent 配常驻接单服务。它的全部前提就是一个能定时唤起 AI 的计划任务;再加守护进程就退回 exec 了。
- 不自动改 agent 机器上的定时任务 prompt。新版 prompt 随仓库推送、也给三个 agent 发了跨机留言,但换命令这一步留给真机上的人——Agent 不该偷偷改自己的调度器。
- 不因为「有结果」就合并。
failed结果不 land;合并仍留给人 review 或总控land。
- 不隐藏运行态不一致。Git 卡面与 store 分叉、常驻进程代码旧、集群无主,都写进文档和排障表,而不是在推介里抹掉。
适合谁:已经有 Git、机器异构、agent 能力参差、接单方是「定时被唤醒的 AI」而不是常驻服务的团队。 不适合谁:单机单 agent、要毫秒级调度、或已有成熟 CI/CD 编排体系的场景。
结语
这一轮最值钱的结论不是「加了个 mode」,而是:
多 Agent 协同里,最容易被忽略的不是「怎么派」,而是「派出去以后,接单方到底有没有机会来接」。
exec 假设接单方一直在线,manual 假设人一直在线,只有 accept 承认「接单方是按自己的节奏醒来的」。一旦把派单与接单拆开,等待窗口、回收策略、TTL、状态留痕、派单对象校验就得一起重新设计——只改最显眼的那一个,后门会替你把它改回去。
开源部分永久免费,直接用就行。真卡住了、或者要接进自己的多机产线,可以写信聊:hello@quye.com。
- 使用指南:仓内
docs/使用指南.md
- 派单—接单机制:
docs/主控与分发.md§4.6;定时接单 prompt:docs/子agent定时领取-prompt.md
- 架构串讲:
docs/架构与排障全景.md
如果只记一句:别急着调 mode,先量一下「派单」到「接单」之间的时间差,再看看系统给这段等待留了多久。
更多推荐
所有评论(0)