在 ATProto 之上运行 ActivityPub
摘要
本文建议在 AT Protocol 的 PDS 之上运行 ActivityPub,认为结合两种架构可以在保持与现有联邦式社交媒体兼容性的同时,提供更好的用户自主权和可信退出机制。
暂无内容
查看缓存全文
缓存时间: 2026/07/10 15:21
# ActivityPub 叠加 ATProto
来源:https://berjon.com/ap-at/
¿Por qué no los dos?
一幅古斯塔夫·多雷风格的嵌合体生物,类似龙形,背上驮着一位女子,通体绿色。在政治运动圈里有这样一个笑话:如果你有一个托洛茨基主义者(你可以把“托洛茨基主义者”替换成任何其他派别),你就有了一党;如果你有两个托洛茨基主义者,你就有两个派系;而如果你有三个托洛茨基主义者,那就得党内分裂了。
如今开放社交媒体领域的氛围似乎也是如此。人们觉得必须选边站队并捍卫己方,宁可互相撕咬,也不愿确保那些“豹子”不会伤人。我想这在某种程度上非常社交媒体化,也非常愚蠢。
我想通过提出一个大家都可以一起讨厌的建议,来缓解这种装腔作势的乏味感。或者更严肃地说,我想通过一个简短的练习来证明,稍微多关注一些有趣的架构细节可能并非最愚蠢的事。这可以为更广泛地讨论Web上的社交媒体奠定基础。
这只是一个草图,并且存在问题。我最初想制作一个原型,但由于工作原因,我几乎没有带宽来做原型(所以我主要把笔记扔到博客上)。把它看作一个设计挑衅(https://en.wikipedia.org/wiki/Speculative_design),挑衅的点在于:
> 只需相对较少的工作,我们就可以在 ATProto 的个人数据服务器(PDS)之上运行 ActivityPub。
我不会试图说服你,我们*可以*在不修改两者当前状态的情况下做到这一点,但我想让你关注*为什么*这件事值得思考,并且如果运气好的话,说服你我们*应该*朝这个方向前进(即使不一定非得是这个确切的组合)。请注意,我很难相信我是第一个想到这一点的人,但我确实没找到任何相关的东西。也许你认为我应该是唯一想到这个主意的人。
首先要理解的是,AT 协议 (https://atproto.com/) 并不是 Bluesky。ATProto 旨在成为构建社交媒体应用的通用工具箱,并且可以说它扩展了(或者可以轻松扩展)到支持个人数据服务器(PDS)的通用基础设施。事实上,ATProto 架构明确被描述为 PDS,并且该 PDS 是一个用户代理 (https://berjon.com/user-agency/)。虽然 Bluesky 已经明确表示他们打算控制实现 Bluesky(运行在 ATProto 之上)的 `app.bsky` API 路由,但他们也明确表示 `com.atproto` 路由旨在成为开放标准。(这尚未获得治理机制来保证,但我本来也不打算请求许可。)
我之所以提请你注意这种区别,是因为 ATProto 具有有趣的特性,特别是它如何支持可插拔的身份(不依赖于你使用的服务器)以及签名的数据仓库。这赋予了用户权力,而不是像传统联邦那样将权力赋予服务器管理员。这意味着你总是可以保证可信退出 (https://subconscious.substack.com/p/credible-exit),你不会被锁定。默认情况下,电子邮件式的联邦(这是 AP 的底层模型)容易被掌控,而电子邮件确实已经被掌控了(约 85% 是 Gmail,迁移要么在域名层面,要么靠管理员的好意——他们可能接受转发)。
然而,ATProto 本身并不做任何社交媒体。它“只是”一个层,在其之上可以实现协议。这并不意味着它可以用来实现任意的协议,但 ActivityPub/Activity Streams 有一个非常好的间接层,使这变得容易得多:`Actor` 文档 (https://www.w3.org/TR/activitystreams-core/#actors)。一个演员是任何可以拥有活动、从而可以在社交上做事的实体。你可以从几乎任何地方获取演员文档,例如,你可以通过在我的 Mastodon 身份 URL 后添加 `.json` (https://mastodon.social/@robin.json) 来查看我的。你也可以通过将句柄解析为 DID,并在 DID 文档中找到嵌入的信息来获取它。
演员文档有一个巧妙的特性:它为你提供了各种操作的 API 端点的 URL。也就是说,它不是期望整个 API 的端点位于预定义的位置,而是为每个端点指定了任意的 URL。从我的 Mastodon 演员文档中删除一些冗余后,我们可以看到列出了几个这样的端点:
```json
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://mastodon.social/users/robin",
"type": "Person",
"following": "https://mastodon.social/users/robin/following",
"followers": "https://mastodon.social/users/robin/followers",
"inbox": "https://mastodon.social/users/robin/inbox",
"outbox": "https://mastodon.social/users/robin/outbox",
"preferredUsername": "robin",
"name": "Robin Berjon"
}
```
这意味着我们可以将其用作间接层,指向带有 ActivityPub 路由的个人 ATProto PDS:
```json
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://mastodon.social/users/robin",
"type": "Person",
"following": "https://pds.berjon.com/xrpc/org.w3.activitypub.following",
"followers": "https://pds.berjon.com/xrpc/org.w3.activitypub.followers",
"inbox": "https://pds.berjon.com/xrpc/org.w3.activitypub.inbox",
"outbox": "https://pds.berjon.com/xrpc/org.w3.activitypub.outbox",
"preferredUsername": "robin.berjon.com",
"name": "Robin Berjon"
}
```
成功了吗?还没。
## 我们遇到了麻烦
我知道你们正坐在座位边缘,咬指甲,有些人紧抓珍珠,等着看我们是否真的可以只通过一点 JSON 调整和一个 ATProto 应用,在不修改任何一个规范的情况下,在 ATProto 上运行 ActivityPub。答案是:还不完全行,但并非遥不可及或不切实际。
第一个问题是,一个 XRPC nsid(例如 `org.w3.activitypub.inbox`)可以是查询(GET)或过程(POST),但据我所知,不能两者都是。但 ActivityPub 的 `inbox` 属性必须支持多个方法。先不谈关于 REST 与 RPC 的长期争论(*哈欠连篇*),这并非无法弥合的重大问题。要么可以为不同的方法更新演员文档,添加独立的属性(对于非 ATProto 实现,这些属性可以指向相同的 URL),要么可以修改 XRPC Lexicon 以支持重载方法。阻碍这里沟通的唯一障碍是人们对这个决定过于虔诚。在现实世界中,这是一个相对容易的修复。
第二个问题是身份和句柄系统并不完全一致。我相信没有什么能阻止 `com.atproto.identity.resolveHandle` 解析 `@[email protected]`,就像它解析 `@robin.berjon.com` 一样,它可能只是去掉开头的 `@`,将另一个 `@` 替换为 `.`,然后使用 DNS 解析 DID。这甚至与 IndieWeb ActivityPub 兼容,在该协议中演员拥有自己的域名(这在 ATProto 用户中相对常见)。应该可以让演员文档也指向 DID,并且 DID 文档反向链接到它作为补充。
(我在这里不打算讨论 DID 的局限性,特别是 `did:plc` 的问题,因为它们不影响集成。我一直在想 DSNP 是否可以为 DID 方法提供合适的基础,但那是另一个话题了。)
然后……就这样了?我的猜测是,由于我还没有机会实际端到端地实现这一点,我可能遗漏了一些棘手问题。但乍一看,这比你在激烈的网络辩论中所想象的要可行得多。
## 为什么要这么做,老兄?
绝大多数情况下,我们对社交媒体的体验是孤岛式的。它们是封闭的环境,旨在让你留在内部,并且与外部世界的整合非常差。
Activity* 标准和 ATProto 都以不同的方式打破了这种孤岛化。Activity* 构建在 URL 之上,可以大致“社交化”Web 上的几乎任何内容,这很好,但它们不触及底层基础。通常的期望是,要么你运行自己的服务器(这并不适合所有人),要么你必须加入一个联邦服务器,这往往会让你受制于管理员(而且,正如有些人不幸发现的那样,并非所有管理员都很好)。ATProto 方面则为一个可扩展的、围绕用户代理 (https://berjon.com/user-agency/) 和可信退出 (https://subconscious.substack.com/p/credible-exit) 设计的 PDS 提供了良好的基础。这意味着你的在线存在可以由监护人托管(这样你就不必担心运行服务器),但如果你不喜欢你的托管方,你可以保证能够(可验证地)把你的内容带到别处,而且一切都不会改变,你甚至不需要更新你的句柄或设置重定向。
也就是说,它们解决不同的问题,并且解决方案是互补的。通过采取一些小步骤使这两个世界兼容,我们可以从两者中获得更多的价值。
似乎值得一试!
---
*本文是重新构想Web部分内容系列的一部分。你可以阅读该系列的其他文章:*
1. 构建下一代 Web (https://berjon.com/next-web/)
2. Web 为了用户代理 (https://berjon.com/user-agency/)
3. 你需要一个更大的浏览器 (https://berjon.com/bigger-browser/)
4. Web 磁贴 (https://berjon.com/web-tiles/)
5. ActivityPub 叠加 ATProto (https://berjon.com/ap-at/)
## 致谢
非常感谢以下出色的人们(按字母顺序排列)提供的宝贵反馈:Amy Guy, Benjamin Goering, Ben Harnett, Blaine Cook, Boris Mann, Brian Kardell, Brooklyn Zelenka, Dave Justice, Dietrich Ayala, Dominique Hazaël-Massieux, Fabrice Desré, Ian Preston, Juan Caballero, Kjetil Kjernsmo, Marcin Rataj, Margaux Vitre, Maria Farrell, and Tess O'Connor。不用说,本文中任何愚蠢和荒谬之处都完全是我自己的责任。
相似文章
ATProto中没有实例
解释为何来自Mastodon/ActivityPub的“实例”概念不适用于ATProto(Bluesky的协议),并阐明在ATProto架构中托管和聚合是分离的。
实现ActivityPub为何困难,又为何不必如此
本文解释了实现ActivityPub协议的复杂性,例如处理多种HTTP签名标准和JSON-LD上下文,并介绍了Fedify,这是一个旨在简化构建ActivityPub应用的TypeScript框架。
ATProto 许可数据提案草案
Bluesky 已发布 AT 协议上许可数据的提案草案,同时还有用户列表、审核、OAuth 等其他提案,作为其持续开发工作的一部分。
ActivityPub实现E2EE前的长尾工作
本文详细介绍了为ActivityPub实现端到端加密(E2EE)所需进行的剩余技术工作,将其分解为基本的消息传递、安全和真实性目标,并解释了密钥透明度和MLS协议如何融入这项工作。
Mandy:Goblins上的ActivityPub
Spritely Institute发布了Mandy,一个原型,它在Goblins演员模型框架之上实现了ActivityPub,使得ActivityPub参与者可以通过HTTP访问。