第31回 构建知识图谱——抽取、消歧与 LLM 辅助
三元一点如星火,聚作人间万里灯。
灯若无油难久照,先把杂质炼精纯。
上回我们学会了“图谱怎么走路”:三元组做路标,BFS 找最短路。
可江湖里真正难的,不是走路——是把路修出来。
现实文档像菜市场:
- 同一个人叫“张三”“张三同学”“三哥”
- 同一个公司写作“OpenAI”“Open AI”“OpenAI, Inc.”
- 同一个关系更乱:是“就读于”还是“毕业于”?是“位于”还是“总部在”?
你若把这些一股脑抽成三元组,图谱立刻变成一团乱麻:
点太多、边太乱、同名不同物、同物不同名。
这一回我们讲“修路三步”:
- 抽取(Extract):从文本里捞出候选三元组
- 定义(Define):把关系与类型收束成一个能用的“简明谱系”(schema)
- 归一(Canonicalize):把同物不同名、同义不同写统一起来
这条三步法在近年的 LLM 驱动构图工作中被明确提出为 EDC 框架:Extract–Define–Canonicalize。1
一、抽取:从“句子”到“三元组”
抽取最常见的两件事:
- 实体识别(NER):句子里哪些词是“人名/地名/机构名/产品名”
- 关系抽取(RE):这些实体之间是什么关系
在传统时代,你要:
- 标注数据
- 训练模型
- 还要维护规则与特征
LLM 时代多了一条路:
把抽取变成“按格式回答”的任务,让模型直接吐出三元组。
但它也带来新坑:吐得像样,不代表稳定;抽得全,不代表不胡。
所以抽取只是第一步,别急着把三元组写进“正式卷宗”。
二、定义:schema 是“法条”,没有法条就没有一致性
schema 说白了就是两张表:
- 实体类型:人、组织、地点、产品……
- 关系类型:就读于、位于、控股、合作……
没有 schema 会怎样?
- 同一句“清华在北京”,有人写(清华,位于,北京),有人写(清华,所在地,北京)
- 关系名字越长越碎,最后重排与推理都用不了
EDC 的思路是:
先让模型抽一批“开放式关系”,再把它们归并成更少、更通用的关系集合(schema definition),再统一命名与对齐(canonicalization)。1
这一步在工程里非常像“立法”:
你要把事实写成可重复使用的条款。
三、归一:同名异物与同物异名,是图谱的“内伤”
归一常见三类:
- 别名归一:OpenAI / Open AI / OpenAI, Inc. → OpenAI
- 同义关系归一:所在地 / 位于 / 坐落在 → 位于
- 实体消歧:同叫“苹果”,到底是水果还是公司
归一的目的不是“字面统一”,而是“让图可推理”。
否则你从张三走到中国要绕十个“别名节点”,路径解释也成笑话。
这正是 LLM+KG 综述里反复强调的痛点之一:LLM 能加速构图,但一致性、可控性与评估仍是核心挑战。23
四、极简可跑代码:抽取只是“候选”,归一才入库
下面代码做三件事:
- 用最朴素的规则模拟“抽取候选三元组”(这里只是演示,不追求准确)
- 用一张“同义表”做关系归一
- 用一张“别名表”做实体归一
import re
TEXTS = [
"张三就读于清华大学。",
"清华位于北京。",
"清华大学坐落在北京市海淀区。",
"Open AI, Inc. 与 OpenAI 合作。",
]
ALIAS = {
"清华大学": "清华",
"北京市": "北京",
"Open AI, Inc.": "OpenAI",
}
REL_CANON = {
"位于": "位于",
"坐落在": "位于",
"合作": "合作",
"就读于": "就读于",
}
def canon_entity(x):
return ALIAS.get(x, x)
def canon_rel(r):
return REL_CANON.get(r, r)
def extract_candidates(text):
patterns = [
(r"(.+?)就读于(.+?)。", "就读于"),
(r"(.+?)位于(.+?)。", "位于"),
(r"(.+?)坐落在(.+?)。", "坐落在"),
(r"(.+?)与(.+?)合作。", "合作"),
]
out = []
for pat, rel in patterns:
m = re.match(pat, text)
if m:
h = m.group(1).strip()
t = m.group(2).strip()
out.append((h, rel, t))
return out
if __name__ == "__main__":
triples = []
for s in TEXTS:
triples.extend(extract_candidates(s))
print("raw:", triples)
canon = []
for h, r, t in triples:
canon.append((canon_entity(h), canon_rel(r), canon_entity(t)))
print("canon:", canon)
你会看到:
- “清华大学”“清华”被归一成一个点
- “坐落在”被归一成“位于”
真实系统当然不会只靠规则表,
但你要记住这个底层逻辑:
抽取是“候选事实”,归一才是“入库事实”。
五、LLM 在构图里扮演什么角色:不是替代工程,而是缩短冷启动
把 LLM 放进构图流水线,最常见的三种位置:
- 抽取器:按格式吐候选三元组
- schema 助手:建议关系集合、解释关系含义
- 归一助手:做别名聚类、关系对齐、冲突解释
但你要防两种幻觉:
- 抽取幻觉:文本里没写的事实,模型补上了
- 归一幻觉:两个不同实体被强行合并
所以 EDC 这类方法强调“后处理与可控”——
让 schema 与归一有清晰的步骤与约束,而不是一把梭哈。1
六、小结:修路的人,先把法条写清
这一回你学到一句硬道理:
- 图谱好不好,不看抽取多花哨,看 schema 与归一多扎实
下一回(第32回)我们把图谱与 RAG 合起来:GraphRAG。
你会看到:
当图谱修得好,检索就不只“找相似段落”,还能“沿关系网找证据链”。
欲知后事如何,且听下回分解。
幻觉核查
- EDC 三阶段框架(Extract–Define–Canonicalize)与动机:可核对原论文标题、摘要与阶段定义。1
- “LLM 驱动构图的挑战与评估”这类归纳:可核对相关综述对范式分类与挑战条目的总结。23
- 本回代码仅用于教学演示“候选→归一→入库”的思路,不代表可用的工业抽取器或消歧系统。
逻辑审计
- 与第30回衔接:第30回解决“图上怎么推理”,第31回解决“图怎么建”。没有一致的点与边,推理路径就不可信。
- 与导读一致:导读主线是“慢思考与可核查”,构图的 schema/归一正是“把事实变成可查证据”的前置工程。
- 为第32回铺路:GraphRAG 的前提是图谱质量;本回把“修路”讲清,下一回才能讲“沿路取证”。
引用与溯源
Footnotes
-
Zhang, B., Soh, H. Extract, Define, Canonicalize: An LLM-based Framework for Knowledge Graph Construction arXiv:2404.03868 (v2: 2024-10-02) https://arxiv.org/abs/2404.03868 ↩ ↩2 ↩3 ↩4
-
Bian, H. LLM-empowered knowledge graph construction: A survey arXiv:2510.20345 (2025-10) https://arxiv.org/abs/2510.20345 ↩ ↩2
-
Ibrahim, N., et al. A survey on augmenting knowledge graphs (KGs) with large language models (LLMs): models, evaluation metrics, benchmarks, and challenges (Discover Artificial Intelligence, 2024) https://link.springer.com/article/10.1007/s44163-024-00175-8 ↩ ↩2