Files
stack/packages/stack-idealjs/blog/cqh963852/gorzil.md
T
2026-08-19 11:28:22 +08:00

101 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
authors: cqh963852
---
# gorzil:面向多人协作的 AI 原生工具开发自述
> 文章结构整理自 glm-5.3
## 为什么做
最近观察到一个现象:AI 编码工具越来越强。
但它们始终是"单人玩具"。Cursor、Claude Code 这类产品默认一个开发者对着一个终端。人与人围绕 AI 工作过程的协作,基本是空白。
{/* truncate */}
我想做的事情可以概括为:多人 + 多 agent 共享同一个工作现场的工具。人发起任务,agent 执行,所有人(包括其他 agent)看到同一份不断演进的状态。
## 发生了什么
在这个开发过程中,我只负责提 ISSUE、把控架构和技术走向。总结性、文档性的工作交给了 ai,编码工作也让 ai 处理,结果好坏参半,后续也会提到。
## 核心设计
gorzil 是一个 Rust 多 Agent 协作平台,三个关键词:CRDT 协同、看板驱动、点对点数据同步。
### 数据本质是共享状态,不是消息流
这是整个项目最重要的一个技术决策。传统 IM(Slack 式)把协作建模为消息流,但 AI 协作的场景里,任务状态是不断被多方修改的:人创建任务、agent 领取、执行中、产出物挂回任务。如果用消息流建模,状态同步就是一场灾难。
所以选择了 CRDT,具体是 Loro。看板/房间状态是共享文档,agent 是文档间的翻译者,图片存引用而非二进制。同步难题由 CRDT 自然消解,不需要中心服务器做仲裁。
### 三端架构
```
coord(公网):信令 + Logto 认证 + 组织管理 + TURN
daemon(PC):本地 agent 宿主,接受 WebRTC,Loro 同步
app(浏览器):Dioxus Web 客户端,发起 WebRTC,Loro 同步
```
coord 只做信令和认证,不碰业务数据。数据在 daemon 和 app 之间通过 WebRTC DataChannel 点对点同步,P2P 失败时降级 coturn 中继。这个"云端尽量薄"的形态是有意为之——协作数据不应该经过我的服务器。
### 双 AI 审查的安全模型
本地 agent 要执行命令、改文件,安全是绕不开的问题。软件把风险暴露给用户做决策,是很常见的偷懒行为——即对风险不做设计,弹个窗让用户选,责任就转移出去了。
这是一种经典的工程师做法。静态规则也是同类问题:区分不了 `rm -rf` 清理 target 和清理 home 的区别,于是干脆都问用户。
但协作软件要面对的是不同身份的人群。既要减少风险对用户的干扰,也要保留工程师的安全审查能力。这两件事不能靠同一个机制完成。
在这里,gorzil 做了如下设计:
1. 减少干扰上
引入 ai 辅助审查:在 tool_calls 提取和执行之间插入一个独立的审查 AI,做意图对齐判断——主 AI 要执行的动作,是否服务于用户的原始意图。审查 AI 的输入是净化过的结构化摘要,不接收主 AI 的原始上下文,从源头切断 prompt injection 的路径。已知危险命令走硬规则,语义模糊的才交给模型。
对于审查 AI 的额外要求是,接入用户足够信任的模型,不做中转站之类的危险做法——安全链路上如果再引入一个不受信任的环节,那就等于白做。
2. 审查能力上
要处理的是传统 ai 群聊看不到 agent 工作过程的难题。群聊里 agent 只输出结论,过程是黑盒。虽然有些聊天工具可以不断更新当前的消息,但是我想,应该没有人愿意一直盯着 ai 在干什么。那样没有节省多少时间。
gorzil 的做法是把工作过程结构化:看板的任务操作记录,将看板任务抽象为 thread 下的引用,操作历史跟着任务走。
如果要看某个 agent 是怎么做的,则通过 agent doc 检查它的历史记录。工程师不再需要盯着消息流,而是直接审计过程本身。
### 被否决的路线
点对点通信、传输层曾经动摇过,最后还是使用 WebRTC 方案。最初的方案也是 WebRTC —— 自己做信令、自己管 ICE、自己部署 coturn。每一个步骤都是琐碎的活,甚至 ai 编码留下了 bug。
看到 iroh 后,优雅的抽象,地址即身份,打洞内置,看起来可以砍掉一大片代码。几乎要迁过去了,甚至开始规划迁移的步骤。
但是在让 ai 真正动手时,ai 说“出问题啦:浏览器端的 P2P 做不了”(一些技术上的限制)。
而 WebRTC 那套虽然琐碎,但每一件琐碎的事我都已经理解了。迁移到 iroh 并不会省掉我熟悉的麻烦,而且增加了我不熟悉的黑盒。
我最终的选择是那个已经踩过坑的方案。
### CRDT 增量同步的坑
wasm 端的 CRDT 增量同步是最痛苦的一段。由于 dioxus 是跨平台,rtc 有 native、wasm 两个端。最痛苦的是,不知道 bug 长什么样。
bug 修复大部分是 ai 在做。因为无法定位 bug,对 ai 的修复过程既不做严格审查,也不纠结代码对不对。协作方式只有两条:
1. 反复告诉 ai"出错了",让 ai 打日志,再把日志喂回去
2. 后续让他自己控制浏览器去读日志
折腾到快要放弃 ai 修复,准备人手工处理时,glm-5.3 发布了。用对待 ai 的老方式尝试了一下,问题解决了(绷不住了)。
为了这个问题,大概燃烧了 2B 的 token。
解决后的第一件事,没有让 ai 接着做事,而是抓紧把集成测试用例写起来。
让 ai 趁着神志清晰的时候,把集成测试写上。不至于出现相同的错误时,再费劲告诉 ai 应该怎么做。
### UI 体系
UI 刚开始做,所以我几乎是 1:1 的模仿 Slack。三栏布局、频道、右侧详情面板,样式体系切到 daisyUI,抽了 gorzil-ui crate,配 storybook 和 Playwright 视觉基线。这部分编码工作 ai 参与度较高,因为组件迁移是模式明确的机械劳动。
但模仿的过程中一个问题一直悬着:如果我的软件在形式上和 Slack 几乎接近,那 Slack 也可以解决 gorzil 能解决的问题——除了技术核心不同。这个质疑我给不出反驳。CRDT、P2P、双 AI 审查都是看不见的东西,用户看见的就是又一个聊天软件。
所以我还在思考:软件的形式本身是否需要变化,才能更好地揭露问题、处理问题。看板驱动是我目前的一个答案——任务状态是一等公民,消息只是状态的注释。但这个答案对不对,要等真实使用之后才知道。形式追随的还是问题本身,而不是 Slack 的截图。