跳到文章正文
JianguoDing

技术实践

GraphRAG 产品分析 ↗

RETRIEVAL NOTES /《水浒传》知识探索实验

GraphRAG 实践
图检索的曲折之路

以《水浒传》为语料做 GraphRAG 检索实验:从 BM25、N-gram、Analyzer 与 RRF,到证据装填,以及关系排名失败后怎样改用关系定位原文证据。

图关系已经存在,答案却仍然找不全。沿着几次真实的检索失败,拆开词项、评分、融合与证据选择,再看结构化知识应该放在哪里。

匹配得到进入上下文足以支持答案

01 RAG · 导入与检索基线

先让检索过程可以被观察

Retrieval-Augmented Generation / 検索拡張生成

《水浒传》的知识探索实验,先从词法检索开始:把问题和原文变成词项,再计算哪些原文块更相关。

RAG(检索增强生成)先检索资料,再用资料帮助生成答案。GraphRAG(Graph-based Retrieval-Augmented Generation,图增强检索生成)则利用图结构支持这个过程;具体怎样用图,仍有不同实现。

初期 MVP 使用字符二元 / 三元片段与 BM25,没有直接把向量检索或图数据库接入主路径。这样做的价值是可解释:命中了哪些词、每一块得到多少分、哪里被筛掉,都可以记录和比较。

这不是一次“BM25 战胜向量检索”的选型实验。项目并未做过完整的两者 A/B 对照。是否需要语义检索,要看词法方案留下了什么失败,以及引入后的实际收益。

机制示意从问题到证据,中间有不同职责
  1. 词项怎样匹配N-gram / Analyzer
  2. 排序谁更靠前BM25 / RRF
  3. 选择哪些能装下证据预算
  4. 回答证据是否足够核对原文与引文

初期已经有抽取的人物与关系,随后也有答案中心的局部图谱。但“有图数据”“展示一张图”和“用图决定检索哪些证据”,是三件不同的事。关系检索专题会回到这条分界。

依据初始 BM25 MVP · 实验数据答案中心局部图谱 · 实验数据检索策略实验 · 实验数据

PART 01 / FOUNDATIONS

基础技术

从词项匹配到融合排名:先弄清四个常见环节各自解决什么问题。

02 BM25 · 相关性评分

BM25|让关键词匹配变成相关性排名

Best Matching 25 / 関連度スコアリング

搜索“林冲 宝刀”时,可能找到很多包含这些词的文本。BM25 根据词语出现次数、稀有程度和文本长度,判断哪些结果应该排在前面。

教学示意 · 以下文本为自拟例子同一个词,出现一次与两次

搜索词:宝刀

文本 A

林冲买了一口宝刀。

1 次命中
文本 B

林冲看见宝刀,又仔细端详这口宝刀。

2 次命中

TF|词频

Term Frequency

词语出现得更多,通常会提供更强的匹配信号。

BM25 的词频贡献会逐渐饱和,不会随重复次数无限线性增长。

教学示意 · 假设数据,非项目实测100 篇文本里,两个词的出现范围
林冲80 / 100 篇
宝刀5 / 100 篇

条长表示包含该词的文本比例,不表示相关性分数。

IDF|逆文档频率

Inverse Document Frequency

越少见的词,通常越能区分哪些结果真正相关。

“林冲”在许多文本里都出现,相较于稀有词,其统计区分力可能更弱。稀有程度不等于语义重要程度。

教学示意 · 以下文本为自拟例子同样命中一次,匹配的集中程度不同

短文本“宝刀”出现 1 次

林冲把宝刀拿在手里,翻来覆去地看。

长文本“宝刀”出现 1 次

林冲清早出门,经过街边的店铺,和熟人说了几句话。路上人来人往,有人挑着担子,有人停下歇脚。走到街角时,他看见一口宝刀,拿起来仔细查看。随后他又沿街走了一段,听见附近酒家传来谈笑声,便转身向家中走去。

长度归一化

Length Normalization

避免长文本只因为内容更多,就天然获得评分优势。

BM25 会参考文档长度及语料平均长度修正评分。这里固定命中次数,只比较词项在长短文本中的集中程度。

排名第二的证据,终于能够被选中

历史记录 · “买刀”证据 ch007_chunk_012去掉分数门槛,保留原有排序

修改前 · 固定阈值 5

3.39 < 5

相关证据排第 2,仍被排除。

修改后 · 取消绝对阈值

仍排第 2

不再被分数门槛挡掉,继续按容量与预算筛选。

31 道有答案的问题中,至少一块核心证据进入上下文

18 / 3120 / 31

取消阈值让证据获得入选机会,并不保证它必然进入上下文;候选数量、容量和预算仍会限制选择。

进一步了解:BM25 评分与历史阈值实验核对 S0 / S1 数据、评测条件,以及评分与证据选择的区别。
检索策略报告 · S0 / S1,评分与排序不变
历史策略Hit@3上下文含 ≥1 核心
S0 · 阈值 50.6518/31 ≈ 0.58
S1 · 去阈值0.6520/31 ≈ 0.65

第 7–11 回、59 块,31 道有答案题;预算 2000、最多 4 块,装不下则跳过继续。Hit@3 检查前 3 名是否含至少一个核心块;上下文覆盖检查最终入选块,二者不同。

3.39、排名第 2 与阈值 5 来自历史诊断。旧通道以 BM25 为基础,还含实体与相邻块加分,因此这里的 3.39 严谨地称为历史检索总分。样本小、单人标注,结果不宜泛化到全部查询。

依据检索策略实验 · 实验数据检索实现说明 · 实验数据Elastic · BM25 similarity ↗

03 N-gram · 连续字符片段

N-gram|把文字切成连续片段

Character N-gram / 文字 N-gram

中文没有天然的空格分词边界。字符 N-gram 不需要先判断完整词语,而是通过滑动窗口生成固定长度的字符片段。

教学示意 · 可选操作窗口宽度改变,词项也跟着改变
林冲买宝刀
1-gram
林冲买宝刀
2-gram
林冲冲买买宝宝刀
3-gram
林冲买冲买宝买宝刀

这是一段简化字符切分示意,不是项目原始检索输出。三种切分的全部词项始终可读,无需操作。

N 代表连续字符的数量。标准字符 N-gram 通常每次滑动一个字符,所以相邻词项会重叠。

N-gram 的重叠发生在词项生成时,Chunk Overlap 则发生在文本分块时。

  • 优点:无需词典,也能匹配未知词中的连续字符。
  • 局限:可能生成没有实际语义的片段,也不能自然理解近义表达。

项目实践 · Python 二 / 三元片段检索实现说明 · 实验数据OpenSearch · N-gram tokenizer ↗

04 Analyzer · 文本分析

Analyzer · 文本分析

Tokenizer / Text Analyzer / トークナイザー / アナライザー

Analyzer 把原始文本处理成可搜索的词项。

标准 Analyzer 教学示意 · 连续处理同一段文本,非项目实际分词器
  1. Character Filter

    字符预处理 · 清理原始文本中的标点

    林冲!!买了一把宝刀!!!林冲买了一把宝刀
  2. Tokenizer

    词项切分 · 将连续文本拆成可检索词项

    林冲买了一把宝刀[林冲] [买] [了] [一把] [宝刀]
  3. Token Filter

    词项过滤 · 根据规则删除部分词项

    [林冲] [买] [了] [一把] [宝刀][林冲] [买] [宝刀]

本例的分词与过滤规则人为设定:过滤“了”和“一把”,不代表所有 Analyzer 都会这样处理。

Character Filter 处理原始字符,Tokenizer 生成词项,Token Filter 进一步筛选词项。

03 · N-gram:了解不同字符切分方式。
下一步研究:了解词项过滤及查询扩展的后续研究方向。

项目通过 Python 自定义代码实现了部分文本分析与过滤功能。

依据检索实现说明 · 实验数据检索策略实验 · 实验数据OpenSearch · Text analysis ↗

05 RRF · 排名融合

RRF · 排名融合

Reciprocal Rank Fusion / 逆順位融合

同一批内容经过不同检索方法,可能得到不同排名。RRF 根据它们在各个排行榜中的名次,计算最终顺序。

两份排名,合成一份最终排名

文章 A 在两份榜单分别排第 1 和第 2,融合后成为最终第 1 名。

教学示意 · 自拟 A / B / C,等权 RRF,k = 60

排行榜 1

  1. 第 1 名文章 A
  2. 第 2 名文章 B

例如,二元 / 三元字符 BM25。

排行榜 2

  1. 第 1 名文章 C
  2. 第 2 名文章 A

例如,单字 BM25。

RRF · 按名次融合

最终排行榜

  1. 第 1 名文章 A0.03252
  2. 第 2 名文章 C0.01639
  3. 第 3 名文章 B0.01613

A 为什么排第一?

排行榜 1:第 1 名。

排行榜 2:第 2 名。

1/61 + 1/62 ≈ 0.03252

两路贡献相加,因此获得最高融合分数。

RRF 使用排名融合,不直接相加不同检索器的原始分数。

历史实测 · 双词法 RRF · Hit@3

0.650.77

“前 3 名是否找到至少一块核心证据”的有答案问题比例提高。

这是增加单字通道并融合后的整体结果,不能把全部收益归因于 RRF 本身。融合排名也不代表答案一定正确。

进一步了解:RRF 公式参数与完整评测数据查看 k = 60、未入榜候选的处理,以及历史三种检索策略的对照。

每路贡献为 1 / (k + 名次),本图等权融合,k = 60;未出现在某路候选中的文章,该路贡献为 0,不视作排在最后。分数统一保留五位小数。

旧通道二 / 三元词 BM25 + 加分
0.65
单字 BM25另一种词项粒度
0.71
双词法 RRF合并两个通道的名次
0.77

第 7–11 回、59 块、31 道有答案题。旧通道含二 / 三元词 BM25、实体与相邻块加分;单字 BM25 Hit@3 为 0.71,双词法等权 RRF(k = 60)为 0.77。去阈值、通道粒度和融合的贡献需要分开控制。

依据检索策略实验 · 实验数据预算对照实验 · 实验数据多章节知识检索设计 · 实验数据Cormack 等 · SIGIR 2009 ↗

PART 02 / FIELD NOTES

真实项目实践

前面介绍了文本分析、相关性评分与排名融合。接下来看看这些技术如何组成实际检索系统,以及我们怎样沿着检索链路定位问题、调整方案。

S 系统检索链路

从基础技术,到实际检索流程

Retrieval Pipeline / 検索パイプライン

前面的技术不是并列的知识点,而是一次回答背后同一条链路上的不同环节。

简化示意 · 当前问答主线,检索对象是原文块一个问题,怎样变成一次回答
  1. 用户提问“鲁智深和林冲怎么认识?”
  2. 文本分析与词项生成参照 03 N-gram04 Analyzer

    问题与原文块都被处理成两套词项:二 / 三元字符片段,以及去掉高频虚字的单字。

  3. 候选检索与相关性评分参照 02 BM25

    通道 1二 / 三元词项 → BM25 排名

    通道 2单字词项 → BM25 排名

  4. 多路结果融合参照 05 RRF

    只按名次合并两份排名,得到一份候选顺序。

  5. 证据选择与 Context 组装实践 A 检索与证据

    按融合名次,把完整原文块依次装入 Context,受 Token 预算与块数上限约束。

  6. Context 边界:模型只看得到已经装进来的证据。

    模型生成回答

    只根据实际收到的 Context 作答;回答后,系统再按原文核对引文。

图为当前主线的简化,不是完整调用链。实践 A 的 2,000 / 4,000 / 8,000 是不同时期的实验配置(旧策略 → RRF);当前默认配置是 RRF · 8,000 估算 Token · 最多 12 块。

进一步了解:这张图没有展开的部分当前主线与历史实验的差别、知识探索支线、事件骨架,以及关系查询与 RRF 的关系。

主线与历史配置。主线对原文块做两路 BM25,以 RRF(k = 60,等权)融合,再按名次依次装入完整块;某块放不下就停止,不跳过它去填更低名次的块。旧策略是阈值 5、最多 4 块、2,000 估算 Token,且会跳过放不下的块继续填。第一部分的 0.65 → 0.77 对应旧通道到双词法 RRF 的历史实验,不是这张图里各环节的单独收益。

知识探索支线。项目另有一条旁挂的知识探索链路:预先整理的人物画像、事件 / 关系 / 状态记录与章节概要作为“知识”,原文块作为另一个来源,两者分别设预算。知识候选同样用两路词法排名做 RRF 融合;问题里出现两个以上有区分力的人物时,再加一路按人物参与度的排名。这一路是对已有知识记录排名,与实践 B 中早期的“关系边排名通道”不是同一个实验。

事件骨架与关系查询。问到人物经历路径时,事件骨架在调用模型之前由知识库确定,再作为上下文交给模型写每个阶段的说明。“两个人物之间有什么关系 / 共同事件”这类查询按记录 ID 读取,不排名,也不是 RRF 的通道。

引文核验。回答之后会核对引文能否在所引原文中逐字找到;这只证明引文可以定位,不等于语义上支持了结论。

图里省略了会话中的证据记忆、追问处理与查询词清理等细节。

这些环节组合起来后,即使检索已经找到相关内容,回答仍可能出现遗漏。那么问题究竟发生在哪一步?看实践 A ↓

架构依据当前问答主线 · 实验数据问答编排 · 实验数据知识探索检索 · 实验数据知识探索链路 · 实验数据

A 检索与证据选择

检索结果与最终证据

Evidence Selection / Token Budget / 根拠の選択 / トークン予算

检索似乎找到了相关内容,回答却仍缺少关键信息。问题出在链路的哪一步?

01回答不完整,先确认问题发生在哪一步

实际回答漏掉了重要信息。先不急着调参数,沿着上面的链路从后往前查:先看模型实际收到的 Context 里有没有这条信息;再回到原文确认必要事实;最后对照候选检索(BM25 评分与 RRF 融合后的排名)和证据装填记录,判断它是没被检索到,还是检索到了却没有装进来。

  1. 最后对照候选检索与证据装填
  2. 先检查Context
  3. 发现问题模型回答

02关键证据已被检索,却没有进入 Context

回看“鲁智深和林冲怎么认识”的离线记录:结义原文已经在候选里,旧通道排第 8,改用 RRF 后升到第 4。但在 2,000 Token 的证据预算下,装填规则仍然挡住了它,Context 里没有这条原文。对这一题来说,名次变好还不够,它还要有机会被装进来。

RRF 离线对照 · 装填机制示意排在第 4,却被预算挡在上下文之外
#1入选#2入选#3超出预算#4核心证据

模型只看到已入选的块第 4 名即使有用,也没有送入这一档上下文。

第 4 名属于 RRF 离线排序,不是旧策略的第 4 名。图按“超预算即停”解释机制,块宽和其他块的截断点仅作示意;这不是下方某次真实模型调用的完整 Trace。

辅助信息 · 初期真实配置 · 第 7–11 回评测集

旧策略 · 2,000 Token

平均原文长度
639 字 / Chunk
实际通常只能装入
约 2–3 块原文
历史报告按 1 字 ≈ 1 Token 保守估算;并非模型实测 Token,容量也随块长度和选择规则变化。

配置来源检索策略实验 · 实验数据

03改变检索策略与预算,再观察实际回答

真实问题:“鲁智深和林冲怎么认识?”我们把检索策略从旧通道改为 RRF 融合,同时扩大证据预算,让更多必要证据有机会进入 Context,再检查回答能否区分相识、结义与野猪林救助。

检索策略与预算Context 的证据覆盖实际回答

旧策略 · 2,000

Token · 证据预算(保守估算)

Context:缺少结义原文。

必要证据不足,未能回答。

返回 insufficient。

RRF · 4,000

Token · 证据预算(保守估算)

Context:已有结义证据,也带入排名靠前的野猪林情节。

有更多证据,但仍混淆事件。

把第 7 回结义与第 9 回野猪林相认混合;3 条引文仅 1 条可定位。

RRF · 8,000

Token · 证据预算(保守估算)

Context:预算扩大,更多证据有机会进入。

这次回答更完整,未再混淆,引用可定位。

报告记为街头相见、认识林父、结义为兄;两条引文均可定位。

各组同时涉及检索策略、预算及选择规则差异,不能把全部效果归因于增加预算。每种配置仅一次真实模型调用,n = 1,不是统计性因果证明。此处未逐块核实本题 4000 → 8000 的 Context 差异,不推断具体新增了哪一块;引文可定位也不等于语义支持已验证。

更多证据,不等于更正确的回答。

扩大预算能改善证据覆盖的机会,同时也可能带来噪声;它不会让模型自动更会理解证据。

Context 还缺必要事实:继续检查检索、候选排序与证据装填。如果词面本来就对不上(例如问“报仇”,原文写“杀”“搠”),见下一步研究。

证据已充分,回答仍混淆:检查证据理解、事件关联、Prompt 设计与回答生成,不能只靠不断增加预算。

进一步了解:候选装填与预算实验记录查看完整覆盖与噪声统计、候选上限,以及不同装填规则。

预算扩大可能同时引入噪声。整个评测集中,RRF 从 4000 到 8000 档,全部核心被选齐的题数由 21/31 增至 27/31,未被标为核心或相关的入选块占比也由 61% 增至 79%。

Context Selection / Context Packing(上下文选择 / 装配,上下文選択 / コンテキスト構成)负责挑选与组织上下文。本文以证据覆盖和预算说明这层职责,不把它当作独立基础评分算法。

离线逐题记录中,“认识”一题的核心块 ch007_chunk_004 从旧通道第 8 名前移至 RRF 第 4 名;RRF 2000 档未入选,4000 档已入选。另一次真实回答对照记录了野猪林情节与结义的混淆;两类记录不能拼成同一次调用的完整 Trace。

双词法 RRF · 不限块数 · 超预算即停
预算
估算 Token
全部核心
题数 / 31
平均
入选块数
无关块
占比
2,00012 / 312.345%
4,00021 / 315.061%
8,00027 / 3110.679%
16,00030 / 3121.689%

“全部核心”检查人工标注 core 是否全入选;无关块按不属于 core∪rel 统计,是噪声上界,未标注不代表一定有害。表格是全评测集结果,不是只统计“认识”一题。

从 4000 到 8000 档,共新增 6 个核心块、176 个无关块。语料仅 59 块,结果不能直接当成更大语料上的推荐预算。

Top-K 限制候选,块数上限与 Token Budget 限制入选。仍限 4 块时,提高预算也不能继续改善。旧策略会跳过装不下的块继续“填缝”;超预算即停能抑制某些噪声,但不是所有任务的最优规则。

依据预算对照实验 · 实验数据逐题排名与失败归因 · 实验数据检索策略实验 · 实验数据

B 图关系检索的曲折

图关系检索的曲折

Graph Retrieval / グラフ検索

加入图关系后,检索命中率反而下降了。

前面的检索链路主要靠词项匹配、相关性评分和排名融合寻找证据。那么,已经抽取的人物、事件和关系,能否为这条链路增加新的检索能力?

01让关系边参与排名,未能带来改善

项目已经具备人物、事件和关系知识。最初的尝试,是把关系边作为第三路检索信号,通过 RRF 与原来的两路词法排名等权融合。

历史实验 · 31 道有答案题关系参与排名

Hit@3:0.77 → 0.68

0.77:原有双词法 RRF。
0.68:加入关系边排名通道。

失败分析额外关系也可能带来噪声

高频人物关联大量关系边,关系描述又未必与问题用词一致;等权融合可能把这些噪声推到前面,扰动原有排名。

这是特定关系文本、匹配规则与等权融合方案的结果,不能解释为图检索本身无效;上面的噪声原因来自报告分析,不是普遍因果结论。

02失败的是图关系,还是使用方法?

这次失败说明直接增加关系排名通道没有达到预期,但并不能证明结构化关系本身无效。研究没有因此放弃,而是开始寻找另一种使用方式。

能否不让所有关系边直接竞争排名,而是用它们查找关联人物和事件,再追踪对应的原文证据?

03让关系辅助证据探索

后续系统已经让结构化关系承担另一种职责:帮助发现相关人物和事件,再回到对应的原文证据,而不是再增加一张排行榜。

早期实验

关系边排名通道RRF 融合与词法结果竞争名次

后续实现

人物 / 事件 / 关系记录查询关联出处原文证据展示与事件路径

  • 人物关系查询读取两个人物之间的关系记录。
  • 关联事件查找找出两人共同参与的事件。
  • 原文证据定位关系与事件记录带有出处,可回到对应的原文片段。
  • 经历路径与事件组织问到人物经历时,知识库先把事件按顺序分成阶段,再交给模型写每个阶段的说明。

实现核对检索实现说明 · 实验数据

组织方式示意 · 原文片段已核对同一对人物,两段不同的事件证据
林冲共同参与 / 关系记录鲁智深
第 7 回林冲与鲁智深结义
ch007_chunk_004
“林沖大喜,就當結義智深為兄。”

人物相遇与结义的原文证据。

第 9 回鲁智深在野猪林救助林冲
ch009_chunk_001
“林沖方纔閃開眼看時,認得是魯智深。”

这里的“认得”不能当作首次相识。

事件标题是教学概括,连线表达组织关系,不冒充实际查询路径或原始 Schema。引文保留原文繁体。

一次失败,不代表整个研究方向没有价值。

最初的排名策略没有成功,但后续系统已经把结构化关系用于证据关联和事件组织。关系承担什么职责,要由问题与实验效果决定,增加一个通道并不保证更好。

上述查询、出处关联与事件组织能力已经实现;它们对回答准确性、完整性的稳定贡献仍需验证,也不意味着全部多跳问题已解决。验证方向见下一步研究。

进一步了解:关系检索实验及实现边界查看早期等权融合条件、后续已实现的查询与经历路径组织,以及效果验证边界。

检索策略报告 S4 / S6,31 道有答案题。枢纽人物名字命中会引入噪声,“认识”与关系类型“结义”也未必字面匹配;本次下降只针对该实验方案。

现有服务的 kb_pair 查询人物关系与共同事件,kb_record 关联事件、关系、状态与出处;经历路径由 plan_for_question 构建事件骨架。人物对查询是按 ID 读取,不参与排名,也不会自动进入模型 Context。可查询和可组织不等于已证明回答质量提升。

依据检索策略实验 · 实验数据逐题排名与失败归因 · 实验数据多章节知识检索设计 · 实验数据Python 知识探索引擎 · 实验数据答案中心局部图谱 · 实验数据Python / FalkorDB Provider · 实验数据

PART 03 / OPEN QUESTIONS

下一步研究

实践留下两类问题:表达与原文用词不同时,证据仍可能找不到;关系与结构化知识对回答质量的贡献,也还没有验证。

→ 下一步优化

下一步:让查询更准确地找到证据

Query Expansion / Query Rewrite / クエリ拡張 / クエリ書き換え

现有词法检索仍然难以处理部分表达差异,例如用户说“报仇”,原文却使用“杀”“搠”等动作描述。

Analyzer / Token Filter · 词项处理与过滤
调整词项处理、领域词典和过滤规则,观察是否能改善检索匹配与噪声。

Query Expansion / Rewrite · 查询扩展与改写
尝试保留原问题、补充相关检索表达,检查能否找回以前遗漏的证据,同时防止查询漂移。

这些方向仍是待验证的假设,需要使用相同评价集与原始策略做对照。结构化关系对回答准确性与完整性的贡献,同样要先对照评估,再下结论。

问题依据检索策略实验 · 实验数据预算对照实验 · 实验数据多章节知识检索设计 · 实验数据

回到工程判断

先定位失败发生在哪一层,再选择技术。

词项没有匹配,改预算无济于事;证据排得靠前却被挤掉,增加图关系也未必解决。更可靠的起点,是让匹配、排名、选择与证据支持都能被检查。

进一步了解:证据来源与文章边界了解实测、教学示意与待验证方向的区别,以及实验规模和独立性的限制。

实验数字来自已提交的历史报告;这些报告和代码在私有仓库里,不对外开放,所以本文不链接到它们。方法、数字和限制集中记录在文末的实验数据与验证依据里。本文没有重跑 LLM 实验,也没有完成独立复评。

Analyzer 的独立例子、N-gram、RRF 数值例子、预算截断与关系组织图均为教学示意。负面实验不泛化为技术优劣,未来研究不视为现有成果。

实验规模小(第 7–11 回、59 个原文块、31 道有答案题)且为单人标注,差一两题就能改变数值,结果不宜推广到其他语料或更大规模。

实验数据与验证依据

这一节只做一件事:把文章引用的实验数字、方法和限制放在可公开访问的地方。完整的内部报告和源代码不公开,也没有复制到这里。

评测设定与检索效果对比评测集与指标口径,以及检索策略、去阈值和关系边通道的 Hit@3 对照。

评测设定

语料《水浒传》第 7–11 回,59 个原文块(Chunk),平均约 639 字 / 块。
评测集33 题:31 题有答案,2 题无答案。核心证据块由一人标注;Hit@3 与核心覆盖指标主要针对 31 道有答案题。
指标Hit@3:前 3 名是否含至少一个核心块。上下文覆盖:最终入选上下文的块里是否含核心块。两者不同。
预算口径按 1 字 ≈ 1 Token 的保守估算,不是模型实测 Token;容量随块长度与选择规则变化。
真实回答每种配置只调用一次模型(n = 1),不是统计性实验;引文“可定位”指能在所引块中逐字找到。
规模与独立性小语料、单人标注,差一两题就能改变数值;没有独立复评,也没有重复调用的方差。

检索策略对照

三种检索配置在 31 道有答案题上的 Hit@3(只用词法检索,没有向量检索):

配置Hit@3说明
旧通道0.65二 / 三元词 BM25,加实体与相邻块加分。
单字 BM250.71另一种词项粒度。
双词法 RRF0.77二 / 三元词与单字两路名次融合,k = 60,等权。

0.65 → 0.77 是增加单字通道并融合后的整体结果;去阈值、通道粒度与融合各自的贡献没有被分开控制,不能把收益全部归因于 RRF。

去掉分数阈值

S0 与 S1 的评分和排序相同,只改是否应用绝对阈值。预算 2,000,最多 4 块,装不下的块跳过后继续。

策略Hit@3上下文含 ≥1 核心块
S0 · 阈值 50.6518/31 ≈ 0.58
S1 · 去阈值0.6520/31 ≈ 0.65

诊断个例:“买刀”证据块 ch007_chunk_012 的历史检索总分为 3.39,排第 2,被阈值 5 排除。这个分数以 BM25 为基础,还含实体与相邻块加分,所以严格说是“历史检索总分”,不是纯 BM25 分。

加入关系边通道

在双词法 RRF 之外再加一路“关系边”排名,等权融合(报告中的 S4 / S6),31 道有答案题:

配置Hit@3
双词法 RRF0.77
加入关系边通道0.68

报告对下降的分析:高频人物关联大量关系边;关系描述与问题用词不一定一致;等权融合可能把这些噪声推到前面。这是该方案(特定关系文本、匹配规则与等权融合)的结果,不能解释为图检索本身无效。

证据预算与真实回答不同预算下的核心块覆盖与噪声,以及同一问题三种配置的回答记录。

证据预算对照

双词法 RRF,不限块数,超预算即停(某块放不下就停止,不再跳过它去填更低名次的块)。整个评测集的结果:

预算(估算 Token)全部核心块入选的题数平均入选块数无关块占比
2,00012 / 31 题2.345%
4,00021 / 31 题5.061%
8,00027 / 31 题10.679%
16,00030 / 31 题21.689%

“无关块”指不属于人工标注 core ∪ rel 的块,是噪声的上界,未标注不代表一定有害。

从 4,000 档到 8,000 档,共新增 6 个核心块和 176 个无关块。语料只有 59 块,结果不能直接当作更大语料的推荐预算。

旧策略(阈值 5、最多 4 块、2,000 估算 Token)会跳过装不下的块继续填;块数上限为 4 时,提高预算也无法继续改善。

真实回答与排名记录

同一个真实问题“鲁智深和林冲怎么认识?”,三种配置各调用一次模型:

配置Context回答记录引文可定位
旧策略 · 2,000缺少结义原文。证据不足,返回 insufficient。—
RRF · 4,000有结义证据,也带入排名靠前的野猪林情节。能回答,但把第 7 回结义与第 9 回野猪林相认混合。1 / 3
RRF · 8,000预算扩大,更多证据有机会进入。此次回答更完整,未再出现之前观察到的情节混淆:街头相见、认识林父、结义为兄。2 / 2

核心块 ch007_chunk_004 的排名:旧通道第 8,RRF 第 4;RRF 的 2,000 档未入选,4,000 档入选。这是离线逐题记录,与上面的真实回答不是同一次调用的完整 Trace,不能拼成一条因果链。

三种配置同时在检索策略、预算与选择规则上不同,不能把效果全部归因于增加预算;也没有逐块核实 4,000 → 8,000 在这一题上具体新增了哪个块。

“引文可定位”只表示片段能在所引块中逐字找到,不表示语义上支持结论;每种配置只调用一次,没有测重复调用的方差。

实现说明、限制与来源检索实现的核对说明、实验的限制与可信度,以及数字的来源。

检索实现说明

文章里的系统图是对下面实现的简化,核对的是 2026-10 的代码(私有仓库,提交 0d26b5c)。

部分说明
当前问答主线只检索原文块:二 / 三元词项与单字词项各做 BM25,以 RRF(k = 60,等权)融合;按名次装入完整块,块数达上限或某块超预算即停止;默认 8,000 估算 Token、最多 12 块。每次提问一次检索、一次模型调用,回答后核验引文。
旧策略(历史)单路 BM25 通道(含实体与相邻块加分),阈值 5、最多 4 块、2,000 估算 Token,跳过装不下的块继续填。
知识探索支线预先整理的人物画像、事件 / 关系 / 状态记录与章节概要作为“知识”,原文块是另一个来源,两者各设预算。知识候选同样做两路词法排名并用 RRF 融合;问题含两个以上有区分力的人物时,再加一路人物参与度排名。
事件骨架问人物经历路径时,事件骨架由知识库在调用模型前确定,作为上下文的一部分交给模型写每个阶段的说明。
关系查询两个人物之间的关系与共同事件、记录与出处的查询按记录 ID 读取,不排名,不是 RRF 的通道,也不会自动进入模型 Context。
多章节检索设计知识探索支线的检索设计来自一次覆盖第 7–11 回的多章节离线实验;本文没有使用它的数字。
演进记录初始 BM25 MVP(2061743)→ 答案中心局部图谱(e32245a)→ Python 知识探索引擎(0b36e0c)→ Relation Provider(Python / FalkorDB,d687c29)→ 本次核对的主线版本(0d26b5c)。这些是私有仓库的提交标识,仅供识别,不提供链接。

能查询、能组织不等于已经证明回答的准确性与完整性有稳定提升;这一点没有被实验验证。

限制与可信度

  • 语料小(59 块)、评测集小(31 道有答案题)、核心块由一人标注:差一两题就能改变数值。
  • 没有向量检索与词法检索的完整 A/B 对照,所以文章不主张“BM25 优于向量检索”。
  • 真实回答每种配置只调用一次(n = 1),没有重复调用的方差;回答由作者对照标注与原文判断,不是第三方评分。
  • 预算是按字数的保守估算,不是模型实测 Token。
  • 没有重跑实验,也没有独立复评。
  • 关系边通道的失败只说明该方案;已实现的关系查询与事件组织对回答质量的贡献尚待验证。

来源说明

这些数字来自 graphrag-shuihu 项目中已提交的实验报告和代码。该仓库目前是私有的,所以本站不链接到它;本节就是这些数字与方法的公开记录。

本节只摘录方法、结果和限制,没有复制完整内部报告或源代码。若本节与原报告的数字不一致,以原报告为准,并应更正本节。

BM25、N-gram、Analyzer 与 RRF 的通用说明,见下列公开文档:

依据Elastic · BM25 similarity ↗OpenSearch · Text analysis ↗OpenSearch · N-gram tokenizer ↗Cormack 等 · SIGIR 2009 · RRF ↗