编程 Buzz 深度拆解:Jack Dorsey 的 Block 开源「人机蜂巢」,为什么说它可能是 Slack 之后团队协作的下一站

2026-07-28 02:19:36 +0800 CST views 10

Buzz 深度拆解:Jack Dorsey 的 Block 开源「人机蜂巢」,为什么说它可能是 Slack 之后团队协作的下一站

一、背景:当 Agent 成为「同事」,聊天工具就不够用了

2026 年 7 月,GitHub Trending 榜首出现了一个新面孔:block/buzz——Jack Dorsey 掌舵的 Block(原 Square)开源的一个「hive mind communication platform(蜂巢思维通信平台)」,短时间内冲到近 1 万 Star,Issues 343 个、PR 435 个,社区活跃度肉眼可见。

一句话概括它是什么:一个自托管的团队工作区,人类和 AI Agent 在同一个房间里干活,底层是一个 Nostr Relay。

先别急着翻白眼说「又一个 AI 协作工具」。我花了一晚上把它的 README、ARCHITECTURE.md 和 NOSTR.md 全部啃完,发现这个项目跟市面上那些「Slack + ChatGPT 机器人」的缝合怪有本质区别。它回答的是一个更根本的问题:

当 AI Agent 从「聊天窗口里的玩具」变成「真正执行任务的数字员工」时,团队协作的基础设施应该长什么样?

现有工具的答案都很尴尬:

  • Slack/飞书/钉钉:Bot 是二等公民,走的是 Webhook + Bot Token 那套补丁式 API,权限模型和人类完全两套,审计日志基本没有
  • GitHub:代码协作没问题,但讨论、CI、发布、值班这些散落在七八个系统里
  • 各家 Agent 平台:Agent 能干活,但它干了什么、为什么这么干、谁批准的,全靠平台方的黑盒日志

Buzz 的答案很激进:人和 Agent 用同一套身份模型(secp256k1 密钥对)、同一个事件日志、同一套权限边界。Agent 不是 Bot,是拥有自己密钥的正式成员。

这篇文章我会从协议设计、系统架构、事件管线、订阅系统、安全模型五个层面把 Buzz 拆开,配上可以直接跑的命令和代码,最后聊聊它的局限和这类「Agent-native 协作平台」的行业走向。

二、核心理念:一切皆签名事件

Buzz 的整个世界观建立在一个极简的原语上——Nostr NIP-01 事件

{
  "id":      "<对事件规范化序列化后的 sha256>",
  "pubkey":  "<secp256k1 公钥, hex>",
  "kind":    9,
  "tags":    [["h", "<channel-uuid>"], ["e", "<event-id>"], ["p", "<pubkey>"]],
  "content": "消息正文或 JSON 载荷",
  "sig":     "<对 id 的 Schnorr 签名>"
}

六个字段,没了。聊天消息是事件(kind:9),表情回应是事件(kind:7),删除是事件(kind:5),工作流的每一步是事件(kind:46001–46012),Git 的 patch 和 CI 状态也是事件(NIP-34),甚至画布编辑、语音房间的生命周期都是事件。

这个设计带来三个直接后果:

1. 加新功能 = 定义新的 kind 数字。 老客户端看不懂新 kind 就直接忽略,什么都不会坏。Buzz 目前在 buzz-core 里定义了 81 个 kind 常量,其中 40000–49999 是自定义区间:

Kind含义
9频道聊天消息(NIP-29 群聊)
7表情回应(NIP-25)
40003消息编辑
43001Agent 任务请求
45001 / 45003论坛主贴 / 回复
46001–46012工作流执行事件
20001 / 20002在线状态 / 输入中(临时事件,不落盘)

2. 天然的全链路审计。 每个事件都带 Schnorr 签名,谁发的赖不掉。Agent 审查了一个 PR?签名事件。工作流自动发布了一个版本?签名事件。人类点了个 👍 批准?还是签名事件。buzz-audit crate 再用哈希链把这些事件串成防篡改日志。这对「Agent 干了什么必须可追溯」的合规场景来说,是从地基上解决问题,而不是事后补日志。

3. 人机真正同权。 Agent 有自己的密钥对、自己的频道成员身份、自己的审计轨迹。给 Agent 授权的方式和给新同事授权一模一样:把它拉进频道。不是「给 Bot 开个 scope 白名单」,而是「身份即边界」。

README 里有句话我很喜欢:

Agents are part of the room, not haunted cron jobs.(Agent 是房间里的成员,不是闹鬼的定时任务。)

三、架构分析:一个 Relay 统治一切

3.1 总体拓扑

┌────────────────────────────────────────────────────┐
│                    客户端                            │
│  桌面 App(Tauri+React)  Agent(Goose/Codex/Claude)   │
│  buzz-cli(JSON in/out)  任意 NIP-29 Nostr 客户端     │
└──────────────┬─────────────────────────────────────┘
               │ WebSocket + REST
               ▼
┌────────────────────────────────────────────────────┐
│                buzz-relay (Axum)                    │
│  NIP-42 认证 · EVENT 管线 · REQ 订阅 · HTTP 桥       │
│  /media(Blossom) · /git(NIP-34) · 审计日志           │
└────┬──────────────────┬──────────────────┬─────────┘
     ▼                  ▼                  ▼
 Postgres           Redis              S3/MinIO
 (事件+FTS全文检索)  (pub/sub+在线状态)   (媒体存储)

与「去中心化」的 Nostr 原教旨不同,Buzz 做了一个务实的取舍:没有 P2P、没有 gossip、没有多 relay 同步,所有读写都经过唯一的 relay。这一刀砍掉了分布式系统 90% 的复杂度——一致性、冲突合并、事件传播延迟全都不存在了。你要的是团队工作区,不是加密货币论坛,单一事实源(single source of truth)就是最合理的架构。

但它保留了 Nostr 的接口兼容性:任何标准 NIP-29 客户端(如 Chachi、0xchat)都可以直接连上 Buzz relay 收发消息。这一点很妙——协议开放性没丢,生态兼容白送。

3.2 Rust Crate 分层:强制的模块隔离

Buzz 是一个 Rust monorepo,crate 依赖关系被刻意设计成星型:

buzz-core   (零 I/O:类型、签名校验、filter 匹配、kind 注册表)
    ├── buzz-db        (Postgres:事件、频道、token、工作流、审计)
    ├── buzz-auth      (NIP-42/98、API token、scope、限流接口)
    ├── buzz-pubsub    (Redis pub/sub、presence、typing)
    ├── buzz-search    (Postgres FTS 全文检索)
    ├── buzz-audit     (哈希链防篡改日志)
    └── buzz-workflow  (YAML 自动化引擎)
         └── buzz-relay (唯一的组装点)

两个值得抄作业的工程决策:

其一,buzz-core 在 Cargo.toml 里显式禁止依赖 tokio、sqlx、redis、axum。 零 I/O 的核心 crate 意味着签名校验、filter 匹配这些纯逻辑可以在任何上下文里测试和复用,编译也快。

其二,子系统之间互相不可见,跨子系统协调只能通过 relay。 buzz-workflow 永远不会直接调 buzz-pubsubbuzz-search 永远不碰 buzz-db。所有编排逻辑集中在 buzz-relay 一处。这种「星型依赖 + 中心编排」的结构在大型 Rust 项目里能有效防止 crate 之间长出意大利面。

3.3 事件管线:12 步流水线的取舍艺术

客户端提交一个 ["EVENT", <event>] 后,relay 内部跑一条 12 步流水线:

1.  AUTH 检查      — 已通过 NIP-42 认证?有 MessagesWrite scope?
2.  公钥匹配       — event.pubkey == 认证公钥?(防止代签)
3.  拒绝 AUTH 事件 — kind 22242 永不落盘
4.  临时事件分流   — kind 20000–29999 走旁路(不存储不审计)
5.  签名校验       — spawn_blocking 里跑 Schnorr 验签 + ID 哈希
6.  成员校验       — 事件带频道 tag?检查发送者是否是成员
7.  DB 写入        — INSERT ... ON CONFLICT DO NOTHING(幂等)
8.  Redis PUBLISH  — 频道级事件广播到其他 relay 节点
9.  本地扇出       — 订阅注册表 → 连接管理器推送
10. 检索索引       — 发送到有界队列(容量1000),异步消费
11. 审计日志       — spawn 异步任务,不阻塞
12. 工作流触发     — spawn 异步任务,排除工作流自身事件防死循环

几个细节值得展开:

验签放进 spawn_blocking Schnorr 验签是 CPU 密集操作,直接在 tokio 异步任务里跑会阻塞 reactor 线程。丢进阻塞线程池是标准做法,但很多项目会忘。

步骤 10–12 全部 fire-and-forget。 搜索索引失败、审计写入失败、工作流触发失败,都不影响事件本身的提交成功。消息收发是主干,其余是旁路——这个优先级排序保证了核心体验的可用性。

工作流防循环。 工作流执行产生的事件(kind 46001–46012)、relay 签名的带 buzz:workflow 标签的消息,都被排除在工作流触发之外。否则「工作流 A 发消息触发工作流 B 发消息触发工作流 A」的死循环分分钟把系统打挂。做过事件驱动系统的人都知道这种防护有多重要,也知道有多少系统是上线之后被循环风暴教育了才补上的。

幂等写入。 ON CONFLICT DO NOTHING 意味着客户端重发同一事件(网络重试很常见)不会产生重复数据——事件 ID 本身就是内容哈希,天然去重。

3.4 订阅系统:三级索引的扇出优化

聊天系统的核心性能瓶颈在扇出(fan-out):一条消息进来,要推给哪些连接?Buzz 用 DashMap 做了三级索引:

pub struct SubscriptionRegistry {
    // 全量订阅表
    subs: DashMap<ConnId, HashMap<SubId, SubEntry>>,
    // 一级索引:(channel_id, kind) → 订阅列表,O(1) 命中
    channel_kind_index: DashMap<IndexKey, Vec<(ConnId, SubId)>>,
    // 二级索引:channel_id → 订阅列表(未指定 kind 的通配订阅)
    channel_wildcard_index: DashMap<Uuid, Vec<(ConnId, SubId)>>,
}

事件到达时按序查询:

层级索引适用场景
1(channel_id, kind) 精确索引明确订阅了某频道某类事件,O(1)
2channel_id 通配索引订阅了整个频道所有事件
3全表线性扫描全局订阅(无频道约束)兜底

关键安全设计:频道级事件只推送给显式订阅了该频道的连接,全局订阅永远收不到私有频道的事件——哪怕 filter 条件匹配上了也不行。这是一条硬编码的安全边界,防止「订阅所有 kind:9」变成窃听全站私聊的后门。

另一个防竞态细节:REQ 订阅处理时,先检查频道访问权限,再注册订阅。反过来做的话,非成员会在「注册成功」到「权限检查踢出」之间的窗口期收到私有频道的实时消息。这种 TOCTOU 级别的细节能写进架构文档,说明团队是真的在安全上花了心思。

3.5 连接生命周期与慢客户端处理

每个 WebSocket 连接跑三个并发任务:recv_loop(收帧解析分发)、send_loop(排空 mpsc 队列写帧)、heartbeat_loop(30 秒 ping,3 次 pong 丢失即断开),用 CancellationToken 统一协调关闭。

慢客户端处理很干脆:try_send 发现发送缓冲满时累加计数器,连续 3 次满就直接掐掉连接。宁可断开慢客户端,也不让它拖垮 relay 的内存——群聊系统里一个 3G 网络的手机端能把服务器 buffer 撑爆的故事,经历过的人都懂。

四、代码实战:从部署到 Agent 接入

4.1 五分钟自托管

git clone https://github.com/block/buzz.git && cd buzz
. ./bin/activate-hermit   # Hermit 固定工具链,自动下载依赖
just setup && just build  # Docker 服务 + 数据库迁移 + 编译
just dev                  # relay(ws://localhost:3000) + 桌面 App 一起起

生产部署用 deploy/compose/ 下的 Compose bundle:Postgres + Redis + MinIO + 可选 Caddy/TLS,一台 VPS 就能跑。桌面客户端有 macOS/Linux/Windows 打包版,直接从 Releases 下载。

4.2 用 nak 直接说 Nostr 方言

因为 relay 说标准 NIP-29,用通用 Nostr CLI 工具 nak 就能操作一切:

# 创建频道(kind:9007)
nak event -k 9007 --tag "name=dev-channel" --tag "visibility=open" \
  --auth --sec <私钥> ws://localhost:3000

# 发消息(kind:9,必须带 #h 频道 tag)
nak event -k 9 -c "Hello from NIP-29!" --tag "h=<channel-uuid>" \
  --auth --sec <私钥> ws://localhost:3000

# 订阅频道实时消息
nak req -k 9 --tag "h=<channel-uuid>" --stream \
  --auth --sec <私钥> ws://localhost:3000

# NIP-50 全文搜索(Postgres FTS 撑腰)
nak req -k 9 --tag "h=<channel-uuid>" --search "deploy failed" -l 20 \
  --auth --sec <私钥> ws://localhost:3000

# NIP-10 线程回复
nak event -k 9 -c "回复内容" --tag "h=<channel-uuid>" \
  --tag "e=<父消息id>;;reply" --auth --sec <私钥> ws://localhost:3000

管理端也是事件驱动的(NIP-43 管理事件):

# 添加成员(kind:9030,需 owner/admin 签名)
nak event -k 9030 --tag "p=<目标公钥>" --tag "role=member" \
  --auth --sec <管理员私钥> ws://localhost:3000

# 提升为 admin(kind:9032)
nak event -k 9032 --tag "p=<目标公钥>" --tag "role=admin" \
  --auth --sec <管理员私钥> ws://localhost:3000

连「加人踢人改角色」都是签名事件,管理操作自动进审计日志。对比一下某些 IM 的管理后台连操作日志都没有,高下立判。

4.3 Agent 接入:buzz-cli 与 ACP 桥

Agent 侧的入口是 buzz-cli——一个刻意为 LLM 工具调用设计的 CLI:JSON 进,JSON 出,没有花哨的 TUI:

export BUZZ_PRIVATE_KEY=<agent专属私钥>
buzz-cli send --channel <uuid> --content "CI 挂了,我看了下是依赖锁文件冲突"

更有意思的是 buzz-acp——一个 ACP(Agent Client Protocol)桥接层,把频道里的 @mention 转发给 Goose、Codex、Claude Code 这些编码 Agent。也就是说,你在频道里 @ 一个 Agent 让它修 bug,它通过 ACP 收到任务、用 buzz-dev-mcp 提供的 shell 和文件编辑工具干活、把 patch 以 NIP-34 事件发回频道。整条链路上每一步都有签名。

4.4 YAML 工作流:Reaction 驱动的发布流程

buzz-workflow 支持消息、表情回应、定时、Webhook 四种触发器。README 里那个「自己写发布说明的 release」的场景大致是这样的:

# 概念示意:tag 触发 → Agent 起草 → 人类 👍 批准 → 发布
on:
  webhook: { id: release-tag }
steps:
  - agent: release-bot
    prompt: "读取本次 tag 涉及的已合并 PR,起草发布说明,发到 #release 频道"
  - wait_for:
      reaction: "👍"
      from: [release-manager-pubkey]
  - agent: release-bot
    prompt: "发布已批准的 release notes 并打包"

注意那个 wait_for reaction——人类的批准动作就是一个 kind:7 表情事件,带签名、可检索、进审计链。「Human in the loop」不再是 PPT 词汇,而是协议层的一等公民。(工作流审批门控目前标记为 🚧 施工中,但基础设施已就位。)

五、安全模型与多租户设计

5.1 认证:没有密码,只有密钥

Buzz 没有传统的用户名密码。WebSocket 连接用 NIP-42(relay 下发随机 challenge,客户端签名应答,±60 秒时间容差),HTTP 端点用 NIP-98(对 URL + Method 签名的 kind:27235 事件)。另有 API token 体系给需要细粒度 scope 的场景,14 种 scope 覆盖消息、频道、用户、任务、文件的读写管理。

访问控制的几个 fail-closed 设计:

  • 公钥白名单开启后,数据库查询失败时拒绝连接(而不是放行)
  • 多租户模式下,未知域名直接拒绝,不会 fallback 到默认租户
  • 涉及私信和成员变动通知的订阅,必须带 #p filter 且只能是自己的公钥,否则 relay 直接拒绝订阅——从协议层杜绝窃听他人私信

5.2 私信:NIP-17 Gift Wrap

私信用 NIP-17 礼物包装(kind:1059):内容用临时密钥加密签名,relay 只知道「有一个加密包裹要给某公钥」,看不到内容和真实发送者。私信不进搜索索引。自托管场景下这意味着连 relay 管理员都读不了你的私聊——这是大多数企业 IM 做不到(或者说不愿做到)的。

5.3 多租户:URL 即社区

Buzz 的多租户模型很清爽:请求的域名决定社区(community),在任何 AUTH/EVENT/REQ/REST 处理之前先解析 TenantContext。默认自托管是一域一社区;托管服务商可以在共享的 Postgres/Redis/S3 上跑多个社区,但每个社区的数据、搜索索引、审计链、媒体元数据全部按社区隔离。客户端提交的频道 tag 必须能解析到当前域名对应社区内的频道,不能跨界。

同一个公钥可以加入多个社区,但资料和私信不跨社区继承——身份是全局的,数据是社区本地的。这个边界划得很清楚。

六、冷静看:局限与坑

夸了这么多,泼点冷水:

1. 限流还没真正实现。 架构文档自己承认:RateLimiter 只有测试桩,RateLimitConfig 定义的 4 档限流(human/agent-standard/agent-elevated/agent-platform)目前只是设计目标。生产环境裸奔限流,一个失控的 Agent 能把 relay 写爆。上生产前必须在前面加一层网关限流。

2. 单 relay 是单点。 没有 P2P 换来了简单性,也意味着 relay 挂了全员下线。多节点扇出通过 Redis pub/sub 打通了,但 presence 的多节点扇出还是「documented as future work」。高可用方案得自己搭。

3. 生态成熟度。 移动端(Flutter)还在施工,推送通知在「strong opinions, pending code」列(README 原话是「请不要把你的合规计划建立在 💭 那一栏上」,这种坦诚倒是难得)。邀请事件 kind:9009 收了存了但处理是 no-op。CLI 管理成员时并发调用会有时间戳冲突,官方建议循环加成员时 sleep 1——这种细节文档里写了,但也暴露了工程还在早期。

4. Nostr 的认知门槛。 对普通团队来说,「给每个成员生成 secp256k1 密钥对」比「发邮箱邀请」的心智成本高一个量级。密钥丢失、密钥托管、密钥轮换这些问题,文档还没给出企业级答案。

七、总结与展望:协作工具的「Agent-native 重构」才刚开始

回头看 Buzz 的三个核心押注:

  1. 身份统一:人和 Agent 都是密钥对,权限即成员身份,不搞两套系统
  2. 日志统一:聊天、代码、CI、审批、工作流全是同构的签名事件,一个搜索索引通吃
  3. 协议开放:站在 Nostr 生态肩膀上,任何 NIP-29 客户端即插即用

这三条恰好对应了现有工具链的三大痛点:Bot 权限体系的补丁化、信息散落七个系统的割裂感、平台锁定。用 README 的话说,Buzz 赌的是「一个社区能干掉团队目前用聊天软件 + 代码托管 + 机器人 + CI 面板 + 发布工具 + 搜索索引 + 一堆胶水代码假装在协作的整个拼盘」。

会不会成?不好说。Slack 的网络效应不是技术优势能轻易撬动的,Nostr 的密钥模型对非技术团队也确实不友好。但有一点我比较确定:当 Agent 真正开始承担生产任务,「Agent 干了什么、谁授权的、依据是什么」会从加分项变成硬需求。到那时候,「每个动作都是签名事件」的架构就不是极客审美,而是合规刚需。

Buzz 未必是终局赢家,但它把「Agent-native 协作平台」的架构标杆立在了这里:Rust 的性能底座、Nostr 的开放协议、哈希链审计、身份即权限。后来者绕不开这套参照系。

对我们程序员来说,现在就值得做两件事:一是 clone 下来跑一遍,感受一下「给 Agent 发密钥拉进频道」和「给 Bot 申请 Token 配 Webhook」的体验差异;二是把它的事件管线和订阅索引设计读一遍——就算不用 Buzz,这些模式在你自己的事件驱动系统里都用得上。

蜂巢已经开源,蜜蜂自带密钥。剩下的,交给时间。

推荐文章

15 个 JavaScript 性能优化技巧
2024-11-19 07:52:10 +0800 CST
如何配置获取微信支付参数
2024-11-19 08:10:41 +0800 CST
CSS实现亚克力和磨砂玻璃效果
2024-11-18 01:21:20 +0800 CST
避免 Go 语言中的接口污染
2024-11-19 05:20:53 +0800 CST
Gai:AI 原生的 Go Web 全栈框架
2026-05-21 16:19:43 +0800 CST
程序员茄子在线接单