[控场AI]
· 9 分钟阅读· 4,832 字

用图数据库构建「公司大脑」:每条回答都能溯源

用图数据库构建「公司大脑」:每条回答都能溯源

Ratified 用图数据库把 IETF 邮件、草案与 RFC 串成可验证的引用链,拒绝模型生成答案。

Ratified 项目探索用 FalkorDB 图数据库构建可证明答案的「公司大脑」,以 IETF TLS 邮件列表为试验场。团队定下「没有链接就没有答案」的硬规则:答案来自确定性路由器挑选的手写 Cypher 查询,而非模型生成,遍历为空时明说「图不知道」。数据建模的关键难点是节号在草案修订间会漂移,因此邮件指向草案修订版而非 RFC,再按标题文本做 ALIGNS_SECTION 对齐。在 13 个自建问题上图方案 13/13,检索方案仅 1/10 确切命中,但作者承认在文本可见证据上差距缩小为 3/3 对 1/3。40 个留出问题首轮 30/40,并暴露出 404 链接、人物重复、计数误判等工程问题。

当规范里的一句话需要一个下午去追溯

2018 年 3 月,IETF TLS 邮件列表上有人讨论 draft-ietf-tls-tls13-24 的第 4.2.1 节。五个人,六封邮件,三天后讨论归于沉寂。这份草案最终成为 RFC 8446,而 4.2.1 节成了 TLS 1.3 通过 supported_versions 扩展而非版本字段声明版本的地方。

今天加入一个交付 TLS 1.3 的团队,你多半会问「为什么要这样设计」。答案就在那条邮件串里,但找到它需要一个记性好的人,或者一个下午。大多数公司把这类问题藏在私有聊天记录里——可搜索,却无法按「语义」搜索。Ratified 这个项目想验证的正是:图数据库能否把这条线索自动串起来,并且每一步都可查证。他们选了公开邮件列表作为试验场,因为那里可以被完整证明。

rss source: Why does the spec say that? Building a company brain on FalkorDB that proves every answer

规则先行:没有链接,就没有答案

在写任何代码之前,团队定下一条硬规则——不能被核查的「公司大脑」只是一个自信的猜测者。因此每个答案都必须以一个陌生人能打开的链接收尾。这条规则决定了大部分设计:

  • 答案来自图遍历,而不是模型的记忆;
  • 没有模型负责写 Cypher,一个确定性路由器为每个问题挑选一条手写查询;
  • 如果遍历返回空,卡片就明说**「图不知道」**。

这个思路与主流 RAG 方案形成鲜明对比:后者把检索到的文本块交给模型自由组织答案,而 Ratified 用结构化的图路径替代生成式推断,把可验证性放在首位。

RAG(Retrieval-Augmented Generation,检索增强生成)是当前主流的问答系统架构:它先用向量检索从文档库中找出与问题相关的文本块,再把这些文本块作为上下文交给大语言模型,由模型自由组织自然语言答案。这种方式的优势是灵活、覆盖面广,但代价是答案的可验证性弱——模型可能综合、改写甚至推断出文本中并不直接存在的结论,引用也常常是事后附会。Ratified 选择了一条相反的路径:检索的不是文本块,而是图上的结构化路径;输出不是模型生成的句子,而是预先写好的 Cypher 查询结果。这样每一条答案都能对应到一次确定的图遍历和一组可点击的源节点,牺牲了部分自然语言流畅度,换来了可审计性。

三步走通一条引用链

第一步:线索是一封邮件

一切从 Message 节点开始。团队从 TLS 列表抓取了 3,078 封邮件(其中 1,324 封含全文)、633 个线程和 403 位参与者,每封邮件都连向作者和线程。

第一个错误是假设邮件里的「Section 4.2.9」就是 RFC 的 4.2.9 节。事实并非如此——节号在草案之间会漂移。一封针对 draft -21 的邮件说「4.2.9」,指的是 -21 版本的 4.2.9,它最终变成了 RFC 的 4.2.10 节。所以邮件不能直接指向 RFC,它指向草案修订版,再由修订版指向具体章节。

第二步:路径穿过草案修订史

团队从 IETF datatracker 加载了 113 份草案及其 839 个修订版,用 SUPERSEDED 连成链,再接上它们最终演化成的 66 份 RFC。最耗时的部分是 ALIGNS_SECTION——把每个修订版的每一节映射到它变成的 RFC 章节。匹配依据是标题文本,因为节号会说谎,标题通常不会。这条边还记录了文本是否仍在变化(与最终发布版本相似度低于 98%)。

于是引用可以被解析:邮件 → 所指修订版 → 对齐的 RFC 章节。无法解析的引用会被丢弃,而不是猜测。整条路径由一条 Cypher 查询完成,最后一跳是可变长度遍历:

MATCH p=(dr)-[:SUPERSEDED*0..]->(last:DraftRevision)
MATCH (last)-[:BECAME]->(rfc:RFC)-[:HAS_SECTION]->(s)
RETURN [n IN nodes(p) | n.id] AS chain, rfc.id AS rfc, s.number AS number

对 §4.2.1 而言,它返回的链条是:邮件 → 线程 → draft -24 → -25 → -26 → -27 → -28 → RFC 8446 → §4.2.1。路径上每个节点都是指向邮件归档、datatracker 或 RFC Editor 的链接。

Cypher 是 Neo4j 提出的图查询语言,采用类似 ASCII 艺术的模式语法:(a)-[:REL]->(b) 表示节点 a 通过 REL 类型的有向边指向节点 b。MATCH 用于描述要匹配的图模式,RETURN 指定输出列,[n IN nodes(p) | n.id] 是列表推导式,用于把路径 p 上的所有节点映射为它们的 id。文中查询里的 [:SUPERSEDED*0..] 是可变长度路径语法,表示沿 SUPERSEDED 边遍历零步到任意步,*0.. 中的 0 使得即使邮件直接指向最终修订版也能匹配。FalkorDB 兼容 OpenCypher,并额外提供 algo.pageRank、algo.betweenness 等图算法过程,可在 Cypher 中直接调用。

第三步:只统计「当时在场」的人

第一版有个缺陷,直到读输出才发现:一个叫「RFC Errata System」的名字被列为在 §4.2.10 发布前「讨论」过它的人。实际上勘误报告虽然指名 draft -28,却是数年之后才提交的。

修复方法是在查询里加一条规则:一封邮件只有写于它所指向的修订版仍然现行的期间(早于下一修订版或 RFC 发布月)才算数。修正后,§4.2.1 给出干净的答案:6 封邮件,5 个人,2018 年 3 月,且写于该条款仍与最终版本不同的时期。团队同时停止使用「反对」这类措辞——边只表示某封邮件在条款变化期间引用了它,其中一些人正是草案编辑本人。卡片现在写的是「在仍变化时讨论过」,并在下方注明**「有连接,非因果」**。

找到对的人,以及几个容易踩的坑

拿到线程之后,下一个问题是「该问谁」。卡片列出线程里的五个人,加上现任主席和区域主管,并草拟一个附带来源的问题——但从不自动发送。

还有一个「谁懂什么」的排名。团队在数据摄入时用 Cypher 构建了 CO_DISCUSSED 投影(两个人在同一线程发言即连边),然后在其上运行 algo.pageRank 和 algo.betweenness。草案编辑在两个指标上都排第一,一位主席排第二。

这里有个陷阱:PageRank 跟随边的方向,而两个人之间的关系没有方向。如果每对只写一条边,排名会退化成字母序。投影边必须双向写入。

PageRank 最初用于网页排名,把节点视为页面、边视为超链接,一个节点的得分取决于指向它的节点数量与质量;Betweenness(介数中心性)衡量一个节点出现在其他节点对最短路径上的频率,常用来识别跨社区的信息枢纽。两者都默认边有方向。在「谁懂什么」的投影中,两个人同帖讨论是一种对称关系,如果只写一条单向边,PageRank 会把所有得分压向边的汇聚端,排序结果退化为近乎字母序。把每对关系写成两条方向相反的边,相当于让随机游走可以双向流动,指标才反映真实的讨论网络结构。

没人会输入「section 4.2.10」

真实用户问的是「为什么早期数据是这样工作的」。对章节标题建全文索引,可以把这句话解析到 §4.2.10 Early Data Indication,展示匹配到的词,并把次优结果作为一键备选。

这里有两个只有对着服务器测试才会学到的教训。空格分隔的词默认是 AND 关系,一句随口带了个多余词的问题会匹配不到任何东西,直到改成 OR。另外,索引章节正文反而让结果变差,因为宽泛的概览章节会压过精确标题——最终只索引标题。

每个答案都展示「解题过程」

每张卡片都有一个面板,列出 FalkorDB 实际执行的 Cypher、参数、行数以及数据库自报的 run_time_ms。以 §4.2.1 的问题为例,共 4 条查询,在笔记本上总耗时不到 1 毫秒。作者建议任何图产品都应该抄这个设计——它把「相信我」变成了「这是查询语句」。

反过来,问 IESG 投票或会议纪要这类从未摄入的内容,你会得到一张灰色卡片,写着「图不知道」。作者说,这是他们最信任的功能。这与生成式系统宁可胡编也要给出回答的倾向截然相反,也是「可证明」定位的落脚点。

它真的赢过普通检索吗?

团队写了 13 个问题,并用独立于主记录的解析器生成答案键。图方案答对 13/13。同样文本上的 BM25 加 bge-small 检索器确切命中 1/10,前十名内 3/10,还有三个计数问题根本无法打分。作者承认这个对比对自己有利,于是给出公平版:在证据确实存在于检索器可见文本的三个问题上,图 3/3、检索 1/3;而修订列表和计数这类问题的答案不在任何文本里,而在结构里——这构成使用图数据库的理由,但严格说并不算检索的失败。

路由器是在这 13 个问题上调过的,所以他们让另一个模型在未见过的前提下写了 40 个新问题。首轮未改动:30/40,其中 5 个路由自信地走错。评分器一开始报 34,逐行检查发现四个问题把「TLS 1.3」当成了第 1.3 节。修掉之后,这个集合就不再是留出集了。

其他被抓住的错误包括:渲染出的每条修订版链接都是 404,直到一个点击检查脚本发现;一个人以两个邮箱地址出现了两次;以及第一次基准测试把一道计数题判给了检索,只因为数字碰巧出现在某个文本块里。

BM25 是一种经典的稀疏检索打分函数,基于词频、逆文档频率和文档长度归一化,长期是全文检索的强基线;bge-small 则是 BGE 系列的小型稠密向量嵌入模型,把查询和文本块映射到同一向量空间后按余弦相似度排序。文中对比的检索器把两者结合,代表「普通检索」的典型配置。计数类问题(例如「有多少封邮件在条款变化期间引用了它」)对这类系统尤其困难,因为答案并不以现成句子出现在任何单个文本块中,而需要跨文档聚合,这正是图遍历的结构化优势所在。

边界与可复现性

图的边界很清晰:它能显示线程与被修改的条款之间存在连接,但不能证明前者导致后者。会议、GitHub issue 和 IESG 投票都在记录之外。RFC 8446 的 84 节中有 47 节能追溯到讨论,其余标记为部分回答。作者强调,他们只在一个工作组上验证了想法,尚未在公司私有聊天上验证。

想自己试的话,在线演示入口点击「Try an example」,再打开「Show how this was computed」;代码在 GitHub 的 ratified 仓库;本地运行只需 docker compose up --build,然后访问 127.0.0.1:8000,它会离线从已提交的记录重建图,不需要任何 API 密钥。团队也说明自己使用了 AI 编程助手,并在 AI_USE.md 中记录。

#FalkorDB#图数据库#公司大脑#Cypher#知识溯源#图遍历#可信 AI#RAG 替代方案
分享:

相关推荐