NextGraph:打造 P2P 与 E2EE 的社区应用
根据 2026 年 9 月 30 日的演讲与问答整理,保留发言顺序、例子、限定条件和交流承接,校订口头重复、断句与明显识别错误。产品状态和后续计划以分享时点为准。时间对应交付视频。

阅读目录
- NextGraph 项目介绍
- 为什么通过 broker 同步
- 不绑定特定 CRDT 的协议
- 密码学能力与访问控制
- 去中心化身份与持久标识符
- RDF、关联数据与 SPARQL
- 可塑软件与数据可迁移性
- 静态加密与 SDK
- TypeScript ORM 与响应式前端
- ShEx 模式与类型安全
- 历史记录、权限与响应式查询
- ELFA 与本地优先生态
- Store 与权限边界
- 加密数据块与提交
- 并发提交与 DAG
- 通过发布订阅分享密钥
- 补齐缺失提交与 broker 联邦
- Merkle 树与分块
- 问答:像一个加密的 Git?
- 问答:规模与基准测试
- 问答:OrbitDB、快照与协调
- 问答:编程智能体与 AI 访问本地数据
- 拉取控制与后量子密码学计划
- ACID 属性与计划中的 Paxos 协调层
- 文档结构:图、discrete 与文件

NextGraph 项目介绍
00:00:00 · Niko Bonnieure
大家好,谢谢你们邀请我。不知道大家能不能看到我的共享屏幕?可以,有人确认看到了,那我可以翻页了。我是 Niko,正在做 NextGraph,项目得到了屏幕上这些欧洲资助机构、欧盟委员会的支持。我想先介绍一下 NextGraph,再深入讲大家最感兴趣的部分。想听哪些内容,可以告诉我。


00:00:44 · Niko Bonnieure
首先,我们有一个数据同步协议。它采用端到端加密,也就是说,接收数据的服务器看不到数据内容。它也是本地优先的,没有互联网也能工作,并且基于 CRDT。我想大家都知道 CRDT 是什么。

为什么通过 broker 同步
00:01:17 · Niko Bonnieure
它并不是纯粹的点对点系统,严格来说并不是那种 P2P。题目里写了 P2P,很抱歉让大家失望了,但这样做有充分的理由。纯粹的点对点意味着设备直接互相连接,比如在浏览器里使用 WebRTC。
00:01:41 · Niko Bonnieure
这意味着同步不经过服务器中转。当你和别人分享内容时,对方的设备必须和你的设备同时开机、同时在线,才能同步,而这一点并不总能保证。所以,你想和别人分享时,更希望先把端到端加密的数据发到服务器,然后自己就可以离线了。
00:02:16 · Niko Bonnieure
等对方上线后,再通过服务器同步。我们把这些服务器叫作 broker。图中的蓝色圆圈就是 broker,它们互相通信,组成 broker 联邦,彼此只交换经过端到端加密的数据块。

00:02:48 · Niko Bonnieure
下方绿色的用户设备可以访问数据,加密和解密都在设备上进行。我们还会说,设备负责将状态物化,也就是 materialize the state。这是 CRDT 里的概念:解密之后,把 CRDT 更新聚合起来,逐条应用,在本地重建文档。
00:03:21 · Niko Bonnieure
这张图展示了网络部署之后的样子。NextGraph 目前还没有用于生产环境。这些黑点是 broker,设备连接 broker,而不是设备之间直接连接。这是我想先说明的。


不绑定特定 CRDT 的协议
00:03:45 · Niko Bonnieure
这个协议可以同步各种 CRDT,不绑定某一种 CRDT。不同的 CRDT 都可以通过它传输和同步。目前我们支持 Yjs、Automerge,以及我们为 RDF 开发的一种专用 CRDT。RDF 是一种数据描述格式,Solid 项目也在使用。我想另一位分享者很快会在这个系列活动里介绍 Solid。

00:04:23 · Niko Bonnieure
我们也支持 RDF,后面会再展开。我们计划接入 Loro 已经有两年了。我知道它来自中国,也认识开发者,这是个很棒的项目,不过我们还没有把它接进来。增加新的 CRDT 应该比较容易,因为协议只做传输 CRDT 所必需的最少工作,后面会解释。基本上,就是保留更新之间的因果顺序,也就是偏序关系。
00:05:09 · Niko Bonnieure
所以,除了 Loro,还可以接入更多 CRDT。我们现在就在增加一种电子表格专用的 CRDT,用到了 NextGraph 协议的这种灵活性。Automerge、Yjs 和 Loro 这三种通用 CRDT 处理的是类似 JSON 的结构化数据,也能存储富文本、Markdown 和纯文本,尤其是 Yjs。

00:05:43 · Niko Bonnieure
NextGraph 协议还可以同步不可变数据,比如二进制文件。我们使用内容寻址:同一个文件上传两次,不会存两份,因为我们会对内容计算哈希,知道这个文件已经有了。它是一个基于文档的系统,同时也面向数据库,把两者结合在了一起。
00:06:14 · Niko Bonnieure
你有一份份文档,所有文档里存储的数据合在一起,就构成了数据库。文档本身也可以组合,类似 Notion 或其他以内容块为基础的系统。关于 CRDT,幻灯片上的网站有更多资料。协议里另一个重要部分是密码学,以及基于密码学的访问控制机制,所以我们把它叫作密码学能力,也就是 cryptographic capabilities。


密码学能力与访问控制
00:07:02 · Niko Bonnieure
后面我会详细讲。如果没有解密密钥,你收到的就只是一团无法使用的加密数据。这就是读取能力:想读,就要有这个密钥。写入能力更多依靠非对称密码学。你需要证明自己是编辑者,这通过签名完成。两者相互配合:读取依靠对称加密,看你是否持有能够解密的对称密钥;其他部分则依靠签名。这是总体思路。

去中心化身份与持久标识符
00:07:48 · Niko Bonnieure
因为整体是去中心化的,这个协议没有单点故障。例如,我们去掉了对域名的依赖。服务器和设备通过 IP 地址以及标识它们的公钥来识别彼此。文档和用户身份都有唯一的去中心化标识,我们使用的是 W3C 的 DID 标准。
00:08:23 · Niko Bonnieure
外面有很多种 DID method,也就是 DID 方法。我们的方法叫 ng,代表 NextGraph。用它可以引用数据库中的任何文档或任何用户。ng 后面跟着标识符,是很长的一串字符,其中有公钥,URI 里还编码了数据位置等信息。

RDF、关联数据与 SPARQL
00:08:57 · Niko Bonnieure
接下来讲讲 RDF,这是我很喜欢的一种数据格式。除了 JSON,我们也提供 RDF,作为补充。它也与关联数据、语义网这些概念有关。基本上,它把数据以三元组的形式存进图里,是一种图数据库。

00:09:30 · Niko Bonnieure
三元组是能够保存的最小数据单元,有点像键值存储中的键值对,也可以看作一个属性。它还能表示对象之间的关系。你可以用 SPARQL 查询它,这和 SQL 类似。图上是一个很简化的例子:这里有一些对象,可以用 RDF 表达对象的属性,也可以表达它们之间的关系。

00:10:08 · Niko Bonnieure
右下角有一个叫 James 的人,他的出生日期属性是 1984 年 1 月 1 日,这是 James 的一个属性。Paris 的类型是“地点”,这是 Paris 的一个属性。对象之间还有关系,例如“访问过”“画过”或“感兴趣”。
00:10:39 · Niko Bonnieure
这样就可以把这些点连接起来。关系有类型、有标签,甚至还可以给关系附加属性,这就是 RDF 能做的事情。我很喜欢把自己的所有数据组织成一张图,再连接、引用其他人的数据。这样,散布在互联网上的许多数据库就能够互操作。

可塑软件与数据可迁移性
00:11:10 · Niko Bonnieure
它还支持可塑软件,也就是 malleable software:你可以更换用来编辑、查看数据的软件,把数据存储和应用分开。如果我不喜欢某个软件,可以换一个,数据仍然保留。保留在哪里?在本地,因为在 NextGraph 和本地优先软件里,数据始终保存在本地。RDF 还能提供自动关联。

00:11:44 · Niko Bonnieure
不像 SQL,你不需要考虑外键。数据有全局标识符,就是前面讲的 did:ng URI。它们全局唯一,也能长期保持:即使数据移动,标识符也不会改变。数据从一个 broker 搬到另一个 broker,ID 仍然不变。这不同于我们习惯的 Web 2.0:URL 依赖域名,数据一移动、域名一变,URL 就失效,还要做重定向。我们去掉了这些问题。


静态加密与 SDK
00:12:30 · Niko Bonnieure
前面说过,它是一个数据库。我还提到了 Tim Berners-Lee,他发明了万维网,也是关联数据概念的提出者。到这里,我们看到了一个不绑定特定 CRDT 的同步协议,以及一个图数据库。除了端到端加密,还有静态加密,也就是 encryption at rest。数据到达本地后,我们解密、物化状态,写进本地数据库,而这个本地数据库本身也是加密存储的。


00:13:06 · Niko Bonnieure
这样,即使设备被盗或被非法访问,数据仍然受到用户打开应用时所用密码的保护。我看一下时间,看看有没有问题。接下来可以讲讲 SDK。我们在协议之上提供 SDK,供大家开发应用,尽量把内部机制隐藏起来,让你专注于自己的应用,不用操心里面怎么工作。

00:13:50 · Niko Bonnieure
你可以开发 Web 应用,也可以开发原生应用,因为我们使用 Tauri。NextGraph 用 Rust 编写,前端部分使用 TypeScript,可以编译到常见的平台。我们还为 Node.js 和 Python 提供 SDK,用来开发服务、AI 等。幻灯片上就是我提到的五个平台,以及目前支持的语言。



00:14:25 · Niko Bonnieure
SDK 有两个层次的 API。用底层 API,你可以订阅文档或者创建文档。订阅意味着数据会持续保持最新状态。网络中某处、某个标签页发生更新时,你在浏览器里的本地数据也会更新。它始终基于 Web 技术,实际上连原生应用也是 WebView。通过订阅,各类数据都能保持更新。
TypeScript ORM 与响应式前端
00:15:04 · Niko Bonnieure
无论文档背后用的是哪种 CRDT,你都可以订阅并收到更新。我们还提供了更高层的 ORM API,把数据映射成 TypeScript 对象。对象可以带 schema,也可以不带,取决于具体情况。你可以把数据直接绑定到 Vue、Svelte 或 React 等前端框架。最近我们还加入了 SolidJS,注意不要和前面提到的 Solid 项目混淆。

00:15:39 · Niko Bonnieure
有了 TypeScript ORM,你就不用操心 CRDT 了。下面的例子里,Yjs 是我前面提到的 CRDT 库。直接使用它,订阅或修改数据需要了解 Yjs 的用法;在这里,你写的只是普通 TypeScript:object.key = value。修改数据后,会立即生成一个端到端加密的更新。如果在线,就通过网络发出去,其他人收到更新。这样就能获得前端响应性,也能实时协作文档。你改一个属性,本地引擎就把它作为 CRDT 操作持久化;在线时同步,不在线就保留到下次联网。



00:16:48 · Niko Bonnieure
其他副本的本地引擎收到这些变化后,本地对象会更新,随后 React、Svelte 或 Vue.js 前端也会更新。这里展示了使用两个主要 API 的前端代码:useDiscrete 和 useShape。useDiscrete 用于基于 Yjs、Automerge 的文档;如果将来接入 Loro,也可以用于 Loro。useShape 用于 RDF,需要传入一个 shape,后面会解释。不管数据来自哪一种文档,使用方式最终都一样,都是响应式的。这里是一个 React hook,把它接到前端和模板上即可。刚才提到的 schema,可以为 TypeScript 提供类型和类型安全。


ShEx 模式与类型安全
00:17:56 · Niko Bonnieure
这目前只适用于 RDF 文档,因为其他文档是 JSON,我们还不支持它们的 schema。我们使用 ShEx 格式描述 schema,就是常见的模式定义:有哪些属性、子属性、各自是什么类型,也可以有嵌套对象。大家可以在我们的 Git 仓库中找到这个费用追踪应用的例子。它可以运行,并且持续更新和测试;想上手的话,可以从这里开始。



历史记录、权限与响应式查询
00:18:44 · Niko Bonnieure
在 SDK 之上,我们还在开发一个框架。如果不同应用需要一些共通功能,我们就通过更高层的 API 提供出来,例如文档历史。你可以回到过去,查看以前的版本,也有审计轨迹,因为所有内容都有签名。

00:19:15 · Niko Bonnieure
每个提交都由作者签名,这份变更历史防篡改、不可变。准确地说,它并不是线性日志,而是 DAG,也就是有向无环图。还有权限机制:你可能不想重新做一套修改文档权限的界面,我们可以按需提供。前面提到的 SPARQL 则提供了本地查询引擎。

00:19:50 · Niko Bonnieure
响应式查询还在开发中,不过进展不错。你发起一个 SPARQL 查询,并保留它的句柄,让查询持续存在。首先会收到初始结果;如果你还在显示这些结果、或者在视图中使用它们时,底层数据发生了变化,就会通过回调收到更新后的结果。
00:20:24 · Niko Bonnieure
例如,一条记录被编辑或者删除,你会自动看到变化,这就是响应式查询。评论、聊天、通知也是框架支持的实用功能。文档共享和数据保存是基础,上面还可以提供这些额外 API。


00:20:58 · Niko Bonnieure
钱包非常重要,主密钥保存在里面。钱包始终放在本地,服务器永远看不到它。还有应用商店和网盘。我们也计划做去中心化、注重隐私的社交网络,使用端到端加密。如果有时间,后面可以讲讲 ACID 事务和智能合约。概括一下,这是一个由 broker 组成的开放平台。


ELFA 与本地优先生态
00:21:31 · Niko Bonnieure
它是开源的,可以自行托管:部署在云上、租来的 VPS 上,或者自己的机器上都可以。它包含协议、SDK、框架,以及应用生态。我想提一下 ELFA。这些一般特性先跳过,之后会把 PDF 给大家。ELFA 是一套应用,我们四个月前开始做。它是一个完整的工作空间,有点像是在尝试与 Google Workspace 竞争,提供你需要的各种应用:文档、电子表格、电子邮件、日历、联系人等。




00:22:14 · Niko Bonnieure
它基于 NextGraph,所以具备端到端加密和本地优先的特性。预计一两年后准备好,近期会有一个 alpha 版本。这里是和我一起参与这个项目的合作伙伴。

00:22:30 · Niko Bonnieure
最近,我还和屏幕上这些伙伴组建了一个更大的联盟,名单甚至有第二页。这是一个新的合作,包括 ELFA、NextGraph 和这些伙伴。他们并不全都使用 NextGraph,但会相互协作。大家将一起把本地优先带给普通用户,带进操作系统、移动操作系统和更多应用,推广到更广泛的开源生态里。


00:23:10 · Niko Bonnieure
接下来可以更深入地讲加密、权限这些内容。我先停一下,看看大家有没有问题,以及希望我展开哪一部分。

00:23:30 · 主持人
也许可以讲讲密码学?
00:23:32 · Niko Bonnieure
好,密码学。我找不到聊天窗口。你们看到里面有问题吗?我没看到它在哪里,这里有聊天窗口吗?
00:23:55 · 主持人
有,不过我想目前还没有问题。
Store 与权限边界
00:23:59 · Niko Bonnieure
好的,看到问题就告诉我,可以随时打断。接下来讲能力和权限系统。所有数据都会组织进 store,文档按 store 分组,你可以把它理解为一个容器。store 有几种类型。private store,也就是私有存储区,数据只在你自己的设备之间同步,不在不同用户之间同步。
00:24:34 · Niko Bonnieure
你可以在里面保存秘密,其中的文档不能分享给别人。在 protected space,也就是受保护空间里,则可以通过不同权限和别人分享文档。还有 public store,即公共存储区,其中的数据任何人都能读,只要把链接给他们即可。这里不检查读取权限,但仍会检查写入权限。基本上,只有你自己能写,除非你把写入权限委托给别人。
00:25:07 · Niko Bonnieure
这是三种 store。此外,还有 group store,也就是群组存储区。你创建一个群组,邀请其他人加入,成员可以在群组里编辑和创建文档。所有这些 store 都有文档层级,可以放文件夹、子文件夹,按自己的方式组织文档。前面也说过,我们还对传输中的数据加密。
00:25:40 · Niko Bonnieure
我们有三种不同层面的加密。设备之间、broker 之间的所有通信都使用 Noise Protocol。
00:25:52 · Niko Bonnieure
权限的粒度是在文档层面,不过也不完全是。写入权限按文档设置,你可以指定谁能编辑这份文档。读取权限则更细,可以细到我们所说的 branch。你可以把文档中的数据分成不同分支,让某些部分可读,而另一些部分隐藏起来。
00:26:25 · Niko Bonnieure
写入权限不细分到这个程度,它仍在文档层面。权限有继承关系:文档继承所在 store 的权限,但你也可以不沿用继承结果,单独修改某份文档的权限。下面进入协议内部加密的技术细节。我觉得这部分有必要讲清楚,先从第二张幻灯片开始。


加密数据块与提交
00:27:01 · Niko Bonnieure
这一部分讲的是我们如何做端到端加密,以及它怎样与 CRDT 结合。我认为,把两者结合起来时,这一点非常重要。每次更新都是一个原子单元,我们把更新放进一个数据块,并单独加密,因为更新随时可能发生。
00:27:33 · Niko Bonnieure
比如,你打开一个文本文档,修改了三个字符,这次编辑就会作为一个数据块被加密。加密的只是这次变化,也就是补丁、CRDT 更新。我们采用对称加密,所以会有一个密钥。看左上角,我们把包含更新的这个块叫作 commit,也就是提交。每个提交都有 ID 和密钥。
00:28:06 · Niko Bonnieure
这里的密钥是对称密钥,ID 是加密后数据块的哈希。如果我把提交 ID 和密钥给某个人,他就可以获取这次更新。
00:28:25 · Niko Bonnieure
我们需要把 ID 和密钥传给想要分享更新的其他节点、其他副本,也就是订阅这份文档的人。有了 ID,他们就能向 broker 请求数据块。broker 保存着所有这些端到端加密的数据块,你给它 ID,它就返回相应的密文数据。
00:28:59 · Niko Bonnieure
有了密钥,就能解密。当然,密钥不会存放在服务器上。先从文档的第一个提交开始,我们叫它根提交;如果借用区块链的说法,也可以叫创世提交,不过这里说的只是文档。第一个提交里有一些元数据,然后图中的第二个数据提交包含第一次更新。
00:29:31 · Niko Bonnieure
第二个提交包含第一次更新,并通过提交 ID 引用第一个提交。这个标着数字 1 的黄色部分就是引用,表示父提交的 ID,有点像 Git。注意,这里还没有提交密钥。之后再增加提交时,也是沿着这个方式继续。
并发提交与 DAG
00:30:07 · Niko Bonnieure
第三列里,提交 3 和提交 4 是并发的。它们可能由不同用户创建,也可能是同一个用户的两个副本、两个标签页创建的,但当时没有联网。所以它们并发发生,并且都指向同一段过去,也就是提交 2。生成的这两个提交,都以提交 2 为父提交。
00:30:44 · Niko Bonnieure
等它们上线后,就会把这些提交发给 broker。其他订阅者收到两个提交,就能看出它们是并发的。数据本身没有问题,因为基于 CRDT,并发更新可以由 CRDT 处理好。不过,这里我们主要讨论加密这一层。
00:31:11 · Niko Bonnieure
两个提交会被解包、解密,并在本地物化,这样就可以工作了。此时我们停留在这个状态,图中后面标注的 merge 还没有发生。数据已经收到,本地文档也已经更新。之后又发生了一次提交,也就是提交 5。某种意义上,它把前面两个提交合并起来,指向提交 3 和提交 4,正如最后一列所示。
00:31:48 · Niko Bonnieure
假设提交 5 是这份文档当前最新的提交,那么我需要分享的就是它的 ID 和密钥。红色框里画的就是提交 5 的 ID,以及提交 5 的密钥。
通过发布订阅分享密钥
00:32:17 · Niko Bonnieure
我确认一下大家有没有跟上。好的。那么,怎样分享这些信息,又不把它们直接交给服务器呢?我们先加密,再通过 pub/sub,也就是发布订阅机制发送。其他副本收到的仍然是密文。
00:32:48 · Niko Bonnieure
这里用的是另一个密钥,暂时不展开。副本之所以能够解密,是因为它们属于这份文档的发布订阅范围,是经过授权的读者。只有这些副本能解开红色框中的信息。解开后,就知道“现在到了提交 5”,于是向 broker 请求对应的数据块,再用密钥解密。
00:33:19 · Niko Bonnieure
如果你已经订阅,我们会直接把数据块推送给你,不需要另行请求。如果晚一些才订阅,就需要获取缺失的提交,但这些工作由协议和库自动完成,不用你手动处理。还有一个协调差异的机制,因为你可能已经有文档的一部分,只缺少其中某些提交。
补齐缺失提交与 broker 联邦
00:33:56 · Niko Bonnieure
你只需要和自己的 broker 通信,不必联系其他副本。前面说过,这不是设备直接相连的 P2P。作为一个副本,你告诉 broker:“我有这些块。”broker 会说:“你还缺两三个块。”然后把缺失的块发过来。这也解释了为什么图中黄色的部分,也就是数据块 ID,没有加密。
00:34:32 · Niko Bonnieure
我们能看到这些 ID,broker 也能看到。承载这些信息的头部是明文,幻灯片右上角也注明了。这让 broker 能看到 DAG 的形状,也就是所有提交组成的图。它可以提前重建这个结构,等某个副本来请求“只给我缺失的最新提交”时,就知道该发哪些。
00:35:12 · Niko Bonnieure
broker 之间也会同步,因为这是一个联邦系统。我可以把数据放在一个 broker 上,另一个人放在另一个 broker 上,仍然可以协作同一份文档。即使我们的设备离线,这些 broker 也会继续交换数据。这样,当我上线时,需要同步的数据就已经到了我的 broker 上。
00:35:49 · Niko Bonnieure
这样就会更快。broker 已经准备好了我缺失的最新提交,连接后只需要接收这些,而且会按正确的偏序顺序收到。这个顺序可以从 DAG 看出来,知道什么发生在先,也有助于后续处理 CRDT。我认为,这是对本地优先数据进行加密的正确方式。
Merkle 树与分块
00:36:24 · Niko Bonnieure
也有其他库采用相同方式。回到前一张幻灯片,这里展示了我们如何具体处理包含数据的数据块、块 ID 和对称密钥。数据块内部有 Merkle 树。如果一次更新很大,超过一兆字节,就会拆成块,有点像 BitTorrent。

00:36:55 · Niko Bonnieure
这张幻灯片讲的就是这些,以及前面提到的对称加密和哈希。技术部分先讲到这里,如果有问题可以现在问,然后我再往下讲。这部分清楚吗?

00:37:29 · Niko Bonnieure
抱歉,我没有听清你的问题或评论。
00:37:34 · 主持人
他在聊天里留了一个问题。
00:37:37 · Niko Bonnieure
聊天窗口在哪里?我看不到。
问答:像一个加密的 Git?
00:37:43 · 主持人
他在问,这个结构是不是像一个加密的 Git?
00:37:54 · Niko Bonnieure
是的,是类似的。主要区别是,Git 里不能有两个以上的父提交。合并两个分支时,一个提交可以有两个父提交。这里则可以有三个、四个或五个。如果三台设备在断网时并发编辑,就会有三个父提交。这是与 Git 类比时的区别。
问答:规模与基准测试
00:38:37 · 观众
你好,Niko,谢谢你的分享。我有两个问题。第一个是关于 NextGraph 的容量:你估计目前这个系统可以支持多少用户、多少设备进行实时的端到端加密协作?
00:39:02 · Niko Bonnieure
我们还没有这方面的基准测试,抱歉让你失望了。我预计参与人数较少时应该能运行得不错,但不知道规模扩大后会怎样。CRDT 部分取决于所用 CRDT 库的性能;网络本身还没有做基准测试,不过我们应该开始做了。
问答:OrbitDB、快照与协调
00:39:40 · 观众
第二个问题是,和 OrbitDB、Delta 这样的其他开源项目相比,你们的路线有什么不同?
00:39:58 · Niko Bonnieure
能再说一下项目名字吗?我没听清你提到的是哪几个。
00:40:05 · 观众
OrbitDB。
00:40:07 · Niko Bonnieure
OrbitDB,好的,我知道这个项目。另一个呢?
00:40:11 · 观众
Delta。
00:40:12 · Niko Bonnieure
Delta,我不确定自己是否了解。OrbitDB 是一个基于日志的数据库、键值存储,需要操作日志。上一次我试用它是很久以前,当时需要重放整个日志才能访问数据。我不知道现在是否还是这样。我在 NextGraph 里尝试解决这个问题,把数据库真正保存在本地,就不用每次都重放一切。
00:40:58 · Niko Bonnieure
每次启动应用或者访问文档,都有一个可以直接访问的本地数据库。例如,RDF 部分使用 Oxigraph。它有静态加密,但查询仍然很快,因为数据就在本地,不需要重放全部历史。对于 CRDT,每次重放、重新物化状态的开销很大,我们想避免这部分成本。
00:41:31 · Niko Bonnieure
主要问题出现在新加入的人身上。你把某人加进一份他从没见过的文档,而文档已经用了整整一年,可能有一万个提交、一万次更新。要重放全部历史,首先得把它们都取回来。broker 可以帮忙,一次发送所有数据,但接收方仍需逐个解密提交。刚才也看到了,这是一个链式的 DAG,要从最新提交开始,往历史回溯。
00:42:04 · Niko Bonnieure
这在加密层面就很慢,之后 CRDT 重新物化全部状态也需要时间。要改善这一点,可以做快照:压缩历史、墓碑标记和不再有用的内容,生成一个可以一次载入的文档,不必重放所有操作。这个快照也只需要加密一次。
00:42:41 · Niko Bonnieure
这就是快照,NextGraph 里已经有了。需要注意的是,做快照时需要与其他参与方进行一点协调。协议会负责,你不需要手动操作,但这一点并不是本地优先的:至少需要自己的 broker 配合,所以必须在线。broker 可以处理这件事,不过要生成这样的快照,你得先连接 broker。
00:43:13 · Niko Bonnieure
还有一些人在尝试不需要协调的快照,比如 Ink & Switch 那些做 Automerge、Keyhive 的人。这些都是取舍。他们做了很好的工作,但我还没有把这些成果整合进 NextGraph。我们的快照仍然需要协调,因为它不是一件每天都要做的事。
00:43:45 · Niko Bonnieure
我们并不会永远离线工作,总要同步。这里说的是间歇性的断网。如果你一个月都不联网,那就没有和别人协作,只是在本地放着一个文件。在这种情况下,你只在本地编辑,从不上线,我们实际上会在本地做快照,已经把内容压缩起来了,因为知道你没有联网,不存在这方面的风险。所以我认为,这是可以接受的取舍。
00:44:29 · 观众
这样也更简单。
问答:编程智能体与 AI 访问本地数据
00:44:31 · 观众
我还很好奇,像 Claude Code、Codex 这样的智能体编程工具,现在有很多功能需要改进或加入。根据你的经验,这些工具对开发效率有什么帮助?
00:44:55 · Niko Bonnieure
你是在说智能体,也就是 AI,对吧?
00:44:58 · 观众
是的。
00:45:01 · Niko Bonnieure
首先,在 NextGraph 和我自己的工作中,我其实不怎么用 AI。有一些和我合作的开发者会用它写代码,但用得很少。如果你想问的是,怎样把 AI 接到这些数据、数据库或者 NextGraph 上,也许你更想问这一点?
00:45:26 · 观众
两方面都可以理解,我都感兴趣。
00:45:29 · Niko Bonnieure
你原来想问哪一方面?
00:45:33 · 观众
我是想问,你们计划加入什么样的 AI 功能?
00:45:39 · Niko Bonnieure
我们没有这方面的计划,不过去年已经有人这么做了。他们使用我们的 API,把它接到了 AI 上。
00:45:54 · Niko Bonnieure
我们有一个演示,可以发给你。我觉得效果不错,原因在于 SPARQL 这个查询语言。顺便说一下,我们用的是中国的 Qwen 模型,它很强,也懂 SPARQL。只要在上下文中放入如何访问数据的说明,大模型就能用 SPARQL 查询你的本地数据。
00:46:29 · Niko Bonnieure
演示里做了一个联系人管理器,存储联系人资料、电话号码等。我们问:“Niko 或另一位联系人的电话号码是多少?”它就能查出来。
00:46:48 · Niko Bonnieure
它使用 SPARQL,甚至没有用 MCP,也不需要 MCP。因为这些 API 在 Python 和 Node.js 里都可以调用,所以从大模型发起查询很方便。
00:47:06 · Niko Bonnieure
当然,这在一定程度上打破了端到端加密的边界,因为大模型运行在服务器上,需要访问它要读取的文档和数据库。你得授予它访问权限,它才能查询。如果自行托管 Qwen 3,隐私会好一些;如果把数据交给 OpenAI,数据就可能外泄。
00:47:35 · 观众
不错。
00:47:36 · Niko Bonnieure
NextGraph 那边有一个代码仓库,名字大概是 LLM router。你可以联系我,我可以带你看一下。
00:47:47 · 观众
谢谢。
00:47:50 · Niko Bonnieure
谢谢,还有其他问题吗?
00:48:02 · 主持人
你还有问题吗?
00:48:07 · Niko Bonnieure
什么?
00:48:13 · 主持人
看来没有其他问题了,那你可以继续。
00:48:19 · Niko Bonnieure
我可以回到幻灯片。后面还有很多页,我之前不知道会花多少时间。这里有同步协议,以及提过的分支。如果没有大家特别想了解的内容,我们也可以很快收尾。这些前面讲过了,发布订阅也稍微提到了一点。之后我会把幻灯片给大家,你们可以慢慢看,到我们的论坛上提问。顺便说,论坛用的也是 Zulip。




00:48:55 · Niko Bonnieure
前面说过,读取能力基于对称加密,写入能力基于非对称加密。
拉取控制与后量子密码学计划
00:49:06 · Niko Bonnieure
DID 前面讲过了。overlay 这里不深入展开,它用于拉取控制,也就是 pull control。我们甚至希望阻止未授权的人拿到加密数据。并不是像前面简化解释的那样,只拿着一个数据块 ID 或提交 ID,就能直接向 broker 索取数据;没有这样的公开 API。你必须属于一个 overlay,这一层同样有加密和安全机制。只有获得了这个 overlay 的访问权限,才能联系 broker,请求特定 ID 对应的数据块或提交。

00:49:51 · Niko Bonnieure
因为我们不知道加密数据将来会怎样,也许有一天会有人能够解开。我们已经有后量子密码学的计划,准备明年加入,也为此获得了更多资助。目前协议中的密码机制基于椭圆曲线,还不能抵抗量子计算,之后会支持。

ACID 属性与计划中的 Paxos 协调层
00:50:24 · Niko Bonnieure
前面还讲了所有数据上的签名、不可变的审计轨迹,以及数据真实性。接下来是 finality,也就是最终确定性,这和我想讲的 ACID 提交、数据库有关。在本地优先模式下,修改数据不需要协调,我在离线时也可以修改。

00:50:57 · Niko Bonnieure
这打破了我们习惯的数据库 ACID 属性。例如 PostgreSQL 这样的数据库部署在服务器上,我连接后执行一个事务,事务里可能包含多项修改。提交时,要么所有数据全部更新,要么完全不更新,没有中间状态。这对资金管理或者电商非常重要。
00:51:31 · Niko Bonnieure
比如一笔订单,你不希望把同一件东西卖两次,也不希望把同一笔钱花两次。CRDT 和本地优先本身解决不了这个问题。你可以在这里改数据、在那里也改数据,不需要协调,也不需要互联网。但等到合并、协调这些变化时,CRDT 并不关心你是不是把东西卖了两次,或者把钱花了两次。
00:52:02 · Niko Bonnieure
这是两个相互独立的问题,不能靠 CRDT 来解决。所以,我们想把 ACID 属性作为附加能力带回 NextGraph。大多数时候,你只需要 CRDT 和本地优先;但有些时候,你希望数据库具备原子性、一致性等 ACID 属性。
00:52:24 · Niko Bonnieure
这部分我们还没有做出来,已有设计,但尚未编写代码。我们会通过 broker 中介进行协调,同时仍然采用端到端加密。broker 不知道你在做什么,但会帮助协调。它基于 Paxos 这个协调算法。在此基础上,就可以做智能合约等需要的功能。


文档结构:图、discrete 与文件
00:52:57 · Niko Bonnieure
这里展示文档的结构。文档有一个 ID,叫 NURI,意思是 NextGraph URI,它是 did:ng 形式的 DID。文档内部可以有 graph,也就是 RDF 部分。这里是一个 RDF 例子,graph 下的每一行都是一个三元组,由主语、谓语和宾语组成。感兴趣的话可以多了解 RDF,我很喜欢它。
00:53:27 · Niko Bonnieure
在场的另一位分享者也很喜欢,接下来几天大家可以问他。你什么时候分享?明天吗?
00:53:37 · 观众
周五。
00:53:38 · Niko Bonnieure
周五,好的。也欢迎大家来听他的分享,会很有意思,还可以在那里问 RDF 的问题。discrete 是文档的另一部分,或者说文档中的那些分支,你可以在里面放 Yjs 数据,比如 Markdown、富文本,也可以放 JSON 数据。

00:54:09 · Niko Bonnieure
graph 和 discrete 这两部分可以同时存在于同一份文档里,这一点很重要。还可以附加二进制文件,文件上传到 broker 后可供访问,你会得到一个指向二进制数据的 URI,可以把这个链接存到图里或者 JSON 里。

00:54:37 · Niko Bonnieure
如果做社交网络,可以有用户资料、社交数据、私信和聊天。基于 NextGraph 构建社交网络是可行的。我们到这里就讲完了,屏幕上是我的联系方式,也可以到网站上找到我。谢谢大家。

00:55:09 · Niko Bonnieure
谢谢大家一起度过这段时间。希望你们基于 NextGraph 做出很多应用。需要帮助的话就告诉我。如果想进一步了解本地优先、加密或者相关概念,我也一直很愿意回答问题。