不用 SSH、不装数据库:我用 1 个 Python 脚本 + Git,把 15 个 AI Agent 串成了一条流水线


title: CSDN-hive-多机Agent协同任务总线

不用 SSH、不装数据库:我用 1 个 Python 脚本 + Git,把 15 个 AI Agent 串成了一条流水线

发布摘要(粘到 CSDN「摘要」框) :多台机器上的 AI Agent 并行改代码,最难的从来不是让它们干活,而是别抢同一张卡、别互相覆盖、干完还查得到。本文复盘蜂巢 Hive 的真实设计------用 git push 的非快进失败当分布式锁、lease_id + fence 拦住旧 worker 复活、任务卡即 Git 文件、六列看板与「搁置」状态,以及 133 张卡跑下来踩过的坑。零第三方依赖,开源。
写在前面:这不是一篇「五分钟搭建多智能体框架」的爽文,也不是概念科普。蜂巢 Hive 是我们每天真在用的工具,跑了 133 张任务卡之后,我觉得值得把为什么这么设计 和哪些坑是真踩过的写下来。所有命令、状态、数字都来自实跑快照,不是示意图。

一句话矛盾:跨 Windows / FreeBSD / macOS 的 15 个 AI Agent,能力不一样、有的连 CLI 都没有,怎么让它们并行改代码而不互相覆盖、不重复领活、干完还查得到?


一、起点:聊天窗口管不住多台机器

最开始的协同方式特别朴素:我在对话框里写好一段需求,贴给 A 机器的 agent;跑完了它把结论贴回来,我再贴给 B 机器。很快就有四个问题同时冒出来:

  1. 谁在干什么,全靠我记。 隔一小时回来,分不清哪张卡在跑、哪张卡其实早死了。
  2. 两个 agent 改同一片文件。 各自都能提交,合流时才炸,而且炸完还得人工分辨谁的结果该留。
  3. 旧进程会「复活」。 一个卡在慢命令里的 worker,租约被回收、卡被别人重新领走之后才醒过来,最后把新人的结果 force push 覆盖了。
  4. 结果散在各台机器的对话里。 想复盘「这张卡为什么停在这儿」,只剩一句「看板操作」。

常见解法我都不太想用:SSH 进 Windows 机器(国产 GUI agent 很多压根没有 CLI)、共享目录(网络一抖就全乱)、中央数据库或消息队列(为了跑几个 agent 先运维一套中间件)。

后来想明白一件事:每台机器上唯一肯定有、且天然支持原子操作的东西,是 Git。 于是整套设计收敛成一句话------

一个 Python 脚本 + 一个 Git 裸仓当协调仓,用 git push 的非快进失败当分布式锁。

不需要 SSH、不需要共享目录、不需要中央数据库。


二、Hive 是什么(以及不是什么)

复制代码
hive.py            一个 Python 脚本,标准库,零第三方依赖
协调仓(git bare)  只存任务卡、结果、租约、审计
dashboard/         零依赖静态看板(HTML + 原生 JS + 标准库 serve.py)
mcp_server.py      MCP stdio server,让 agent 自己来领活
hive_cluster.py    可选:常驻集群,秒级同步 + SQLite store

三个角色,职责切得很硬:

角色 只做三件事 不做什么
总控(人或主控 agent) 写任务卡、分派、验收合流 不替 worker 写代码
worker(每台机器一个) 拉取、原子领取、独立 worktree 干活、推回结果 不自己合并 main
看板 只读全局 + 少量带鉴权的运维写操作 不调度、不做业务判断

顺带澄清一个常被误会的点:Hive 和「光明(LightLang)」中文编程语言没有关系。 光明是独立项目,早期只是拿它的代码仓当过登记示例。Hive 是自包含的工具,没并入任何其它项目。


三、核心机制:把 git push 当分布式锁

一张卡的一生大致是这样:

复制代码
总控写卡 tasks/T-0101.md (state: ready)
        │
        ▼  dispatch 按能力/负载/依赖挑卡
   state: assigned ──► inbox/<agent>/T-0101.md
        │
        ▼  worker 原子抢锁:push refs/heads/claim/T-0101(非快进即失败)
   claim/T-0101 分支   ← 只有一个 worker 能 push 成功
        │
        ▼  独立 worktree 干活,push task/T-0101 代码分支
   res/T-0101 分支     ← 结果 JSON(verify 全绿才 status=done)
        │
        ▼  人工 review 或总控 hive land 串行合流
   state: done + results/T-0101.json 归档,claim/res 分支删除

三套 ref 各管一件事,这是整套设计里我最满意的部分:

ref 内容 生命周期
claim/<tid> 租约:谁领的、lease_id、fence 只在进行中存在,close 时删
res/<tid> 结果:verify 输出、耗时、head、summary 合流后归档成 results/<tid>.json
task/<tid> 代码分支 交给 PR / land

抢锁的原子性完全来自 Git 服务端:两个 worker 同时 push claim/T-0101,非快进的那个一定被拒,不需要额外的锁服务。配合每人一个 worktree,agent 物理上就看不到对方没提交的改动。

但只有锁是不够的:fencing

上面第 3 个坑(旧 worker 复活)是纯 Git 模型答不了的:res/* 用的是 --force-with-lease,本意是「同一张卡重跑能覆盖上一次」,结果恰好也允许旧 worker 覆盖新 worker。

补法是每次领取写两样东西:

  • lease_id:这次领取的唯一编号,写结果前必须对账;
  • fence:单调递增序号,每次回收 / 重派 +1。

旧 worker 醒来写结果时,lease_id 对不上直接拒;就算它绕过校验硬推,res.fence < card.fence 也会让 land 在合流前把这份过期结果认出来。锁决定「谁能干」,fencing 决定「过期的结果不算数」,两层缺一不可。

再加两层才闭环:

层 防的是什么
paths 互斥 两张不同的卡改同一片文件 → dispatch 就不派下去(粒度是路径,不是整个仓)
land 串行 一次只合一张,冲突显式暴露,不静默覆盖

四、任务卡长什么样

一张卡就是一个带 frontmatter 的 Markdown 文件,Git 就是数据库,所以天然有历史、有 diff、能离线看:

yaml 复制代码
---
id: T-0101
title: 修复 CSV 导出在中文 Windows 下的编码
repo: demo
base: main
state: ready
owner: null
priority: P1
needs: [windows]          # 能力标签:没有对应 agent 的卡不该派出去
paths:                    # 声明会动哪些文件,防冲突的第一道闸
  - src/export/csv.py
  - tests/test_csv.py
verify:                   # 真跑的命令,不是人肉勾选
  - python -m pytest -q tests/test_csv.py
depends_on: []
max_retries: 3
---
复现步骤:...... 判据:导出的 CSV 用 Excel 打开不乱码。

几个字段是踩坑踩出来的:

  • verify 必须真跑过 。曾经有一条验收命令自己写错了(sys.exit 却没 import sys),代码全对,submit 判 failed。
  • paths 要写全。有次顺手改了 README 却没列进 paths,被自己的越界检测抓回来重写。
  • needs 要确认有 agent 能满足 。写过一张 needs: windows 的卡,结果四个 agent 一个都没声明这个能力,它就在 ready 里躺成了僵尸卡------现在 draft lint 会拦。
  • 有结果才算完成 。早期 close 无条件写 done,于是「中途掐掉」和「真做完」在看板上长得一模一样。现在没 res 就记 closed(作废),并把原状态、owner、失败原因一起写进卡面备注。

五、五分钟跑起来

以下命令都在工作目录 执行(比如 ~/dswork),hive 仓位于 ./hive;Windows 把路径分隔符换成反斜杠、解释器写 python,参数完全一样。

sh 复制代码
# 1) 拿代码。推荐直接把工具仓推成自己的协调仓,hive.py / docs / windows 都跟着走
git clone https://gitcode.com/skywalk163/hive.git hive
git -C hive remote add origin <你的协调仓地址>
git -C hive push -u origin main

# 2) 初始化:补齐 tasks/ inbox/ results/ claims/ agents/ 等目录
python3 hive/hive.py --dir hive init

# 3) 登记一台机器(agent 名全局唯一)
python3 hive/hive.py --dir hive agent add --name win-a --mode manual \
  --capabilities windows --repo demo=<本机代码仓路径>

# 4) 建一张卡
python3 hive/hive.py --dir hive task new \
  --title "修复 CSV 导出编码" --repo demo \
  --paths src/export/csv.py \
  --verify "python -m pytest -q tests/test_csv.py"

# 5) 先看分派计划,再落库
python3 hive/hive.py --dir hive dispatch            # 只看计划
python3 hive/hive.py --dir hive dispatch --apply   # 真分派

# 6) 各台机器上起 worker(--once 先跑一轮,常驻用 --interval 30)
python3 hive/hive.py --dir hive work --agent win-a --once

# 7) 全局视图
python3 hive/hive.py --dir hive status
python3 hive/hive.py --dir hive doctor          # 体检:冲突/僵尸租约/land 滞后
python3 hive/hive.py --dir hive stats --json    # 成功率、耗时

也可以从完全空的裸仓开始(init --remote <地址> 会建目录并推第一版),但那样就没有现成的 windows/ 和 docs/,得自己拷。

看板另起一个零依赖静态服务(浏览器打开 http://127.0.0.1:8787):

sh 复制代码
# 同样在工作目录里,脚本会自己定位 hive 仓
PORT=8787 INTERVAL=20 ./hive/scripts/serve-dashboard.sh

worker 一定用 setsid、tmux 或计划任务常驻,我吃过亏:随父 shell 回收,日志静默停在半路,六小时后才发现。


六、看板:一眼看到全局,且不会骗你

六列按单向互斥判定,一张卡只出现在一列:待领取 / 进行中 / 待合并 / 异常 / 最近完成 / 已关闭。租约过期在渲染时重新计算,哪怕快照没刷新,时间一到卡片自己变红落进异常列。

有个细节我特别想安利:响应头带快照时刻 ,页面右下角显示「数据源:/api/status(快照 N 分钟前)」,超过 10 分钟加警示。起因是刷新循环曾经停摆,/api/status 依然返回 200,页面安安静静渲染了一份 2 小时 43 分钟前的数据,害我误判「退回没生效」。接口是活的,不等于数据是新的------这种坑不显式摆出来就只能靠人肉发现。

其它:仓库 / owner / 优先级筛选、文本搜索、详情抽屉(完整结果摘要 + 每条 verify 的命令与退出码)、深浅双主题、窄屏单列。看板写操作(退回、重试、关闭、搁置)默认只在回环绑定下免鉴权,绑到内网必须配 token,每次写操作落一条 append-only 审计日志。

最新加的「搁置」:给做不了的卡一个体面的去处

有些卡当前确实做不了(比如需要 macOS arm64 机器,手边只有 x86_64)。打回待领取会占位置、干扰 agent 领取;一直挂在异常列又太显眼;直接删更不行,删了就真忘了。

于是加了 shelved:不算挂账,但不能忘。

  • 搁置时释放 claim/ res/ status/ 分支、归档结果、收件箱信号和本机/集群租约,推进 fence;但卡面连同「为什么停、什么时候停、之前什么状态」全部留着,连完整结果摘要都抄进卡面折叠块------因为释放 res/ 分支会删掉那份结论,而「不要忘记」不能只留 200 字。
  • 排版上没加第七列 :六列已经够挤,搁置卡也不该和活跃卡平级。做成顶栏常驻的「搁置 N」+ 一条默认收起的横条,点开才显示卡片与三个出口:放回待领取 / 另立新卡 / 废弃。
  • 它不进任何列、不计入活跃统计、doctor 不报、不归档;调度、worker、MCP 领取、land --all 全跳过。复制按钮拿到的也不是「请领取任务」,而是一段写明不要领取的搁置说明。

七、让 agent 自己来领活:MCP + 跨机留言

hive mcp 是一个标准库实现的 stdio JSON-RPC server,把任务总线暴露成 15 个工具,agent 可以自助闭环:

复制代码
hive_whoami → hive_next → hive_claim → 干活 → hive_submit
                                   └→ 干不下去 hive_abort / hive_block

一个 server 进程 = 一个 agent,只能操作自己 :不能替别人领卡、提交、终止租约,越权直接返回错误,失败时还会给 hint 告诉你下一步。

但这里有个很现实的约束:我们登记的 15 个 agent 全是 manual 模式------国产 GUI agent(小浣熊、Trae、CodeArts、WorkBuddy 之类)很多没有 CLI,没法自己起进程调 MCP。所以看板每张卡上有个「复制派发指令」按钮,复制出来粘到 agent 对话框里。这是最土的办法,也是跨机器、跨客户端最可靠的办法,我们保留着,没硬拗全自动。

跨机沟通同样不走聊天软件:看板右下角「留言」,频道分大厅 / task:T-0231 / agent:名字 ,消息 1~2 秒同步到全网,卡片和详情抽屉里都有「讨论 n」入口,甩一条 #chat=task:T-0231 的深链过去,人点开就是那个线程。集群没起时降级到本机文件,照样能发能看,只是会明确提示「别的机器暂时看不到」。


八、踩过的坑,比特性更值得写

现象 根因 后来的做法
旧 worker 复活覆盖新结果 res/* 的 force push 认不出过期租约 lease_id + 单调 fence,写前对账、land 再验一次
代码全对但判 failed verify 命令自己没 import sys 卡面入库前手动把每条 verify 真跑一遍
卡在 ready 里永不派发 needs 写了没有 agent 声明的能力 draft lint 拦截 + 写卡前 hive agent list
worker 日志静默停在半路 没用 setsid,随父 shell 回收 常驻启动脚本统一收口
「完成」和「被掐掉」长得一样 close 无条件写 done 有 res 才 done,没有记 closed 并写现场
看板显示几小时前的旧数据 刷新循环停了但接口仍 200 快照时刻响应头 + 超 10 分钟警示
重试卡反复被字段吞掉 重写卡面时未登记字段被丢 write_card 保留自定义字段

这些都不是理论上的「最佳实践」,是半夜排障排出来的。它们现在都变成了代码里的守卫或卡面里的一个字段。


九、跑到现在的数据

一份真实的当前快照(不是压测,不是 benchmark):

项 值
任务卡 133 张(131 done / 2 shelved)
有结果归档 129 张(128 done / 1 failed)
登记的 agent 15 个,跨 Windows / FreeBSD / macOS
涉及仓库 4 个
几个核心文件合计 约 1.7 万行(hive.py 7.1k、hive_cluster.py 3.9k、看板前端 2.6k 等,不含文档与测试)

两套模式可以叠加:纯 Git 模式零依赖、单机也能跑;常驻集群 模式(hived + SQLite store)面向更大规模,目标 70 个并发 Agent × 7 张卡/天、可扩展到 100 节点,选主和复制按 OSPF 的思路做(Hello/Dead、term/vote、分区内多数),Git 退回只写「建卡 / 结果归档 / 合并关闭」三个里程碑。一致性是分层的:claim / lease / result 走可复制的 op log,progress 走可丢最后几秒的临时通道。

明确不保证:单节点分区最后几秒的进度、分区期间可能重复干活、Gitea 挂掉时 land 延后。写清楚比藏着强。


十、有哪些「故意不做」

  • 不自动合并 main。 合并留给人 review PR,或总控用 land 一次一张串行做,冲突显式暴露。
  • 一个 worker 串行跑。 要并行就同机起多个 worker + 多个 agent 名,不做复杂的本地调度。
  • 不做自动扩缩容、不接 K8s。 拓扑是运行态不是配置项,1 台能起、100 台能加,但成员靠发现不靠编排平台。
  • 看板不做拖拽改状态、不搞后端数据库。 页面只读为主,写操作走 CLI 并留审计。
  • 没有中央调度服务。 没有那个单点,也就没有那个单点要运维。

适合谁:已经有 Git、机器异构、agent 能力参差、需要「谁在干什么 / 为什么停」可追溯的团队。

不适合谁:单机单 agent、要毫秒级调度、或已经有成熟 CI/CD 编排体系的场景------那套比这个合适。


结语

回头看,这套东西最值钱的不是代码量,而是把「协同」这件事压回到了 Git 已有的语义里 :状态是文件、锁是 ref、结果是分支、审计是 commit。于是它天然能离线、能回溯、能用 git log 查半年前某张卡为什么被搁置,也天然不需要我们再运维一个「协同系统」。

开源部分永久免费,直接用就行。真卡住了、或者要接进自己的多机产线,可以写信聊:hello@quye.com。

如果只记一句:别急着给多智能体协同上中间件,先看看你手里的 Git 能不能当锁用。


标签 :AI Agent 多机协同 Git Python MCP 分布式锁 工程实践 开源

相关推荐
Decay__33 分钟前
19_MySQL 告警与自动化运维 —— 告警分级收敛 / Webhook / 定时巡检 / 脚本库
运维·数据库·sql·mysql·架构
AI全栈学习助手34 分钟前
告别“转圈等待”:Spring Boot + SSE 让大模型像 ChatGPT 一样流式输出
java·人工智能·spring boot·后端·aigc
天天被压力35 分钟前
【A股分钟级高频数据完全手册 #02】Python调用股票1分钟数据接口:Pro版最新分时取数与字段解析
java·人工智能·python
代码不停35 分钟前
Spring Aop
java·数据库·spring
楚山之石37 分钟前
【MRM】CAPLEX 对比剂灌注 MRI 开源术语库:ISMRM OSIPI 共识报告
图像处理·人工智能·学习·mri
FungLeo39 分钟前
成为全栈·基础补充·Linux 服务器入门
linux·运维·服务器·ssh·部署·成为全栈
keyipatience42 分钟前
MySQL 学习(4)常用数据类型
数据库·mysql
达梦产品与服务44 分钟前
SQLark V4.2 更新 | 新增TiDB、SSL安全连接、数据字典、清空/截断表等40+项功能已上线!
数据库·安全·tidb·ssl
Godspeed Zhao1 小时前
从零开始学AI22——集成学习
人工智能·机器学习·集成学习