- 引言 — 演示是一次调用,生产是一条流水线
- 模式先行 — 没有本体,堆起来的只有噪声
- 抽取 — 传统 NER,还是 LLM
- 实体解析 — 真正难的地方
- 载入图存储 — 并给每一条边都带上出处
- 增量更新与模式漂移 — 一次做不完
- 质量与证据 — 评估不了,就别部署
- 诚实的成本 — 在哪里崩掉
- 结语
- 参考资料
引言 — 演示是一次调用,生产是一条流水线
「把文档喂进去,知识图谱就出来了。」演示里,这看起来就是一次 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_nodes和allowed_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 Wei、Zhang, W. 可能是同一个人,也可能不是。整理这件事就是实体解析(entity resolution),也是知识图谱构建中质量分野的地方。
标准做法分三步。
- 分桶(blocking)。 缩小候选范围。两两比较所有实体,成本会以 n² 爆炸(10 万个实体就是 100 亿对比较),所以要用基于嵌入的近似最近邻搜索之类的办法,把「好歹有点像的」先归到同一个桶里。正如现场的格言所说,分桶比匹配更重要 — 在这里漏掉的那些对,后面再也碰不到面。
- 打分(scoring)。 给桶内的每一对打上相似度 — 字符串相似度、关系上的邻近性、嵌入、行为信号等等。
- 聚类/规范化(canonicalization)。 依据分数把属于同一实体的归到一起,再把每一簇做成一个规范节点。
失败模式在两个方向上对称。
- 过度合并(over-merge)。 把两个不同的
张伟合并成一个节点。于是图开始 说谎 — 一个人的履历里混进了两个人的事实。它悄无声息,所以危险。 - 合并不足(under-merge)。 把
IBM Corp、International Business Machines、IBM Corporation留成三个节点。查询只命中三者之一,漏掉剩下的三分之二。
嵌入在这里帮上大忙。稠密向量即便字符串毫无重叠,也能凭语义把它们连起来 — 上面 IBM 的三种写法,可以 "without a single explicit rule" 就合成一个。但光靠嵌入还不够。无论是基于规则,还是纯粹的 LLM,在网络规模上单打独斗都撑不住。实战是分桶 + 相似度匹配 + 概率/ML 分类 + 全局一致性校验的组合。
这里有一点必须诚实说清。很多工具并不替你做这一步。 比如 GraphRAG 的默认流水线,只是把 名字完全相同的 提及合并、再把描述做个摘要,它并不会把 IBM Corp 和 IBM 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一篇里接着讲,而真正驱动这条流水线的工具,则在知识图谱的工具地形一篇里继续。
参考资料
- LlamaIndex — Property Graph Index 介绍
- LlamaIndex — LLM Path Extractor 对比 (Simple / Schema / Dynamic)
- Tomaz Bratanic — Building Knowledge Graphs with LLM Graph Transformer
- Neo4j — Creating Knowledge Graphs from Unstructured Data
- Microsoft GraphRAG — Indexing 方法论
- Microsoft GraphRAG — Indexing Pipeline 概念
- Edge et al. — From Local to Global: A Graph RAG Approach (arXiv)
- Microsoft Research — Moving to GraphRAG 1.0 (增量更新)
- Modern Data 101 — Entity Resolution at Scale
- Scientific Reports — 反映用户需求的知识图谱评估
현재 단락 (1/66)
「把文档喂进去,知识图谱就出来了。」演示里,这看起来就是一次 LLM 调用。往 LangChain 的 `LLMGraphTransformer` 或 LlamaIndex 的 `PropertyGr...