Skip to content

About

基于 Pinia 全局状态思想的「多智能体异步协作」底层架构。/A zero-dependency framework for autonomous dual-agent collaboration. /

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

31 Commits

Folders and files

Repository files navigation

🌉 Agent-Bridge

基于 Pinia 全局状态思想的「多智能体异步协作」底层架构

License: MIT Dependencies: 0

简体中文 | English


👨‍💻 写在前面的话:为什么会有这个项目?

作为一名深耕业务的前端开发者,在近期深度探索 AI 辅助编程(AI Coding)的过程中,我萌生并独立主导了这个开源项目。

【起因与痛点】 在使用大模型开发项目时,我发现像 Codex / Claude-3.5-Sonnet 这样的顶级模型价格昂贵。如果手里同时推进多个项目,完全用昂贵模型写基础业务代码非常不划算。 于是我产生了一个构想:能不能让“昂贵且聪明”的模型充当架构师与监工,去驱动和审查“便宜且量大”的模型(作为基层码农)干活? 并且,我希望这一切是全程 100% 自动化、零人工干预的。

【灵感与破局:借鉴 Vue 的 Pinia 思想】 在实验初期,我试图让两款不同的 AI 编程软件(比如 Codex 和另一款终端大模型)建立直接的 WebSocket 或 RPC 连接。但由于不同工具的环境黑盒,多次实验均以失败告终。 在苦思冥想时,我想起了前端老本行——Vue 生态中的 Pinia 全局状态管理。 既然不同组件(AI 软件)无法直接通信,为什么不把整个项目根目录作为唯一的全局 Store 呢? 只要我们在本地规定好一套严密的“读写锁”与“状态机制”,不同的编程软件共用同一套项目目录:

  1. Watchdog(看门狗) 作为 Store 的响应式监听器,实时监控状态变更。
  2. Supervisor(监工方/贵模型) 充当架构侧的 Action,负责心跳响应与结果校验。
  3. Builder(施工方/便宜模型) 充当视图/业务更新层,自动进行底层逻辑的编写。

昂贵的模型只需负责补充好 docs/prd.md 需求文档与编写严苛的测试用例,便宜的模型就能依靠这套“状态管理”机制,彼此接替,直到把整个项目开发完毕。


🚀 核心架构与原理解析

本项目实现了一套**零依赖(Zero-Dependency)**的三权分立状态机。

  • Builder (施工方):纯粹的代码生产者。执行完任务后,主动调用本地阻塞脚本挂起,交出控制流。
  • Supervisor (监工方):冷酷的代码审查者。不写业务代码,只跑测试和审查差异。若不合规,则将状态打回 REJECTED 强制重写。
  • Watchdog (看门狗):无情的流水线传送带。纯原生 Node.js 进程,只盯防根目录的 bridge.md 状态机锁文件,负责调度和唤醒。

💡 开发中的思想迭代与踩坑实录

实现真正的“无人值守”,远比画架构图要艰难。在这个项目中,我遇到并解决了三个极度棘手的跨环境工程 Bug,这也是本项目最核心的技术壁垒:

1. 进程状态嗅探的“系统权限壁垒”

  • 痛点:最初监工方尝试使用 WMI (Get-CimInstance) 嗅探系统级进程状态,但在 Windows 下即使是管理员权限也频频遭遇“拒绝访问”。
  • 解决:坚决摒弃全局扫描。改为依赖轻量级的文件级互斥机制——通过 fs.openSync(path, 'wx') 的排他创建标志实现锁(该系统调用由操作系统保证原子性,不存在「先检查再创建」的竞态窗口),配合 PID 存活探测实现陈旧锁自动回收。将跨进程通信降维到文件系统层面,完美绕过了 UAC 权限限制。
  • 工程验证:实测 8 进程 × 25 次并发自增,无锁时丢 58%(83/200),加锁后零丢失(200/200)。详见 tests/lock-primitives.test.cjs。

2. 长驻服务的“终端阻塞死锁” (Foreground Hang)

  • 痛点:施工方在拉起前端 Vite 开发服务器时,由于是阻塞式前台进程,导致大模型的终端执行(Tool Call)一直挂起,无法拿回控制权推进状态。
  • 解决:强制将所有长运行服务剥离。利用 Start-Process ... -WindowStyle Hidden 及 Node 的 detached 模式将服务丢入后台守护,确保命令秒级返回,将控制流交还给大模型。

3. 工具超时的竞态条件 (The 120s Race Condition)

  • 痛点:这是最难排查的一个 Bug。施工方执行挂起脚本等待任务,但在第 120 秒时,大模型客户端因为“单次工具执行超时限制”自动退出了挂起状态。而监工方的深度审查往往需要 150 秒。双方在时间轴上产生致命脱节。
  • 解决:引入了**“自我续期挂起” (Self-Renewal Wait Pattern)** 韧性机制。我在传给大模型的 Prompt 协议中下达死命令:如果脚本因超时返回,绝对禁止停止思考,必须立即发起新的挂起脚本调用,用无限接力的方式填平时间差,确保链路永不断裂。

4. 陈旧锁接管的「假互斥」 (The Fake Mutex)

  • 痛点:崩溃后残留的锁需要被自动接管,否则一次崩溃就永久锁死。但最初的实现是「读锁 → 判 PID 已死 → 覆盖写锁」三步——这不是原子的。实测 6 个进程并发接管同一个陈旧锁,5 个进程全部返回“接管成功”,锁文件最后只剩 1 个 PID,可另外 5 个都以为自己持着锁。也就是说,在最需要互斥的时刻(看门狗崩溃重启后),互斥恰好失效,两个 Watchdog 会同时驱动状态机。
  • 解决:改为三段式接管,每段都有一次内核级原子判定:① 抢占凭证(${lockPath}.reclaim.${token},名字含唯一 token,openSync('wx') 保证只有一个候选者);② 用 rename 把陈旧锁原子搬到隔离区,并校验搬走的字节与判定时完全一致(防 ABA);③ 锁路径此刻为空,再对它做一次 openSync('wx') —— 这次原子判定才是归属的唯一权威。任何一段失败都明确判负退出,绝不进入临界区。
  • 工程验证:实测 6 进程 × 5 轮并发接管,每轮有且仅有一个赢家,临界区重叠观测 0 次。见 tests/concurrency-fixes.test.cjs 的 D1-1 / D1-6b。

5. 退避重试把长驻服务「钉死」 (The Event Loop Freeze)

  • 痛点:锁竞争时需要退避重试。最初用 execSync("ping -n N 127.0.0.1") 实现 sleep——这是同步阻塞调用,会连事件循环一起钉死。实测请求 200ms 退避,实际阻塞 1365ms(近 7 倍);阻塞 2368ms 期间,setInterval(50ms) 触发了 0 次(理论约 47 次),fs.watch 回调同样无法触发。也就是说:一旦锁被竞争,看门狗在最需要工作的时候彻底失聪。还发现一个更隐蔽的问题:ping -n N 的语义是「发 N 个包、间隔 1 秒」,总耗时约 N-1 秒,导致所有 ≤1s 的退避塌缩成同一个 ~1.3s,指数退避策略在 Windows 上退化成常数退避。
  • 解决:改为非阻塞的 await new Promise(r => setTimeout(r, ms))。这要求把 withLock 及其调用链(writeBridge、tick、assembleReviewRequest、consumeVerdict)系统性改为 async,共 10 处调用点补上 await,并保证「状态落盘」先于 shutdown()——否则进程可能在状态写入前就退出,状态机停在旧状态。
  • 工程验证:实测退避期间事件循环心跳从 0 次 → 22 次;退避耗时从 1365ms 降到毫秒级。见 D2-2 / D2-3。

6. CRLF 让状态机「静默停摆」 (The Silent Stall)

  • 痛点:这是本轮审计中最危险的缺陷——因为它不报错。bridge.md 的状态解析正则硬编码 \n 行尾,而仓库 core.autocrlf=true 且没有 .gitattributes。任何 Windows 用户 clone 后,bridge.md 就是 CRLF 行尾,parseBridge() 返回 null,tick() 首行直接 return。结果是状态机彻底停摆、零日志、零报错——用户只会看到「什么都没发生」,且没有任何线索指向行尾。实测:CRLF 文件的正则匹配结果就是 null。
  • 解决:三重防线。① 仓库层:新增 .gitattributes 强制 * text=auto eol=lf,从根源归一化;② 解析层:parseBridge() 在做任何正则匹配前统一调用 normalizeEol(),把 CRLF/CR 一律转成 LF;③ 兜底层:所有派生正则加 \r?,逐行取值时再 replace(/\r$/, '')——否则 status 会变成 "PENDING_DEV\r",导致所有状态判断失配。
  • 工程验证:CRLF 与 LF 文件的解析结果完全一致,且含反证测试(证明不做归一化时 CRLF 确实解析失败)。见 tests/crlf-regression.test.cjs 12 项。

7. git 命令的「静默降级」 (The Silent Degradation)

  • 痛点:看门狗要审查用户项目的 git 历史,但进程 cwd 取决于用户从哪个目录启动。若 cwd 完全不在 git 仓库内,git rev-parse 抛 fatal: not a git repository,而旧代码 catch { return null } 把异常吞掉——结果是 diff 审查静默降级:不报错,只是审查内容为空。用户看到的是「Supervisor 说没问题」,而不是「审查根本没跑」。
  • 解决:启动期用 git rev-parse --show-toplevel 探测一次仓库根并缓存,后续所有 git 命令与用户自定义 checks 都以该根为 cwd(不依赖用户从哪启动);探测失败则明确 warn 到控制台。同时统一走 execInProject() 入口,并约定返回值契约:探测失败返回严格 null 而非空字符串,让调用方能区分「项目不可用」(配置问题)与「命令成功但无输出」(正常状态)。
  • 一个被实测推翻的直觉:最初以为「给 execSync 加 cwd: process.cwd()」就能修。实测发现 git 会自动向上查找 .git,cwd 在仓库内任意层级都正常,所以那本来就是默认值、加了毫无作用。真正的问题是「完全不在仓库内」的场景。
  • 工程验证:见 tests/git-root-detection.test.cjs 12 项,覆盖仓库内(含深层子目录)、非仓库、返回值契约三种场景。

📷 项目实况展示

以下是项目在真实环境下,完全由大模型自行流转、互相协作与审阅的运行实况:

1. 自动化流水线运转

左上:监工方 (Supervisor) 正在异步轮询。右上:施工方 (Builder) 完成代码编写并触发重审。下方:Watchdog 实时调度。 流水线运转实况

2. 状态机切换与冲突阻断

严谨的状态流转机制,即使遇到复杂问题,系统也能及时阻断并将控制权安全挂起。 状态机切换

3. 完美零干预闭环

施工方代码全自动通过 ESLint/Prettier 校验,监工审批通过,Watchdog 自动推进至下一阶段任务。 零干预闭环


📖 快速开始与详细文档

要体验本项目,只需在一个空文件夹下执行:

npx agent-bridge init

如果您想深入了解底层协议细节、CLI 指南或想参与贡献,请查阅以下核心文档:


🧪 测试与质量保障

npm test          # 运行全部 4 个套件(共 90 项断言,含真实多进程压测)
npm run test:concurrency   # 仅跑并发缺陷修复验证(45 项,最核心)
套件 断言数 验证内容
lock-primitives 21 锁原语基础行为、无锁对照组(证明锁确实生效)
crlf-regression 12 CRLF 行尾回归(高危,防状态机静默停摆)
git-root-detection 12 git 仓库根探测(防 diff 审查静默降级)
concurrency-fixes 45 四个并发缺陷的修复验证 + 端到端联调

测试设计原则:所有并发断言都必须保留对照组数据(例如无锁时 8 进程丢 87%、 加锁后 200/200)——没有对照就无法证明锁是否真的生效。判定互斥的正确判据是 「任意时刻只有一个进程在临界区内」(观测临界区重叠次数),不能用「赢家数 > 1」 ——串行接管下多个进程先后合法持锁,赢家数必然大于 1。

tests/_archived/ 下是审计过程中的历史对照实验,因对照样本丢失已归档,不参与 npm test。


“真正的自动化不是赋予大模型无限的自由,而是为其戴上最严酷的工程枷锁。” —— 感谢您的阅读。

About

基于 Pinia 全局状态思想的「多智能体异步协作」底层架构。/A zero-dependency framework for autonomous dual-agent collaboration. /

Topics

Resources

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages