先理解
刚接触这个知识点
补齐先备概念,读原理与反例,再用自己的话解释为什么。
从核心原理开始 →理解 → 实现 → 排错 → 取舍
考察混合检索、排序融合、去重与多阶段评测。
知识内容核对 2026-10-03 · 原题来源核对 2026-10-02
建议先理解:
提示、结构化输出与迭代验收 →上下文与生成预算 →工具调用的结构、授权与业务契约 →按当前基础选择起点,也可以依次深入。遇到不熟悉的概念,先回到核心原理;完成后用知识练习检查理解。
LEARN · PRACTICE · REFLECT
先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。
核心知识 · 混合检索中的互补召回与排名融合
先备概念:倒排索引与 BM25、向量相似度、候选与重排
词法检索和语义检索解决不同遗漏,融合让互补证据进入候选。重排只能重排已有证据,任何融合算法都无法找回从未被召回的精确实体。
产品编号 XQ-104 与 XQ-140 的字符相近,但业务对象不同;“自动暂停续费”和“取消后不再扣费”字符不同却可能表达同一需求。词法或精确字段擅长识别标识,向量召回擅长语义变化。编号还要检查分词与归一化,不能认为只接 BM25 就一定保留短横线和大小写语义。
让各路在同一授权与版本范围内产生候选,使用稳定的块 ID 识别同一项。RRF 按名次贡献求和:score(d) = Σ 1 / (c + rank_i(d)),只对召回 d 的列表求和,排名从 1 开始,c 是融合常数。它避免直接比较两路原始分数的尺度。
例如 c=60,A 在两路排名为 1 和 3,B 为 2 和 1,C 只在第二路排第 2:
| 证据 | 两路贡献 | 融合分数(近似) |
|---|---|---|
| A | 1/61 + 1/63 | 0.03227 |
| B | 1/62 + 1/61 | 0.03252 |
| C | 0 + 1/62 | 0.01613 |
融合后是 B、A、C;这只是名次计算,仍需核对事实适用性。c 不等于向量检索的候选数 k:k 决定向量路提供多少候选,融合窗口决定各路最多参加多少项,size 决定最终返回多少项。以 Elastic 为例,k 大于融合窗口时会截断;只提高 size 也不会找回根本没有进入候选的证据。
重排器通常只看到候选文本,若编号被改写器删掉或检索器漏掉目标,它无法凭空补出。重排可能更偏爱内容丰富的旧说明,必须保留版本、实体匹配与权限这些硬约束。重复的相邻块会占据候选窗口,可以在保留必要证据的前提下去重或按来源聚合,但不能把不同版本混成一个“共同支持”的对象。
准备精确编号、同义表达、错别字、无答案和混合条件问题,分别关掉一路检索做对照。先测目标证据覆盖,再测重排与回答支持率,同时统计延迟。RRF 分数受参与排名列表数量影响,不能设一个不经校准的全局事实阈值。稳定的融合策略来自具体查询分布,而非算法名称本身。
产品编号、精确名称通常需要词法或精确匹配,语义改写则可用向量召回。我会在权限过滤下运行两路检索,按稳定文档块 ID 去重,用 RRF 等排序融合形成候选,再在预算内重排。BM25 分数与向量分数不能随意相加。分别测候选证据覆盖和重排后的有效排序,防止只优化最终列表而掩盖召回缺失。
“ZX-104 故障”要求精确型号,近似语义可能召回 ZX-105;“无法启动”则可能需要匹配“开机失败”。先规范化查询中的编号、时间和实体,保留原始问题。词法与向量两路都使用当前权限和文档有效性过滤,不能先把越权文本交给重排模型再过滤展示。
可用排名融合建立基线:对每一路中第 r 名的文档贡献 1/(k+r),按统一 ID 合并。k 和各路候选窗口影响结果,需要在数据集上校准。分数融合也可行,但应处理量纲、分布和权重,不能直接把 BM25 的 12 分与向量的 0.8 分相加并认为公平。
重排器只能在输入候选中选择。先看候选集合是否包含必要证据,再分析排序是否把它排到上下文窗口以外。过多相邻重复块会占满名额,可以按文档或主题做去重和多样性控制。重排服务超时要有明确降级方案,例如使用融合排序,并记录此次未重排。
分别准备精确编号、同义改写、长问题和无答案问题。检查 Recall@K、nDCG 或人工相关性、最终引用正确性与 P95 时延。对召回和重排候选数做小范围消融,报告提升来自哪类问题。RRF 是一种可测的工程基线,不是无需数据就能保证最优的算法。
演示排名融合;没有实现检索器、权限过滤或参数调优。
def rrf(rankings, k=60):
scores = {}
for ranking in rankings:
unique = dict.fromkeys(ranking)
for rank, doc in enumerate(unique, 1):
scores[doc] = scores.get(doc, 0) + 1 / (k + rank)
return sorted(scores, key=lambda doc: (-scores[doc], doc))
print(rrf([["A", "B", "C"], ["B", "D", "A"]]))
预期输出
['B', 'A', 'D', 'C']沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。
第 1 层RRF 如何处理同一块被两路召回?
从两路互补进一步落实同一证据的身份。
用同一个稳定 chunk_id 聚合两路结果,并累计它在不同列表中的名次贡献;同一路列表内重复出现不能重复计票。保留每路名次方便解释与调试。相同文本但不同文档版本不能只靠文本哈希合并,否则旧版与新版可能被错误当成互相支持。
沿着这个回答继续深入
第 2 层两路命中相同正文的不同块,应该当成同一项吗?
父问以 ID 合并后,真实数据中的重复文本又可能放大排序贡献。
先区分证据身份与文本重复。相同来源版本内的重叠块可聚合或降低冗余,但不同条款、版本、权限不能只凭正文相同合并。保留原块定位,重排后按来源多样性选证据;否则十份复制文档会看似形成十票共识。
沿着这个回答继续深入
第 3 层去重后目标掉出结果,怎样判断是去重错了还是融合参数不合适?
引入去重改变名次后,需隔离语义丢失与参数效应。
对比去重前后的来源定位与必要证据内容;若例外条款随去重消失,先修身份规则。若证据仍在但排名降低,再在标注集调整候选窗口或融合常数。两个改动分开做,避免参数调优掩盖错误合并;最终复核答案支持而不只看排名。
第 1 层为什么重排模型更强仍会答错?
区分候选覆盖与排序能力,避免错误归因。
重排只优化给定候选的顺序,候选没有正确证据就无从排序;文本缺单位、版本或编号时也可能把相关但错误的块排前。先检查候选覆盖和硬约束,再评估重排。更强模型也可能流畅补全缺失信息,不能把流畅当支持。
第 1 层编号被查询改写器删掉怎么办?
召回改善依赖上游意图不被改写破坏。
保留用户原句作为独立检索支路,提取编号为受保护实体槽位,改写结果必须通过保留校验;编号冲突或遗漏时拒绝该改写或回退。不要让语义扩展替代精确限定。记录原句、改写和各路命中,才能发现改写前后召回方向改变。
先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。
改变的条件:从编号查询变成自然语言同义句
延伸问题:关键词一路没有命中,还应该固定提高它的权重吗?
不能为单类题统一抬权重。保留语义支路,评估其是否召回目标证据;再通过融合与重排保留语义命中。按问题分层看变化,精确标识题和同义题可能需要不同查询计划。权重是基于数据的选择,不应把某一路视为永久更可靠。
保持不变的原理:不同检索信号互补,最终以目标证据是否覆盖而非单路高分判断。
改变的条件:身份相同,但适用版本不同
延伸问题:两路都命中旧版,是更强的证据吗?
只是两种检索方法都认为它相关。先按用户指定版本过滤,未指定且会改变答案时澄清或明确列出版本差异。将 document_version 纳入证据身份,不跨版本累计支持;候选共识不能覆盖业务适用性。
保持不变的原理:排名一致性不等于事实适用性,版本是证据成立的条件。
依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。
读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。
把检索前过滤的思想迁移到记忆版本与恢复。观察撤销后已有草稿怎样失效。
python3 cli.py memory-put --db memory.sqlite
python3 cli.py submit --db memory.sqlite
python3 cli.py run --db memory.sqlite --lease-seconds 2 --fault after_draft
python3 cli.py memory-forget --db memory.sqlite
# 等待至少 2 秒后分别执行
python3 cli.py run --db memory.sqlite
python3 cli.py inspect --db memory.sqlite验证本地作用域、版本与撤销阻断;旧检查点仍保留,不提供日志、备份和检查点的彻底删除。
手算两路排序 A,B,C 和 B,D,A 的 RRF,说明重复文档如何合并。