首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Neo4j知识图谱:Graph RAG让大模型理解实体关系

Neo4j知识图谱:Graph RAG让大模型理解实体关系

作者头像
陆业聪
发布2026-07-20 20:53:51
发布2026-07-20 20:53:51
210
举报

📰 科技要闻

• iOS 27 首个公开测试版已放出,几项系统级交互改动值得关注,果链开发者可以提前踩坑了。

• 荣耀与阿里宣布将开展 AI 智能体终端合作,小米机器人同期宣布首次实现汽车工厂柔性工件的长时作业——终端 Agent 化和机器人自动化都在加速落地。

• Nothing 新款 Watch 3 Pro 智能手表定价仅 69 美元,颜值和硬件规格对同价位是个降维打击。

上一篇讲混合检索的时候,我留了个坑没填:三路召回里的"知识图谱检索"这一路,当时只画了个占位框,说下一篇专门讲。这一篇终于要来填坑了——但填坑之前,我得先坦白一件事:我们团队最早是不信知识图谱的。

理由很简单,向量检索 + 关键词检索已经能覆盖 90% 的场景,图谱这套东西听起来又重又贵,构建成本高、维护成本更高,团队里有个资深同事直接甩过来一句话:"这不就是十年前语义网那套东西的新皮肤吗?"我当时也没法反驳,直到我们真的撞上了一类查询,向量和关键词双双失灵,才彻底改了看法。

那类查询是这样的:"A 项目依赖的哪个组件,被 B 团队负责,且这个组件在最近一次事故报告里被提到过?"这句话里藏了三层关系跳转:项目→依赖组件、组件→负责团队、组件→事故报告。向量检索能找到"和这句话语义相近"的文档片段,但它压根不知道"依赖""负责""提到"这几个词背后是结构化的实体关系,它只是在算余弦相似度。关键词检索更没辙,因为用户问题里根本没出现具体的组件名或团队名。这种多跳关系推理的查询,两路召回都是盲区,这才是知识图谱真正该出场的地方。

向量检索的盲区:多跳推理与结构化查询

先把问题说透,向量检索的本质是"相似度匹配",它擅长回答"哪些文档在说和这句话类似的事情",但完全不擅长回答"A 和 B 之间是什么关系",更别提"顺着这条关系链走两步、三步之后是什么"。

举个更直观的例子。假设知识库里有一份文档提到"张三是订单服务的负责人",另一份文档提到"订单服务在 2026 年 3 月因为超时问题重构过"。用户问"张三负责的服务出过什么问题",向量检索会分别召回这两份文档,因为它们各自都和 query 有一定语义相关性,但检索结果是两个孤立的片段,模型拿到这两段上下文之后,还得靠自己的推理能力把"张三→订单服务→重构过"这条链路拼起来。文档一多,这种隐式拼接就会翻车——大模型看到的是几十个片段的大杂烩,它未必能精确抓出"张三"和"订单服务"之间那条唯一正确的关联。

知识图谱把这种关系显式化了。实体和实体之间的关系不再靠大模型"猜",而是提前抽取好、存成结构化的边,查询的时候直接顺着边走,这是确定性的图遍历,不是概率性的语义匹配。这也是为什么图谱检索特别适合处理那些"关系链路型"问题——组织架构、依赖拓扑、因果链条,这些天生就是图结构,而不是一堆孤立的文本片段。

一句话总结:向量检索管"语义相近",关键词检索管"字面精确",知识图谱管"关系确定"——三者不是替代关系,是互补的三条腿,缺一条都会有系统性的查询盲区。

知识图谱构建:从非结构化文档到实体关系

知识图谱构建的传统做法是人工标注 + 规则抽取,成本高到没法接受。现在用大模型做实体关系抽取,成本直接砍了一个量级,但坑也不少,我们踩过的最深的一个坑是:一开始直接让模型"随意抽取实体和关系",结果同一个实体在不同文档里被抽成了五六种不同的名字——"订单服务""order-service""订单微服务""Order Service"全都指向同一个东西,图谱里凭空多出了五个孤立节点,查询的时候压根连不上。

抽取 Schema 要先定死,不能让模型自由发挥

吃了那个亏之后,我们的做法改成了先定义实体类型和关系类型的 Schema,再让大模型在这个约束下抽取,而不是完全自由发挥。比如我们的技术文档知识库,实体类型只允许是:服务、团队、人员、事故、组件、依赖库这几种;关系类型只允许是:负责、依赖、导致、修复、隶属于。抽取 prompt 大概是这样:

代码语言:javascript
复制
ENTITY_TYPES = [
"服务", "团队",
"人员", "事故",
"组件", "依赖库"
]
RELATION_TYPES = [
"负责", "依赖",
"导致", "修复",
"隶属于"
]# prompt 核心约束
EXTRACT_PROMPT = f"""
从下面的文本中抽取实体和关系,
严格遵守:
1. 实体类型必须是
{ENTITY_TYPES} 之一
2. 关系类型必须是
{RELATION_TYPES} 之一
3. 实体名称使用文中的
规范全称,不要用简写、
缩写或别名
4. 输出 JSON 格式:
{{"entities": [...],
"relations": [...]}}文本:
{{chunk_text}}
"""

Schema 定死之后,抽取质量立竿见影地提升,但"实体名称使用规范全称"这条约束在 prompt 里管不住模型 100% 遵守,光靠 prompt 约束是不够的,还得配一道后处理的实体归一化。

实体归一化:别让同义实体变成图里的孤岛

实体归一化我们用了个简单但有效的两阶段方案:第一阶段是规则匹配,维护一份别名词典(比如从 CMDB 里同步服务的标准名和别名列表),命中直接映射;第二阶段是对规则没覆盖到的实体,用 embedding 计算相似度,超过阈值的候选再丢给大模型做二次确认"这两个是不是同一个实体",而不是直接自动合并——自动合并的风险是把两个真正不同但名字相近的实体错误地捏成一个,这个错误一旦进了图谱,后面所有基于这个节点的查询都会跟着错,比检索不到还麻烦。

代码语言:javascript
复制
def resolve_entity(
name: str,
alias_dict: dict,
existing_entities: list
) -> str:
# 第一阶段:别名词典直接命中
if name in alias_dict:
return alias_dict[name]# 第二阶段:embedding找相似候选
candidates = find_similar(
name, existing_entities,
threshold=0.85
)
if not candidates:
return name  # 新实体# 相似但不完全确定,让LLM确认
for cand in candidates:
if llm_confirm_same_entity(
name, cand
):
return cand
return name

Neo4j Cypher 查询语言快速上手

图数据库我们选了 Neo4j,理由很务实:Cypher 查询语言的可读性在图数据库里数一数二,社区生态成熟,APOC 插件补全了不少工程化场景需要的函数,单机版对我们这种知识库规模(几十万节点、百万级边)也完全够用,没必要一上来就上分布式图数据库。

Cypher 最核心的设计理念是用"图形化的语法"描述图形化的查询,节点用括号 () 表示,关系用箭头 -[]->/ 表示,写出来的查询语句长得跟你画的关系图几乎一模一样。上面那个"张三负责的服务出过什么问题"的查询,写成 Cypher 是这样的:

代码语言:javascript
复制
MATCH (p:人员 {name: "张三"})
-[:负责]->(s:服务)
MATCH (s)<-[:导致]-(i:事故)
RETURN s.name AS 服务,
i.name AS 事故,
i.date AS 日期
ORDER BY i.date DESC

这条查询的意思一目了然:先找到"张三"这个人员节点,沿着"负责"关系走到他负责的服务节点,再反向找出哪些事故节点通过"导致"关系指向这个服务。跟传统 SQL 比一比就知道差距——同样的多跳关联查询,用关系型数据库要写好几层 JOIN,表结构设计还得提前想好每一层关联的外键,而且 JOIN 层数一多性能就会明显下降;Cypher 直接顺着关系走,语义清晰,性能也更稳定,因为图数据库的存储结构天生就是为"遍历关系"优化的,不需要像关系型数据库那样在查询时动态计算笛卡尔积再过滤。

性能优化:索引和查询深度控制是两条命

图数据库不代表天生高性能,用不好照样能把它跑成瓶颈。我们踩过的最典型的坑是忘了给节点属性建索引,导致每次按名称查找起始节点都是全表扫描,节点数一上到十万级,查询延迟直接从毫秒级掉到秒级。

代码语言:javascript
复制
CREATE INDEX entity_name_idx
FOR (n:服务) ON (n.name);
CREATE INDEX entity_name_idx2
FOR (n:人员) ON (n.name);

另一条命是查询深度。图遍历最怕的就是没有边界的多跳查询,比如写一个不限跳数的 -[*]-,在稠密图里这种查询的时间复杂度是指数级增长的,节点稍微多一点就能把数据库拖死。我们的规矩是所有变长跳数查询必须显式限定最大跳数,一般不超过 3 跳:

代码语言:javascript
复制
-- 危险:不限跳数,稠密图必炸
MATCH (a)-[*]-(b)
RETURN a, b-- 安全:显式限定1到3跳
MATCH (a)-[*1..3]-(b)
WHERE a.name = "订单服务"
RETURN a, b

3 跳这个数字不是随便定的,我们做过实测:多跳推理场景下,超过 3 跳的关联结果,业务相关性会急速衰减,用户几乎不会需要"朋友的朋友的朋友的同事负责的服务"这种查询,跳数越深,噪声越大,与其追求"图能查多远",不如把边界卡死,保证近距离关联的查询质量和响应速度。

Graph RAG 架构:图谱先行,向量补充

回到系列的主线:图谱这一路怎么跟向量、关键词两路配合。上一篇的三路并行召回架构里,图谱是并行的第三路,但实践下来我们发现,对于"关系链路型"的问题,并行召回其实不是最优解,串行的"图谱先行,向量补充"效果更好。

用户 Query

是否含实体+关系意图?

✅ 是 → 图谱检索先行 抽取query里的实体, Cypher查询相关子图

补充 → 用子图涉及的实体名 做向量检索,补充非结构化 细节描述

❌ 否 → 直接走上一篇的 向量+关键词混合检索

合并上下文送入LLM

这个架构里最关键的一步是"是否含实体+关系意图"的判断,我们用一个轻量的意图分类器(其实就是一个几十个 few-shot 样例的小 prompt)先判断 query 是不是关系推理型的问题,是的话才启动图谱检索,不是的话就直接走向量+关键词那套老路,没必要每次查询都触发图遍历——图谱检索的开销比向量检索要高不少,尤其是涉及多跳的时候,不该走图谱的查询硬塞进去只会拖慢整体响应。

"图谱先行,向量补充"这一步的补充逻辑也值得说一下:图谱查出来的子图只有结构化的实体和关系名,没有细节描述,比如查到"张三负责订单服务"这条边,图里只有这三个字段,具体张三是怎么负责的、订单服务这次事故的详细排查过程是什么,这些细节还是躺在原始文档里的。所以图谱检索之后,我们会拿子图里涉及的实体名再去做一次向量检索,把相关的文档片段捞回来,跟图谱结构一起送给大模型——图谱给"骨架",向量给"血肉",这个组合比单纯图谱或单纯向量都更完整。

Microsoft GraphRAG:社区摘要与全局查询

聊完我们自己的实现,得提一下微软 2024 年发的 GraphRAG 论文,因为它解决的是一个我们上面那套方案完全没碰的问题:全局性的归纳型查询。

"张三负责的服务出过什么问题"这种查询是局部的,答案就藏在几个明确的实体和关系里,图遍历几步就能找到。但换一个问题:"这个项目整体的技术风险分布是什么样的?"这种问题没有明确的起点实体,答案需要综合整个知识图谱的全局信息才能回答,局部图遍历完全无从下手,因为你压根不知道该从哪个节点开始查。

GraphRAG 的解法是提前对图谱做社区检测(community detection),把关联紧密的实体聚成一个个"社区",再让大模型给每个社区生成一份摘要,相当于给整个知识图谱建了一层"分层缓存"。全局查询的时候,不用遍历原始图,直接在社区摘要这一层做检索和归纳,社区数量比原始节点数量少得多,归纳成本可控。它把图谱查询拆成了两层:

查询类型

典型问题

解决方式

局部查询

张三负责的服务出过什么问题

从起点实体做图遍历

全局查询

项目整体技术风险分布如何

检索社区摘要层,归纳汇总

我们试着在自己的知识库上做了个小范围的社区检测实验,用的是 Neo4j 的图数据科学插件 GDS 里的 Louvain 算法,效果确实惊艳,服务、团队、组件这些实体天然按业务线聚成了清晰的社区簇,一个社区基本对应一条业务线。但摘要生成的成本比我们预期的高不少——每个社区都要单独调一次大模型生成摘要,社区数量一多,这笔 token 开销就上去了,而且知识图谱一旦发生增量更新,受影响的社区摘要理论上都要重新生成,这就引出了下一个问题:维护成本。

知识图谱的维护成本:增量更新怎么做

这是我认为知识图谱这条技术路线最容易被低估的一块成本。向量索引的增量更新很简单,新文档来了,切块、embedding、插入索引,互不干扰。知识图谱不一样,一份新文档进来,抽取出来的实体可能和图里已有的实体产生关联,也可能触发实体归一化的重新判断,甚至可能让某个社区的边界发生变化——图谱是"活"的,牵一发动全身。

我们最后落地的增量更新策略是分层处理,不同层级的更新代价差异很大,不能一视同仁:

新文档进来

↓ 抽取实体关系

Layer1 → 节点/边直接写入 图数据库,实时生效,成本低

Layer2 → 实体归一化异步批处理, 定时任务而非实时触发

Layer3 → 社区摘要仅对受影响 社区增量重算,每周批量跑一次

节点和边的写入是实时的,因为成本低,新文档抽取完直接落库;实体归一化改成异步批处理,因为它涉及跨全图的相似度比对,没必要每来一份新文档就跑一遍全量归一化;社区摘要更是直接降级成每周批量重算一次,而且只重算受影响的社区,不是每次都全量重跑——这一步的判断依据是"实用主义":全局查询本身对实时性的要求就不如局部查询高,用户问"整体风险分布",摘要延迟一周更新,绝大多数场景是可以接受的。

说实话,如果一开始就知道维护成本这么高,我们可能会更谨慎地评估"到底哪些查询场景真的需要图谱",而不是一上来就想着把知识图谱做成"全能选手"。现在我们的原则很明确:只在关系链路型查询这个明确的场景里用图谱,不追求用图谱去覆盖所有检索需求,向量和关键词依然是主力,图谱是精准打击那一小块两者都够不到的盲区。

这一篇填完了三路召回的最后一路,混合检索 + Reranker + 图谱补充的架构基本闭环了。但架构闭环不代表质量闭环——检索出来的东西到底对不对、好不好,光靠主观感觉判断是不靠谱的,得有一套量化的评估体系撑着。下一篇打算聊 RAG 评估这件事,从社区常用的 Ragas 框架讲到我们自己搭的量化评估 Pipeline,毕竟这一路优化下来最大的教训就是:没有评估指标兜底的检索优化,都是在盲人摸象。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陆业聪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档