Skip to content
Published on

从文档到知识图谱 — 一条诚实的构建流水线

分享
Authors

引言 — 演示是一次调用,生产是一条流水线

「把文档喂进去,知识图谱就出来了。」演示里,这看起来就是一次 LLM 调用。往 LangChain 的 LLMGraphTransformer 或 LlamaIndex 的 PropertyGraphIndex 里塞几篇文档,就会得到一张画着节点和边的漂亮图。演示五分钟就能结束。

问题出在那之后。把客户的数万页文档变成一张 可查询的 图 — Forward Deployed Engineer 实际在做的事 — 不是一次调用,而是一条六段式的流水线。而成本与痛苦的大部分,不在人人都盯着的那一段(抽取),而在没人会在演示里展示的那一段(实体解析)。

本文诚实地沿着这条流水线走一遍 — 一直走到钱花在哪里、又在哪里崩掉。

文档
  │  (1) 模式 / 本体先行 — 定下节点·边的类型
分块 ──(2) 抽取──▶ 原始三元组   ← 调用数与分块数相当,可预估
  │        基于 LLM,模式约束
(3) 实体解析   ← 同一实体,无数写法 · 真正难的地方
  │   分桶 → 打分 → 聚类(规范化)
(4) 载入图存储   (+ 每条边都带出处)
  ├─(5) 增量更新 & 模式漂移  ← 一次做不完
  └─(6) 质量 / 评估   ← 精确率(对不对?) · 召回率(漏没漏?)

力气实际集中的地方 (大致的感觉):
  抽取          ~20%   (看得见、可预估)
  实体解析      ~50%   (长尾、手工活)
  评估 + 出处    ~30%   (没有它,等于部署一张不可信的图)

模式先行 — 没有本体,堆起来的只有噪声

从抽取开始的诱惑很大。但如果没定好要抽什么就去抽,得到的不是图,而是一堆噪声。同一个概念一会儿是 公司、一会儿是 企业、一会儿是 组织,关系的名字也随句子而变。这样的图画得出来,却查询不了。

所以第一步不是代码,而是决定 — 存在哪些节点类型和边类型。 这就是领域本体,而为什么要先做这件事,我在如何把领域知识做成本体里另作了讨论。这里重要的是:这个决定左右着整条流水线。下一步的抽取器会把这份模式当作约束来接收,模式里没有的东西就不抽。模式就成了图的语法。

抽取 — 传统 NER,还是 LLM

第二步,是真正从文本里把实体和关系抽出来。往长了看,有两条谱系。

传统方式 把命名实体识别(NER)和关系抽取(relation extraction)串成一条流水线。成熟、便宜、擅长大批量处理。代价也很清楚 — 每换一个领域都要新的带标注训练数据,实体识别阶段的错误会传播到关系抽取(流水线的老毛病),而且难以捕捉跨句子的上下文。

基于 LLM 的抽取 是另一侧的权衡。无需标注,从零样本/少样本起步,在保留上下文的同时把结果映射到模式上。代价是冒出两个新问题 — 幻觉(编造出不存在的关系)与 表述差异(同一样东西每次换个叫法)。前者让后面的第 4 步更难,后者让第 3 步更难。

看三个实务工具,权衡就摸得着了。

  • LangChain LLMGraphTransformer convert_to_graph_documents 把文档变成节点和关系。用 allowed_nodesallowed_relationships 约束类型(两者的默认值都是空列表 = 全部允许),而 allowed_relationships 甚至接受 (起点类型, 关系, 终点类型) 这样的三元组。它还是个 experimental 模块,视模型不同,有时会返回空结果。
  • LlamaIndex 的抽取器。 同一件事提供三条路径。SimpleLLMPathExtractor 不带模式自由抽取,"may produce a larger number of diverse relationships",但 "might lack consistency in entity and relation naming"。SchemaLLMPathExtractor 用预先定义的模式,"produces a more structured graph",但 "might miss a lot of relationships that don't fit the predefined schema"。DynamicLLMPathExtractor 介于两者之间 — 接受初始模式的引导,但必要时会扩展,追求 "a balance between diversity and consistency"。可以说,权衡已经被做成类名钉在那里了。
  • Microsoft GraphRAG。 对每个文本单元抽取实体和关系,给每个都附上描述,然后把同一实体的多条描述合并成 "coherent, non-redundant descriptions"。

成本可以预估。抽取本质上就是 每个分块一次 LLM 调用。文档越多,成本线性增长,可以批量跑,缓存也管用。这是流水线里最好对付的一段。难的地方另有其处。

实体解析 — 真正难的地方

抽取一结束,就会冒出几十万条三元组,其中相当一部分是 指向同一事物的不同名字张伟Zhang WeiZhang, W. 可能是同一个人,也可能不是。整理这件事就是实体解析(entity resolution),也是知识图谱构建中质量分野的地方。

标准做法分三步。

  1. 分桶(blocking)。 缩小候选范围。两两比较所有实体,成本会以 n² 爆炸(10 万个实体就是 100 亿对比较),所以要用基于嵌入的近似最近邻搜索之类的办法,把「好歹有点像的」先归到同一个桶里。正如现场的格言所说,分桶比匹配更重要 — 在这里漏掉的那些对,后面再也碰不到面。
  2. 打分(scoring)。 给桶内的每一对打上相似度 — 字符串相似度、关系上的邻近性、嵌入、行为信号等等。
  3. 聚类/规范化(canonicalization)。 依据分数把属于同一实体的归到一起,再把每一簇做成一个规范节点。

失败模式在两个方向上对称。

  • 过度合并(over-merge)。 把两个不同的 张伟 合并成一个节点。于是图开始 说谎 — 一个人的履历里混进了两个人的事实。它悄无声息,所以危险。
  • 合并不足(under-merge)。IBM CorpInternational Business MachinesIBM Corporation 留成三个节点。查询只命中三者之一,漏掉剩下的三分之二。

嵌入在这里帮上大忙。稠密向量即便字符串毫无重叠,也能凭语义把它们连起来 — 上面 IBM 的三种写法,可以 "without a single explicit rule" 就合成一个。但光靠嵌入还不够。无论是基于规则,还是纯粹的 LLM,在网络规模上单打独斗都撑不住。实战是分桶 + 相似度匹配 + 概率/ML 分类 + 全局一致性校验的组合。

这里有一点必须诚实说清。很多工具并不替你做这一步。 比如 GraphRAG 的默认流水线,只是把 名字完全相同的 提及合并、再把描述做个摘要,它并不会把 IBM CorpIBM Corporation 连起来。真正的实体解析是你自己的活儿。FDE 在客户项目里花时间最多的地方,正是这里。

载入图存储 — 并给每一条边都带上出处

解析完的三元组,这就进入图存储。若是属性图(Neo4j 等),就给节点·边挂上属性;若是 RDF,就放进三元组存储,用 SPARQL 查询。怎么选,由团队的工具生态和查询模式来定。

载入时绝对不能漏掉的,正是 溯源(provenance)。每一条边都得一并带上「它出自哪份文档、哪个分块」。GraphRAG 之所以保留文档元数据、把每份文档与由它生成的文本单元关联起来,也正是为此。带出处的图可以审计、可以引用、出错时知道该去哪里修。没有出处的图,不过是一堆听着有理的主张。而这份出处,到后面会成为图 RAG给回答附上依据的材料。

增量更新与模式漂移 — 一次做不完

客户的文档不会停在原地。新合同进来,组织架构变动,产品增加。图也得跟着变。

全量重建简单,但昂贵。所以需要增量更新。GraphRAG 1.0 的 update 命令会 "computes the deltas between an existing index and newly added content and intelligently merges the updates to minimize re-indexing" — 也就是尽量只反映新增内容。不过有一条诚实的脚注。一旦新内容动摇了社区结构本身,就得重算相当大的一部分,最坏的情况会接近全量重新索引。稍可宽慰的是,LLM 缓存能大幅降低重跑的成本。

更隐蔽的问题是 模式漂移。第 1 步冻结下来的本体,时间一长就与现实脱节。新的实体类型和关系冒出来,而受模式约束的抽取器会悄悄把它们放过。所以模式不是立起来就忘掉的东西,而是一份需要治理的、活着的资产。构建不是一次性事件,而是持续运营。

质量与证据 — 评估不了,就别部署

「图看着不错」不是评估。构建出来的知识图谱,可以在三元组的层面上度量,也应该去度量。

基本的维度有四个 — 准确性(accuracy)、完整性(completeness)、一致性(consistency)、冗余(redundancy)。实务中最先量的是前两个。用精确率(precision)量准确性 — 抽出来的三元组里正确的比例 — 再 用召回率(recall)量完整性 — 本该存在的三元组里被抽到的比例。用手工做一份黄金样本、逐条边比对,是最诚实的起点;也有像基于链接预测的指标那样、不需要黄金样本就能自动衡量质量的办法。

而在评估与信任的交汇处,溯源 又一次出现。给每个值都附上出处跨度(attribution),就能滤掉幻觉 — 拿不出依据的三元组,存疑即可 — 同时也让最终用户能够验证答案。评估流水线和溯源不是事后加上的装饰,而是让图变得可信的唯一途径。

诚实的成本 — 在哪里崩掉

归纳一下,成本是这样分布的。

  • 抽取 与分块数量成线性。看得见,能做预算,缓存也管用。是最容易的一段。
  • 实体解析 是一条长尾。80% 能自动化,但剩下的 20% 需要领域知识和手工操作,而质量的大部分就在这里被决定。
  • 社区摘要(GraphRAG 类)在规模变大时,会和抽取一样贵,有时更贵。因为它要为每一个社区都生成一份 LLM 报告。
  • 增量更新 不是免费的,最坏的情况会退化成全量重建。

演示展示的,只有第一行。剩下的都不在演示里,于是从报价里漏掉,于是项目延期。

结语

用 FDE 的视角看,把文档变成图,大约 20% 是抽取,80% 是解析·评估·溯源·运营。执行(抽取)正在变便宜 — LLM 替你做了 — 价值留下来的地方是判断。决定什么算作节点的模式,判定同一即同一的解析规则,能证明「错了」的评估。这些,都是今天的模型不会替你决定的维度。

要用一句话留下的,就是这句。模式先行,证据永随。 图不是目的,而是手段;这手段是为了什么 — 检索与回答 — 会在图 RAG一篇里接着讲,而真正驱动这条流水线的工具,则在知识图谱的工具地形一篇里继续。

参考资料