首页 > 教程攻略 > ai资讯 >RAG进阶:混合稠密检索和知识图谱来提升精度

RAG进阶:混合稠密检索和知识图谱来提升精度

来源:互联网 时间:2026-08-23 13:57:11

HuixiangDou 这个项目,定位是群聊场景下的 LLM 知识助手。群聊里人多口杂,机器人显然不能每条消息都回复,它的设计哲学就三条:

RAG进阶:混合稠密检索和知识图谱来提升精度

  • 无关内容不吭声

    ——直接拒答
  • 明确该答的,直接回复

    ——启动检索
  • 不能违反核心价值观

    ——确保可靠

在上篇文章里,我们用真实的群聊数据做了一轮测试,对比了多种方法和参数调优,最终把拒答的 F1 score 干到了 75.88。

今天这篇,要聊的是如何把知识图谱和稠密检索混着用,让 F1 进一步攀升到 77.57。

先把目前测试过的所有方法做个对比:

方法

F1 score

备注

BCE+KG混合(本文)

77.57

KG 权重约 20%
BCE75.88需配合特定 splitter
BGE72.23使用 bge-large-zh-v1.5
BGE-M370.62测试数据 token 不足 8192,无法评估能力
M3 稠密+稀疏混合63.85使用 milvus hybrid_search 测试,WeightedRanker 中稀疏占比越大效果越差

本文方法的本质,其实就是在稠密检索的过程中,给那些高频词汇加个权重。这么做有几个好处:

  1. 简单

    。核心实现只有几百行代码,而且完美兼容旧版本。具体的 Pull Request 可以参考 这里
  2. 可靠

    。反复测试下来,只要参数设置合理,精度提升是稳定的。
  3. 成本可控

    。不需要依赖多轮 LLM 调用就能提升精度,本文只做 2 轮 LLM 的 NER 来提取知识库里的实体词。

1. 术语介绍

考虑到读者的背景可能不太一样,先把文里涉及的关键词捋一遍:

  • 知识图谱(Knowledge Graph)

    :一种结构化的知识库,用图的形式把实体、属性、关系及类型都组织起来。
  • 命名实体识别(Named Entity Recognition)

    :从自然语言里提取有意义的实体,比如人名、昵称、时间等等。
  • 稠密检索(Dense Retrieval)

    :属于非结构化方法。先靠模型把文本、图像、语音的特征提取出来,再算算特征之间的距离来找匹配目标。人脸识别里用的就是这招。
  • networkx

    :一个 Python 写的开源图论和复杂网络分析库,能让你方便地创建和操作各种图结构。
  • neo4j

    :成熟的图形数据库管理系统,很适合用节点和边来保存知识图谱。
  • milvus

    :开源向量数据库,专门设计来存储、搜索和分析海量向量数据。

2. 方案阐述

RAG 为什么需要 KG?或者更直接点,KG 能给 HuixiangDou 带来什么?

理想状态下,KG 应该能带来三样东西:

  1. 提升系统的可解释性

    。稠密检索的那个高维空间,说实话,调试起来基本靠猜。
  2. 保证术语间的层级关系

    。比如在杂交水稻这个领域,无论你用稠密还是稀疏方法,都很难清晰地表达“野败”和“南优2”之间的亲本关系。
  3. 无侵入性

    。KG 的加入,不能明显干扰现有的服务流程和精度表现。

本文用的 KG,是以属性为中心来连接 chunk 的。

举个具体的例子,拿 MMDeploy 和 MMPose 这两个项目的 README 来说,它们的交集会落在 “mmpose” 和 “ncnn” 这类术语上。如果一个名词(比如 “ncnn”)能关联到大量文档,那说明它要么很重要,要么很常见。本文的核心假设就是:这类高频词汇,在 RAG 中理应获得更大的权重。

2.1 建立知识库

这里用了 qwen1.5-110B 来做 NER。为了控制成本,调的是 silicon cloud 的 API。知识库方面,用的还是 OpenMMLab 那 9 个算法库。

建库过程大概需要 14M token,单并发跑下来要 12 个小时以上,费用差不多 50 元。

python3 -m huixiangdou.service.kg --build

建库成功后,workdir/kg 目录下会出现 jsonl 格式的节点和关系文件。

此时可以试试检索效果,比如问一下怎么安装 MMPose:

python3 -m huixiangdou.service.kg --query 如何安装mmpose?

考虑到 API 欠费、网络断开这些不可控因素,代码里会记录已完成的部分,支持断点续建。

2.2 可视化

在 HuixiangDou 里,知识图谱的存储用的是 jsonl,图计算则靠 networkx。为了白嫖 neo4j 的可视化能力,我们也支持把 jsonl 转到 neo4j 里。

python3 -m huixiangdou.service.kg --dump-neo4j --neo4j-uri ${URI} --neo4j-user ${USER} --neo4j-passwd ${PWD}
# 30 万节点和关系数据,远程通信预计耗时 4 小时

下面是部分节点可视化的例子,看起来就像蒲公英一样:

  • 红色是属性节点
  • 蓝色是 chunk
  • 橙色是文档
  • 灰色是图片

2.3 直接检索测试

检索的过程和建库类似,先用 LLM 提取实体词,然后去匹配候选文档。

关于 score 的计算,我们事先统计了所有命中个数的分布。多数问题关联不了 100 个文档。考虑到后续还要缩放分值,就简单做了个拍脑袋的处理:

score = min(100, count(docs)) / 100

这里的阈值也是候选文档个数。举个例子,如果对某条用户输入,检索到 5 个以上的候选文档,就判定为 True,机器人会继续处理这句话,不拒绝。

测试结果很直观:随着阈值提高,知识图谱的检索结果会越来越保守,很多正类样本会被错误地归到负类里去。

2.4 混合检索测试

不过话说回来,

保守也是一种可靠

这种保守的特质,很适合用来计算正值 [0, +1],然后叠加到稠密检索的结果上,让原来的分布方差变得更大。

本文用的混合检索,说白了就是“考试加分”。具体公式如下:

final_score = dense_score + 0.2 * kg_score

这样一来,在实现层面就相当于变相改了阈值,而不用动稠密检索的代码。具体流程是:

  1. 先算 kg_score
  2. 重置 query 的阈值:throttle = throttle_in_config - 0.2 * kg_score
  3. 继续走原有的稠密检索流程

这样一来,知识图谱就变成了一个可开关的选项,和旧版本的特征库完美兼容!

3. 总结

总的来说,这套基于知识图谱和稠密检索的混合方案,本质就是在稠密检索过程中给高频词汇加权,最终带来了不到 2 个点的精度提升。

当然,现阶段实现得还有点糙,只支持 markdown 和纯文本格式。速度方面也没做任何优化,KG-LLM 的完整能力还没发挥出来。

接下来会继续完善代码,并在更多领域里跑一轮测试。