外观
RAG 检索优化
目录
- 1. 学习目标
- 2. 面试结论
- 3. 面试官为什么问
- 4. 概念与边界
- 5. 原理剖析
- 6. 实现与代码
- 7. 实际项目案例
- 8. 方案权衡与常见误区
- 9. 面试题与参考答案
- 10. 递进追问
- 11. 实践任务
- 12. 相关知识与参考资料
- 13. 简明总结
1. 学习目标
- 理解查询改写、关键词检索、稠密检索、元数据过滤、融合、重排和上下文压缩的职责;
- 能够推导 BM25、Reciprocal Rank Fusion(RRF)、MRR、nDCG 和 MMR 的核心公式与边界;
- 能够解释为什么检索优化首先追求候选召回,再由重排提高前排精度;
- 能够横向比较固定 Top-K、绝对分数阈值与 AutoCut 动态截断,并按查询类型、分数可比性和风险选择;
- 能够实现一个最小混合检索程序,保证租户过滤早于候选进入上下文;
- 能够用“现象 → 根因 → 修复 → 验证”定位无召回、错召回、查询漂移、过滤泄露和重排退化。
2. 面试结论
2.1 30 秒回答
RAG 检索优化不是盲目增大 Top-k,而是把链路分成候选召回和精排:先对查询做必要的规范化或改写,用 BM25 召回精确词、用稠密检索召回语义近邻,并在可信身份条件下做元数据过滤;再用 RRF 等方法融合,Cross-Encoder 重排,最后去重和压缩上下文。优化必须在带证据标注的固定集上比较 Recall@k、MRR/nDCG、延迟和成本,否则无法证明效果。
2.2 一分钟复述版
我会先分析失败样本属于哪类:文档不存在、查询表达和文档不一致、关键词稀有、语义同义、过滤条件错误,还是相关结果被排在后面。稀有编号、产品名和错误码适合 BM25;同义表达适合稠密检索;两路分数不可直接相加时可以按排名用 RRF 融合。融合后只对有限候选做 Cross-Encoder 重排,因为它联合编码 query-document,相关性通常更细,但计算成本更高。ACL 必须在检索算子内或候选进入应用前生效,不能先检索未授权内容再在答案层隐藏。最终按查询类型分桶,对比召回、排序、端到端答案、p95 延迟和 Token,而不是只看平均分。
3. 面试官为什么问
- 核心考察点:是否有信息检索基础,能把“效果不好”拆成可测的排序问题;
- 对应岗位与级别:AI 应用、搜索、推荐和 AI 平台;高级岗位会追问融合、过滤、复杂度与线上回滚;
- 优秀回答的区分度:
- 能解释 sparse 与 dense 的互补,而不是宣称谁绝对更好;
- 能写出 BM25、RRF、MRR/nDCG 的含义;
- 能区分召回阶段与重排阶段的目标;
- 能指出查询改写可能产生语义漂移;
- 能把权限过滤视为安全边界。
4. 概念与边界
4.0 小白先这样理解:图书馆里的两支找书队
你去图书馆找一本书:若手里有 ISBN“978-…”,电脑可按精确编号直奔书架;若只记得“讲宇航员在火星种土豆”,图书管理员会按语义猜到可能是《火星救援》。前者像 BM25 关键词检索,后者像 稠密检索;两支队先各交候选,RRF 像合并名次的裁判,Cross-Encoder 像逐本翻看简介的终审员,最后才把最相关且不重复的几本放上借阅台。
类比边界: 检索优化不能找到馆里根本没有的书,描述被改写错也会带偏方向;终审只能重排已有候选,不能凭空补书。读者证和密级对应租户与 ACL,必须在各路召回时就过滤,并在交付前再次授权,不能先让未授权资料进入候选再“假装没展示”。
4.1 是什么
检索优化是在语料和基础链路已正确的前提下,提高“必要证据进入最终上下文并排在合适位置”的概率。完整漏斗及各阶段 Trace 见 5.8 可视化辅助:它把查询理解、强制过滤、多路召回、融合、精排和上下文选择画成一条可观测链,而不是用一行箭头隐藏阶段差异。
每一层目标不同:
- 查询理解:让用户表达与索引表达更匹配;
- 召回:尽量不漏掉相关文档;
- 融合:合并不同检索器的互补结果;
- 重排:把最相关候选推到前面;
- 上下文选择:在 Token 预算内兼顾相关性、完整性和多样性。
4.2 不是什么
- 检索优化不能找回语料中不存在或解析丢失的事实;
- 查询改写不是让 LLM 自由“补全用户真实意图”;
- Rerank 不是生成答案,也不保证候选中一定有正确证据;
- 相似度阈值不是跨模型通用常量;
- Metadata Filter 不只是性能优化,租户和权限过滤是安全约束;
- 线下 Recall 提升不必然让最终答案提升,更多噪声可能伤害生成。
4.3 典型技术栈的职责
| 技术 | 擅长 | 主要短板 |
|---|---|---|
| BM25/倒排索引 | 错误码、编号、专有名词、词项匹配 | 同义改写与语义泛化有限 |
| 稠密双编码器 | 语义近邻、同义表达 | 稀有精确词可能弱;依赖 Embedding 领域适配 |
| Metadata Filter | 时间、类型、租户、ACL | 错误条件会直接造成零召回 |
| RRF | 融合不可比分数的排名 | 不利用原始分数幅度 |
| Cross-Encoder | 对 query-document 联合精排 | 逐候选推理,成本和延迟较高 |
| MMR | 相关性与多样性平衡 | 参数不当会牺牲最相关证据 |
| Query Rewrite/HyDE | 缩小问法与文档表达差距 | 可能漂移、放大延迟与调用成本 |
4.4 输入、输出与前置条件
- 输入:原始查询、会话中已确认的省略信息、身份过滤、候选索引;
- 输出:带 retriever、rank、score、版本和过滤理由的候选列表;
- 前置条件:
- 语料覆盖与解析已验证;
- 至少一部分查询有相关证据标注;
- ACL/租户条件来自可信服务端;
- 检索与重排模型版本可追溯;
- 最终上下文和候选列表能在 Trace 中重放。
4.5 与相近优化的区别
- 召回优化关注相关文档是否进入候选集;
- 排序优化关注相关文档在候选中的位置;
- 上下文优化关注哪些候选真正进入模型输入;
- 生成优化关注模型是否忠实使用上下文;
- 语料治理关注知识是否正确、完整、当前有效。
如果问题是旧文档仍在索引,换 Reranker 只能把错误候选重新排序,不能修复版本真相。
5. 原理剖析
5.1 查询处理
查询处理应从确定性步骤到生成式步骤逐级增加:
- Unicode、大小写、空白和标点规范化;
- 拼写、别名、产品词典和错误码规范化;
- 从已确认会话状态补全省略指代;
- 查询分类,选择索引、过滤和检索器;
- 必要时做受约束的 rewrite、多查询或 HyDE。
生成式改写必须同时保留原查询,并记录 rewrite_version。对于“不要退款”“旧版不适用”这类否定和时间条件,要设计保真校验;不能只检查改写后的句子是否流畅。
5.2 关键词检索:BM25
对查询
其中:
:词项 在文档中的频次; :文档长度, 为平均文档长度; :控制词频饱和; :控制长度归一化; :稀有词权重。
直觉上,一个词从出现 0 次到 1 次很重要,从 100 次到 101 次贡献不会线性增长;长文档因为词多而偶然命中的优势会被校正。中文效果还依赖分词、字粒度、同义词词典和字段权重。
5.3 稠密检索
双编码器分别计算查询与文档向量:
然后用点积、余弦或距离排序。文档向量可离线预计算,因此在线只编码查询并查 ANN。优势是语义泛化,限制是:
- 向量压缩了文本细节;
- 领域外术语和精确标识符可能召回差;
- 模型和索引必须同版本;
- ANN 参数引入额外近似误差。
教学插图:BM25 与稠密检索的互补召回

替代文本: 用户身份先转换成可信权限过滤,并在检索前同时约束 BM25 与稠密检索。BM25 利用错误码、产品名等精确词项产生词法排名;稠密检索在概念性语义空间中召回措辞不同但含义相近的文档块;两路排名最终由 RRF 按名次融合。
读图结论: BM25 保留精确词项信号,稠密检索补充语义改写能力;混合召回的价值来自互补,而且权限边界必须在每一路检索中生效,不能等融合后再补救。
图中的二维向量空间只是高维 Embedding 的概念投影;稠密检索和 ANN 都不保证召回正确答案。RRF 使用排名而不是直接相加异构原始分数,融合后仍需要去重、重排和二次授权校验。
5.4 混合召回与 RRF
BM25 分数和向量相似度的量纲、分布不同,直接加权相加需要校准。RRF 只使用排名:
其中
边界:
- RRF 稳健但丢弃原始分数置信信息;
- 候选深度不同会影响结果;
- 同一内容的重复 Chunk 可能多次获益,融合前后都需去重;
- 权限过滤应在各路候选可见性边界内执行。
5.5 Cross-Encoder 重排
双编码器独立编码 query 和 document,适合大规模召回;Cross-Encoder 把二者联合输入模型:
它能建模更细的词间交互,但需要对每个候选执行推理。若初始候选数为
重排必须看到足够的 Chunk 文本与关键元数据。输入截断恰好切掉答案时,模型再强也无法正确排序。
5.6 Top-K、阈值与 AutoCut 的候选截断
三者都用于从已排序候选中决定“保留多少”,但控制变量不同。本文统一假设 相似度越大越相关;若引擎返回 Distance,则通常是越小越相关,阈值方向和差值公式都要反转。技术上应写“阈值”,不是“阀值”。
设排序分数为:
text
0.92, 0.90, 0.88, 0.61, 0.59, 0.31Top-K=5:固定保留前 5 条,不判断第 5 条是否真的相关;threshold=0.70:保留前三条,结果数量可从 0 到候选上限;AutoCut=1:若实现把0.88 → 0.61识别为第一个显著跳变,则在此截断;以 Weaviate 的语义为例,参数表示保留到第几个 Jump,而不是直接指定结果数。
5.6.1 横向对比
| 对比维度 | 固定 Top-K | 固定阈值 Threshold | AutoCut / 动态断点 |
|---|---|---|---|
| 控制对象 | 数量上限 | 绝对分数质量线 | 单次查询内的相对分数跳变 |
| 输出数量 | 固定或不超过 K | 可变,可能为 0 | 可变,受候选池和 Jump 参数影响 |
| 是否依赖分数校准 | 低,只要求排序大致正确 | 高,分数方向、尺度和版本必须稳定 | 中,不要求跨查询同尺度,但要求单次排序曲线有可信断点 |
| 主要优点 | 简单、确定、易做容量和延迟预算 | 能拒绝“虽然排前但仍不相关”的结果 | 能根据每个 Query 的分数分布动态调整 K |
| 主要缺点 | 无答案查询也会强行返回 K 条噪声 | 模型、语料或查询类型变化后容易误杀或放入噪声 | 平滑下降、候选太少或多意图多证据时可能找不到正确切点 |
| 典型场景 | UI 固定槽位、Reranker 输入上限、延迟/Token 硬预算 | 已校准 Reranker、严格证据门禁、允许空召回和拒答 | 分数尺度随 Query 变化、相关结果形成明显分组、希望动态控制上下文 |
| 不适用场景 | 高风险无答案判断只靠 Top-K | 未校准 BM25/Dense/RRF 原始异构分数,或版本频繁切换 | 排名曲线近似均匀、重复 Chunk 制造假断点、多跳证据跨多个分数组 |
Top-K 不只是效果参数,还是容量保险丝;即使使用 Threshold 或 AutoCut,通常仍保留 k_recall_max、k_rerank_max 和 k_context_max 三个硬上限。Threshold 是绝对门禁,适合回答“最低质量是否合格”;AutoCut 是相对分组,适合回答“本次查询的自然相关结果组在哪里结束”,二者不能互相冒充。
5.6.2 AutoCut 的机制与边界
对降序相似度
AutoCut 类方法寻找显著的 autocut/auto_limit 按结果 Distance 或 Search Score 的不连续点工作,和 limit 同用时只检查 limit 已返回的候选,Hybrid Search 还要求使用其 relativeScoreFusion 排名方式。因此 AutoCut 是产品化的 Query-dependent K 策略,不是跨引擎同定义的标准算法。
它有四个重要失败边界:
- 分数均匀下降时没有明显断崖,切点可能不稳定;
- 重复 Chunk 会制造密集高分组或假 Jump,应先按稳定 Evidence ID 去重;
- 多跳问题所需证据可能分布在多个分数组,只保留第一组会伤害 Recall;
- 若正确证据根本没进入初始
limit/k_recall,AutoCut 和 Reranker 都无法补回。
一项 2025 年临床 EHR RAG 研究在其开发集上观察到:既有 AutoCut 取得了较高 Precision、但 Recall 明显偏低,而且论文明确指出均匀递减分数是其困难场景。这只能作为失败边界证据,不能推导 AutoCut 在其他语料上一定差或一定好。
5.6.3 生产组合方式
推荐把三者放在不同职责层,而不是强行三选一:
text
ACL/Metadata 硬过滤
→ 每路召回 Top-K 上限 k_recall
→ 融合、去重
→ Top-K 上限 k_rerank
→ Reranker 得到同口径分数
→ 可选 Threshold 质量门禁
→ 可选 AutoCut 动态分组
→ Top-K/Token Budget 上限 k_context
→ final_context 或无证据拒答- 默认可靠基线:Top-K 硬上限 + 去重 + Token Budget;先建立可复现的质量、延迟和成本基线;
- 高风险问答:在经过标注集校准的 Reranker 分数上使用 Threshold,再用
k_context_max封顶;没有候选时明确拒答或转权威工具; - Query 分数尺度变化明显:在同一排序通道内评估 AutoCut,同时保留 Top-K 上限和多跳查询旁路;不能直接对未经校准的 BM25、余弦和 RRF 原始分数混用一个断点;
- 允许组合时:先用 Threshold 删除绝对不合格证据,再用 AutoCut 找自然分组,最后由 Top-K 和 Token Budget 封顶;若离线评测证明组合造成过度截断,应只保留其中一个质量策略。
选参必须固定语料、Embedding/Reranker、索引、查询集和 ACL,按查询类型分桶扫描 k、threshold 与 jump_count,同时比较 Recall@K、Precision@K、MRR/nDCG、必要证据进入 final_context 的比例、空召回率、答案正确性/引用支持率、平均上下文 Token、P95/P99 和成本。任何模型或融合版本变化都要重新校准,不能沿用旧阈值或旧断点结论。
5.7 多样性与 MMR
为了避免多个近重复 Chunk 占满上下文,可以用 Maximal Marginal Relevance(MMR)迭代选择:
是候选; 是已选集合; - 第一项奖励相关性,第二项惩罚与已选结果重复;
越大越偏相关,越小越偏多样。
MMR 适合多方面问题,但单一精确事实可能不需要多样性。不要不分查询类型统一启用。
5.8 可视化辅助
图 1:从查询到最终上下文的检索漏斗
替代文本: 用户查询先经过受控规范化和可信过滤条件,然后并行进入 BM25 与稠密检索;候选经 RRF 融合、Cross-Encoder 重排、去重与上下文预算,最后送入生成模型。每层都保留指标和候选快照。
图表加载中…
读图结论: 检索优化是有可观测中间结果的漏斗;只有保存每层候选,才能判断优化或退化发生在哪里。
5.8 排序指标
Recall@k
衡量候选覆盖,定义见 RAG 基础链路。
MRR
若第一个相关结果排名为
若没有相关结果,该查询倒数排名记 0。MRR 强调“第一个正确证据尽快出现”,不衡量后续多个相关结果。
nDCG@k
对于有分级相关性
IDCG 是理想排序的 DCG。nDCG 适合“多个证据具有不同相关等级”,但需要可靠的分级标注;若 IDCG 为 0,应按评测约定处理而不是除零。
指标边界:
- 只看 MRR 可能掩盖第二个必要证据缺失;
- 只看 Recall@k 可能允许正确证据排在末尾;
- 离线相关性与最终答案价值不完全相同;
- 应按精确实体、同义问法、多跳、否定、时间和无答案查询分桶。
5.9 复杂度与容量边界
设两路各返回
- RRF 时间与候选总数近似线性:
; - 去重若用哈希主键可近似
,语义去重则需要额外相似度计算; - Cross-Encoder 重排
个候选约为 ; - 多查询生成
个改写会放大查询编码、检索和融合成本,粗略随 增长; - MMR 朴素实现需要反复比较已选与未选候选,最坏可接近
次相似度计算; - Metadata Filter 的代价依赖索引是否原生支持;先取全局 Top-k 再过滤可能既漏召回又不安全。
优化目标是质量、延迟、成本和安全的约束优化,不存在脱离数据分布的“最佳 k、阈值或融合权重”。
6. 实现与代码
6.1 最小可运行混合检索
以下示例只依赖 Python 标准库,实现:
- 可信 tenant 预过滤;
- BM25 词项召回;
- 教学用词频余弦“dense-like”召回;
- RRF 排名融合。
第二路并不是真正神经网络 Embedding,只用于让融合流程可离线运行;生产环境替换 dense_scores 即可。
python
import math
import re
from collections import Counter
from dataclasses import dataclass
@dataclass(frozen=True)
class Document:
doc_id: str
tenant: str
text: str
def tokenize(text: str) -> list[str]:
return re.findall(r"[a-z0-9_-]+", text.lower())
def bm25_scores(query: str, docs: list[Document],
k1: float = 1.2, b: float = 0.75) -> dict[str, float]:
tokens = [tokenize(doc.text) for doc in docs]
if not tokens:
return {}
query_terms = list(dict.fromkeys(tokenize(query)))
avgdl = sum(map(len, tokens)) / len(tokens)
df = {
term: sum(term in set(doc_tokens) for doc_tokens in tokens)
for term in query_terms
}
result = {}
for doc, doc_tokens in zip(docs, tokens):
tf = Counter(doc_tokens)
score = 0.0
for term in query_terms:
idf = math.log(1 + (len(docs) - df[term] + 0.5) / (df[term] + 0.5))
denominator = tf[term] + k1 * (
1 - b + b * len(doc_tokens) / max(avgdl, 1e-12)
)
if denominator:
score += idf * tf[term] * (k1 + 1) / denominator
result[doc.doc_id] = score
return result
def dense_like_scores(query: str, docs: list[Document]) -> dict[str, float]:
"""教学替身:词频余弦;生产中换成 Embedding + ANN。"""
q = Counter(tokenize(query))
q_norm = math.sqrt(sum(v * v for v in q.values()))
result = {}
for doc in docs:
d = Counter(tokenize(doc.text))
d_norm = math.sqrt(sum(v * v for v in d.values()))
dot = sum(v * d.get(term, 0) for term, v in q.items())
result[doc.doc_id] = dot / (q_norm * d_norm) if q_norm and d_norm else 0.0
return result
def ranking(scores: dict[str, float], limit: int) -> list[str]:
return [
doc_id
for doc_id, score in sorted(
scores.items(), key=lambda item: (-item[1], item[0])
)
if score > 0
][:limit]
def rrf(rankings: list[list[str]], c: int = 60) -> list[tuple[str, float]]:
fused: dict[str, float] = {}
for result in rankings:
for rank, doc_id in enumerate(result, start=1):
fused[doc_id] = fused.get(doc_id, 0.0) + 1.0 / (c + rank)
return sorted(fused.items(), key=lambda item: (-item[1], item[0]))
def hybrid_search(query: str, tenant: str, all_docs: list[Document]):
# 安全边界:可信 tenant 先限制可见文档,不让越权候选进入融合。
visible = [doc for doc in all_docs if doc.tenant == tenant]
sparse = ranking(bm25_scores(query, visible), limit=5)
dense = ranking(dense_like_scores(query, visible), limit=5)
return rrf([sparse, dense]), sparse, dense
if __name__ == "__main__":
documents = [
Document("a1", "team-a", "ERR-42 means payment signature timeout"),
Document("a2", "team-a", "payment request timeout troubleshooting"),
Document("b1", "team-b", "ERR-42 private incident report"),
]
fused, sparse, dense = hybrid_search(
"ERR-42 payment timeout", "team-a", documents
)
print("bm25:", sparse)
print("dense-like:", dense)
print("rrf:", fused)
assert all(doc_id != "b1" for doc_id, _ in fused)6.2 关键实现说明
- tenant 过滤来自函数参数,真实系统必须从认证上下文而不是用户文本取值;
- BM25 使用去重后的查询词,避免同一 query term 在简单实现中重复累加;
- RRF 用稳定 doc_id 去重,不直接相加不同量纲分数;
- 排名相同的边界用 doc_id 作为确定性次序,便于测试重放;
- 生产中还要记录每路 rank/score、过滤条件、索引版本和最终上下文;
- 如果向量库只支持检索后过滤,必须评估召回缺失与安全风险,必要时按租户分区索引。
6.3 边界条件与验证
可执行验证:
- team-a 查询绝不能返回 b1;
- 删除精确错误码后,观察语义路是否仍能召回故障说明;
- 添加大量长文档,验证 BM25 长度归一化与排名;
- 两路候选完全不重合时,检查 RRF 排序是否符合定义;
- 某路返回空列表时,融合仍可工作;
- 把同内容复制成多个 Chunk,观察重复候选为何要在重排前治理。
生产替换稠密检索后,使用精确向量检索或标注结果作为小规模基线,分别评估 ANN 近似损失与 Embedding 语义损失。
6.4 技术栈与横向选型
检索优化的主体是可分层评测的召回漏斗,不是单一引擎名称。下表将稀疏、稠密、融合和重排拆成稳定 TP;任何产品选择都要在同一语料、ACL、查询集、候选数和硬件下比较。
| 技术点 ID | 技术点/环节 | 类型 | 采用方案 | 链路职责 | 版本/证据边界 |
|---|---|---|---|---|---|
| TP-RO-01 | 稀疏候选召回 | 检索服务 | 通过 Adapter 封装 OpenSearch/Elasticsearch BM25,不让业务绑定 DSL | 命中专有名词、代码、缩写和精确词项,输出独立 Rank | 分词、Analyzer、BM25 参数与版本都会影响排序;不假定两产品默认值相同 |
| TP-RO-02 | 稠密 ANN 召回 | 向量检索服务 | Qdrant 作过滤型参考;Milvus 作大规模候选 | 使用查询向量与 ACL/元数据过滤召回语义候选 | ANN 索引、过滤、一致性和容量配置需在真实数据上实测 |
| TP-RO-03 | 多路结果融合 | 算法 | RRF 作默认无量纲基线;加权分数融合作可校准候选 | 去重并把稀疏、稠密排名合成一个候选序列 | RRF 的 k 与加权权重都需固定评测集;不宣称某策略永久最优 |
| TP-RO-04 | Cross-Encoder 重排 | 模型/服务 | 本地 Sentence Transformers CrossEncoder 作可控参考;托管 Rerank API 通过 Adapter 作候选 | 对有限候选的 Query-Document 对精排,为上下文预算提供顺序 | 模型领域、截断、候选数和批大小影响质量与延迟 |
| TP-RO-05 | 排序候选截断 | 算法/检索算子 | Top-K 作各阶段硬上限;校准后按风险选 Threshold 或 AutoCut | 控制召回、重排和最终上下文的候选数量、证据门槛与动态分组 | AutoCut 以 Weaviate 官方语义作参考;跨引擎定义、分数方向和能力必须按锁定版本核对 |
| 技术点 ID | 候选方案 | 优点 | 缺点/代价 | 适用场景 | 不适用场景 | 选择结论与依据 |
|---|---|---|---|---|---|---|
| TP-RO-01 | OpenSearch BM25 | 开源搜索服务,倒排、Analyzer、过滤和集群能力完整 | 需运维集群、词典和 Mapping,分词升级会引发重建索引 | 已采用 OpenSearch 或需开源可控搜索平台 | 数据小且单机全文检索已满足 | 不因“开源”自动选择,用运维基线与词项召回证据决策 |
| TP-RO-01 | Elasticsearch BM25 | 检索生态、工具与托管选择丰富 | 许可、托管成本、版本与运维策略需单独评估 | 现有 Elasticsearch 平台、索引治理与团队经验已成熟 | 仅为 RAG 原型便新建重型集群 | 优先复用已验证平台,同语料检查 Analyzer 与排序差异 |
| TP-RO-02 | Qdrant | 服务化边界直接,向量与 Payload 过滤结合 | 新存储引入备份、容量与升级成本 | 过滤丰富、中等规模在线向量搜索 | 需超大规模独立资源组与复杂分布式调优,但未做容量测试 | 作过滤型基线,根据 p95、Recall@k、容量与运维演练决策 |
| TP-RO-02 | Milvus | 面向大规模向量数据的分布式与索引选择丰富 | 组件、资源与运维复杂度较高,小规模可能过度设计 | 数据与吞吐已超过简单服务基准、团队有分布式运维能力 | 小数据、低运维预算或尚无容量证据 | 仅在压测证明 Qdrant/现有存储无法达标时升级 |
| TP-RO-03 | RRF | 只使用名次,避免直接混合不同量纲分数 | 忽略原始分数置信度,k 与候选深度仍需调优 | 多路分数不可比、需稳定首个混合基线 | 已有可信校准分数且业务需显式权重 | 默认无量纲基线,用分查询类型的 Recall/nDCG 验收 |
| TP-RO-03 | 归一化加权分数 | 可显式表达稀疏/稠密信号权重,可按查询类型调节 | 分数分布漂移会破坏归一化,维护和校准成本高 | 有标注数据、分数稳定且查询路由可解释 | 无评测集或索引/模型频繁升级 | 只在相比 RRF 的切片收益稳定且可监控时采用 |
| TP-RO-04 | Sentence Transformers CrossEncoder | 本地权重、批处理和数据边界可控 | 需 GPU/CPU 容量、模型选型和推理运维 | 敏感数据、稳定负载、需自训或领域模型 | 请求少、无模型运维能力或突发弹性为主 | 作可控基线,通过候选数、批大小和超时降级测试验收 |
| TP-RO-04 | Cohere Rerank API | 托管接口减少本地模型运维,接入速度快 | 数据出域、限流、成本和版本能力边界需持续复核 | 合规允许、弹性负载和快速建立重排基线 | 严格数据驻留、无外网或必须自训领域模型 | 只作 Adapter 后的参考服务,在质量、延迟、成本与合规同时达标时采用 |
| TP-RO-05 | 固定 Top-K | 确定、简单,能建立延迟、重排和 Token 容量上限 | 无答案也可能返回噪声,无法表达绝对质量 | 各阶段候选上限、稳定基线、固定 UI 槽位 | 单独承担高风险证据准入 | 始终保留为资源上限,K 由分层评测而非经验常数决定 |
| TP-RO-05 | 固定分数阈值 | 允许零结果,可形成明确最低证据线 | 高度依赖分数方向、校准、模型和查询分桶 | 校准后的 Reranker、无答案拒答、高 Precision 场景 | 未校准异构原始分数、频繁换模型和融合策略 | 只有校准误差、误拒和漏放均达门禁才启用,版本变化重新标定 |
| TP-RO-05 | AutoCut / 分数跳变截断 | 按本次查询的相对分布动态选择结果组,弱化跨查询绝对尺度差异 | 无明显 Jump、多意图或重复候选时不稳定,仍需候选上限和参数 | 分数组明显、期望 Query-dependent K、已完成分桶评测 | 平滑分数曲线、多跳召回或必须保证固定证据数 | 作为 Top-K 上限内的可选动态策略,与固定基线做受控对照后决策 |
6.5 架构与技术调用流程
图:架构|混合检索漏斗与降级边界
替代文本: 查询和可信 ACL 条件先经过路由,再并行调用 BM25 和稠密 ANN,候选经去重、RRF/加权融合、Cross-Encoder 重排和上下文预算后进入生成,每层均保存版本、候选快照与超时指标。
图表加载中…
读图结论: 混合检索不是把两路 Top-k 简单拼接,而是一条可独立评测、限时降级和重放的多阶段漏斗。
架构图要求每层保留输入候选、输出候选和版本指纹。否则线上答案变差时,无法区分是查询路由、召回、融合、重排还是上下文截断导致。
图:技术调用流程|双路召回、超时降级与重排
替代文本: 检索编排器并行调用稀疏与稠密召回,单路超时时只在另一路证据达门槛时降级;融合后调用重排,重排超时可回退融合顺序,两路都失败或无候选时必须拒答。
图表加载中…
读图结论: 单路超时可否降级由证据门槛决定,不是“有结果就继续”;重排失败可回退排序,但必须暴露降级信号。
时序图表达了查询级故障隔离。应按稀疏、稠密、融合和重排分别记录耗时、候选数和版本,避免只看总延迟与最终答案。
7. 实际项目案例
示例项目,非本仓库真实业务;不虚构检索提升、延迟或数据规模。
7.1 背景、目标与约束
产品支持助手需要检索多个版本的 API 文档、错误码手册和变更说明。查询类型包括:
- 精确错误码与字段名;
- 用户自然语言描述的同义故障;
- 指定版本、地区和产品线;
- 新旧文档有冲突;
- 多租户私有排障记录。
目标是必要证据进入有限上下文,并保证版本和租户正确。
7.2 架构与调用链
该案例直接复用 6.5 架构与技术调用流程 的组件边界,不另画一条重复漏斗。落到产品支持助手时,调用顺序具体表现为:
- 认证服务生成可信的租户、角色和可访问产品范围,Query Router 只消费该授权上下文;
- 路由器根据错误码、字段名或自然语言故障选择 BM25、Dense 或混合召回,并把版本、地区和产品线作为硬过滤;
- 两路候选进入 RRF、同源去重和有限候选截断,Cross-Encoder 超时时退回融合顺序;
- 父段落展开和 Token Budgeter 只处理已授权候选,最后把真实上下文与 Citation ID 交给 LLM;
- 每一步把候选快照、索引与模型指纹、降级原因和最终引用写入同一条 Trace。
Trace 保存:
- raw_query 与 normalized_query;
- 过滤条件来源;
- 每路候选、rank、score 和 index_version;
- 融合与重排结果;
- 最终实际上下文;
- 生成引用与评测标签。
7.3 方案选择与实现难点
- 错误码和字段名保留 BM25,不只依赖 Embedding;
- 自然语言故障描述由 Dense 补召回;
- 多路分数未校准时先用 RRF,后续有足够标注再评估学习排序或加权融合;
- Reranker 只处理受限候选并设置超时,超时降级到融合排名;
- 时间和版本过滤是硬约束,不让 Reranker 用“语义相关”覆盖;
- 多查询只对已识别的语义型问题开启,并保留原查询结果。
7.4 异常处理、监控与测试
| 现象 | 根因 | 解决 | 验证 |
|---|---|---|---|
| 错误码查询零召回 | 分词拆坏标识;只走 Dense | keyword normalizer;字段级 BM25 | 精确实体查询集 Hit@k;分析器单测 |
| 同义问法召回差 | 领域词不在通用 Embedding 表达中 | 增加 Dense;领域对比集;必要时训练检索器 | 同义分桶 Recall@k,不只看总体 |
| 改写后查到别的问题 | rewrite 丢否定/版本条件 | 保留原查询并行;规则校验关键实体 | 原意保持测试;漂移样本回放 |
| 过滤后无候选 | 过滤值映射错误;先 Top-k 后过滤 | 过滤词典和类型校验;原生 pre-filter | 过滤前后候选数;已知版本金标 |
| Rerank 后正确结果下降 | 输入截断;领域不匹配;标签偏差 | 保存 pair 输入;调候选文本;回滚模型 | 比较 rerank delta 和 nDCG;失败对 |
| p95 延迟突增 | 多查询放大;Reranker 队列或超时重试 | 预算与并发上限;批处理;超时降级 | 分阶段延迟、队列深度、调用次数 |
| 未授权结果进入候选 | ACL 来自用户参数;缓存未分域 | 认证上下文强制过滤;缓存键含权限版本 | 越权测试;Trace 审计;撤权回归 |
7.4.1 故障演练:Reranker 队列拥塞导致 P99 和重试同时上升
- 现象与影响:Recall 指标稳定,但在线 P99 突增并出现超时;客户端和编排层重复重试,进一步占满 Reranker 队列。
- 定位证据:按 request_id 查看 sparse、dense、fusion、rerank、context_build Span,关联候选数、batch、队列深度、超时和重试次数。
- 根因:候选 K 或多查询数量扩大,Cross-Encoder 吞吐不足;多个层级各自重试且没有共享总时间预算。
- 临时止损:停止扩量,降低 rerank top_n 和并发;Reranker 超时直接降级到 RRF 顺序,不在同步路径无限重试。
- 长期修复:建立候选与延迟预算、长度感知批处理、队列限流和熔断;所有阶段共享 deadline,并把降级结果从正常质量指标中分桶。
- 回归验证:在同一查询集和硬件上压测候选 K、并发与失败注入,检查 Recall/nDCG、P95/P99、队列和降级率同时满足门槛。
- 防复发:监控分阶段尾延迟、队列等待、候选数、重试放大率和降级率;检索参数或模型更新必须通过质量—性能双门禁。
监控不能只有端到端时长,应拆 query_rewrite、sparse_search、dense_search、fusion、rerank、context_build。质量指标按 query_type、tenant(合规聚合后)、language、version_filter 和 answerability 分桶。
7.5 结果与复盘
发布一个检索变化前:
- 在固定证据标注集比较 Recall@k、MRR、nDCG;
- 检查端到端答案质量,没有因噪声增加而下降;
- 对精确实体、同义、多跳、否定、时间、无答案分别报告;
- 压测 p50/p95/p99、Reranker 队列、超时和成本;
- 运行越权、撤权和缓存隔离测试;
- 灰度时按版本观测,能够回滚旧索引与旧检索配置。
不能只说“RRF 提升了效果”;必须给出同一评测集、配置版本、样本量和统计不确定性。本文没有真实实验,因此不填写提升数字。
8. 方案权衡与常见误区
8.1 适用与不适用场景
- 混合检索适合同时存在精确实体与自然语言问法的语料;
- Cross-Encoder 适合候选有限且前排质量重要的场景;
- Query Rewrite 适合明显表达差距,不适合高风险精确条件未经约束的改写;
- MMR 适合需要多方面证据的问题,不适合每题只需单一精确句时机械开启;
- Metadata Filter 适合结构化条件,但错误或过细标签会损失召回。
8.2 替代方案
- 倒排字段权重、同义词词典和分析器可解决许多确定性词法问题;
- 专用实体解析器适合错误码、订单号和法规编号;
- 领域双编码器微调可改善 dense retrieval,但需要可靠训练和难负样本;
- Learning to Rank 可学习融合权重,但特征、标签和漂移治理更复杂;
- 小知识库可先用精确搜索建立质量基线,再决定 ANN。
8.3 常见错误回答
- “向量检索比 BM25 高级,所以应替换 BM25”:两者解决不同查询分布;
- “把两路 score 直接相加”:量纲和分布可能不可比;
- “提高 Top-k 就提高效果”:召回、噪声、延迟和 Token 要联合看;
- “Reranker 可以找回没召回的文档”:它只能重排已有候选;
- “过滤放在最后结果一样”:先 Top-k 后过滤会丢失可见候选,权限上也危险;
- “用 LLM 改写一定更懂用户”:改写可能丢失否定、实体和版本约束。
8.4 生产诊断决策树
- 金标准文档未进入任一路候选:
- 查语料/解析/过滤;
- 用精确向量检索排除 ANN 参数;
- 分别看 BM25 分析器与 Embedding 相似度。
- 进入候选但融合后靠后:
- 查候选深度、重复 Chunk、融合参数和 doc_id 映射;
- 融合靠前但 Rerank 降级:
- 重放 query-document 实际输入,查截断、模型和版本;
- 重排正确但最终上下文没有:
- 查去重、父块展开、Token 预算和权限二次过滤;
- 最终上下文正确但答案错误:
- 转到生成忠实度、Prompt 和冲突证据,不继续盲调检索。
8.5 面试方法论:比较五维度、区分三个 K、排查八层证据
面试官连续追问语义检索、关键词检索、Recall/Precision、Top-k、Rerank 和线上故障,本质上不是在考六个孤立名词,而是在判断候选人是否能完成三件事:按统一维度做技术比较、用数据解释参数权衡、沿真实链路定位故障。
8.5.1 比较检索方案时固定五个维度
| 维度 | 关键词检索(Sparse/BM25) | 语义检索(Dense Retrieval) | 面试中应给出的证据 |
|---|---|---|---|
| 匹配信号 | 分词后的词项、词频、逆文档频率和字段权重 | Query/Document Embedding 的向量距离或相似度 | 同一查询的词项命中、向量相似度和候选排名 |
| 擅长问题 | 错误码、产品名、字段名、精确短语和稀有实体 | 同义改写、口语描述、词面不重合的语义问题 | 按精确实体、同义问法、否定和多语言分桶的 Recall@k |
| 主要短板 | 分词或拼写变化可能导致漏召回,难覆盖纯语义改写 | 领域不匹配可能产生“语义看似接近但事实不相关”,精确实体可能变弱 | 失败样本、Analyzer 输出、Embedding 版本和相似度分布 |
| 工程成本 | 倒排索引、Analyzer、词典和字段设计 | Embedding 服务、向量索引、模型/索引版本一致性和 ANN 参数 | 摄取与查询延迟、索引体积、资源和更新成本 |
| 选择结论 | 作为精确词强基线,不因 Dense 流行就删除 | 用来补充语义召回,不宣称无条件替代 Sparse | 在相同语料、查询集、权限和预算下比较 Sparse、Dense 与 Hybrid |
口述时不要只说“BM25 看关键词,向量检索看语义”。至少补充一个对照例子:ERR_CONN_RESET、API 字段和版本号优先依赖词法;“连接总被远端断开”可能需要 Dense 找到同义故障说明。最后给出条件性结论:业务同时存在精确实体和自然语言改写时,通常先保留两路召回,再用固定评测集决定融合是否值得增加复杂度。
8.5.2 Recall 与 Precision 要落到三个 K
工程中不要把所有候选数量都叫 top_k。至少区分:
k_recall:每路召回保留多少候选,目标是让必要证据进入候选集;过小会漏召回,过大会增加噪声、延迟和后续成本;k_rerank:送入 Cross-Encoder 的候选数,受模型吞吐、输入长度和 deadline 约束;Reranker 只能重排这里已有的文档;k_context:最终进入 Prompt 的证据数或 Token 预算,目标是保留回答所需证据而不是塞满窗口。
增大 k_recall 往往提高或保持 Recall,但不会自动提高最终 Precision。候选噪声可能挤占 k_rerank 和 k_context,切块过细还会产生大量重复高分 Chunk;如果 Prompt 接近窗口上限,关键证据可能被截断或被冲突证据稀释。因此选 K 应做控制变量实验:固定语料、查询集、Embedding、Reranker、Prompt 和模型,扫描不同候选深度,联合观察 Recall@k、MRR/nDCG、上下文必要证据覆盖率、答案正确性、P95/P99、Token 和成本。
60~90 秒口述模板: 我会把优化目标拆成候选 Recall、前排 Precision 和最终答案质量。Sparse 与 Dense 先取
k_recall保覆盖,融合去重后只把k_rerank个候选送给 Cross-Encoder,最终按k_context或 Token 预算构造 Prompt。K 过小会漏证据,过大会引入重复、冲突、重排延迟和窗口挤压,所以我不会报通用固定值,而会在同一评测集上扫描 K,并同时看 Recall@k、排序、答案、尾延迟与成本。
8.5.3 线上排障使用“定界—分层—对照—闭环”
第一步不是调参数,而是固定一个失败 request_id,保存 raw/rewrite query、身份和 ACL、语料/索引/Embedding/Reranker/Prompt/Model 版本、各层候选以及 final_context。然后寻找必要证据第一次消失或被错误改变的位置:
- 权威语料:答案是否真的存在,文档版本和权限是否正确;
- 解析与切块:目标段落是否解析成功,Chunk 是否过细丢上下文、过大被截断,overlap 是否制造重复;
- 索引:内容是否进入当前别名,删除、缓存和多节点版本是否一致;
- 查询处理:规范化或 Rewrite 是否丢失实体、否定、时间和版本条件;
- 召回:每路 candidate_count、rank、score、相似度分布和过滤理由是否异常,必要时用精确向量检索对照 ANN;
- 融合与重排:正确证据是否因候选深度、stable_id、输入截断、模型版本或超时降级而掉队;
- 上下文构造:二次授权、去重、父块展开和 Token Budget 是否把正确证据移除,Prompt 是否发生窗口溢出;
- 生成:若
final_context已包含充分证据,再检查 Prompt、冲突证据、引用约束和模型忠实度。
“偶发检索为空”优先怀疑版本不一致、索引别名或缓存漂移、ACL 过度过滤、依赖超时/降级和节点差异;如果同一请求可稳定复现,再检查切块、Embedding 相似度、ANN 参数和查询表达。“回答跑偏”必须先看正确证据是否进入 final_context:没进入属于检索/上下文问题,已经进入才转向 Prompt 与生成,不能靠继续增大 Top-k 掩盖根因。
修复后要用同一个失败样本重放,并检查相邻查询分桶没有回归;最后把样本、版本、期望证据和断言固化为 EvalCase,把关键 candidate_count、空召回率、截断率、阶段 P99 和降级率纳入告警或 Runbook。
9. 面试题与参考答案
问题 1:关键词检索和语义检索有什么区别?
- 难度:基础;
- 考察点:能否用同一维度比较匹配机制、适用查询、短板和成本;
可直接口述的参考回答: BM25 等关键词检索根据分词、词频、IDF 和字段权重匹配,适合错误码、字段名、版本号和精确短语;Dense Retrieval 用 Embedding 相似度找语义近邻,适合同义改写和词面不重合的问题。前者可能因分词或拼写变化漏召回,后者可能把语义相近但事实不相关的内容排高,所以我通常把 Sparse 当精确词基线、Dense 作为语义补充,再在相同查询分桶上用 Recall@k、排序、延迟和成本决定是否做混合检索。
- 常见错误:只说“一个看关键词,一个看语义”,没有例子、失败模式和验证指标;
- 可继续追问:
ERR_CONN_RESET被 Analyzer 拆坏时怎么处理?通用 Embedding 不理解领域缩写时怎么验证?
问题 2:RAG 如何平衡召回率和精确率,Top-k 应该怎么选?
- 难度:中级;
- 考察点:候选覆盖、噪声、窗口预算与数据化选参;
可直接口述的参考回答: 我不会用一个 Top-k 表示全链路,而会区分
k_recall、k_rerank和k_context。召回 K 太小会漏证据,太大会带来重复、冲突、重排延迟和 Prompt 窗口挤压;因此我会固定语料、模型和查询集扫描不同 K,同时比较 Recall@k、MRR/nDCG、最终证据覆盖、答案正确性、P95/P99、Token 和成本。目标不是单独最大化 Recall 或 Precision,而是在业务质量、延迟和成本约束下找到可解释的 Pareto 选择。
- 常见错误:直接给出固定的
top_k=5,或认为 K 越大答案越准; - 可继续追问:切块变细后为什么可能需要重新选择 K?多跳问题和精确实体问题能否共用一个 K?
问题 3:Top-k 和 Reranker 分别在什么场景使用?
- 难度:中级;
- 考察点:两阶段检索的计算和候选边界;
可直接口述的参考回答: Top-k 是检索阶段的候选截断机制,用于在大规模索引中快速保留高覆盖候选;Reranker 通常是 Cross-Encoder,对有限 query-document 对做更细交互,用来提高前排 Precision。候选规模大、词法和语义多路融合时 Rerank 更有价值,但会增加推理和尾延迟;如果正确证据没进 Top-k,Reranker 无法补回。生产上要限制
k_rerank、设置 deadline,超时回退到融合排名,并通过 rerank delta 与分桶 nDCG 证明收益。
- 常见错误:对全库使用 Cross-Encoder,或把 Reranker 当成召回器;
- 可继续追问:Reranker 输入被截断会出现什么现象?超时后应该重试还是降级?
问题 4:为什么用 RRF,而不是直接相加 BM25 与向量分数?
- 难度:中高级;
- 考察点:异构分数校准与排名融合边界;
可直接口述的参考回答: BM25 分数和余弦相似度的尺度、分布与查询间稳定性不同,未经校准直接相加会让某一路因数值范围占优。RRF 只使用各路 rank,通过倒数排名平滑融合,对异构分数更稳健;代价是丢失原始分数幅度,并受候选深度、重复文档和常数
c影响。有足够标注数据时,可以比较分数校准、加权融合或 Learning to Rank,但不能无条件说 RRF 最好。
- 常见错误:认为 RRF 一定提升效果,或忽略 stable_id 与重复 Chunk;
- 可继续追问:有分级相关性标签后,如何验证学习排序是否值得替换 RRF?
问题 5:线上偶发检索为空、回答跑偏,如何排查?
- 难度:高级;
- 考察点:工程排障顺序、日志字段、数据证据和故障闭环;
可直接口述的参考回答: 我先固定失败 request_id、raw/rewrite query、身份/ACL 与完整版本,寻找正确证据第一次消失的位置。偶发空召回优先比较节点、索引别名、缓存、超时、过滤前后 candidate_count 和版本一致性;稳定空召回再查文档是否存在、Chunk 粒度、Analyzer、向量相似度和 ANN。回答跑偏先看正确证据是否进入 final_context:没进入就查融合、重排、去重和 Token 预算,已经进入才查窗口截断、冲突证据、Prompt 与生成忠实度。修复后重放原样本和相邻分桶,并固化 EvalCase、告警和 Runbook。
- 常见错误:一上来增大 Top-k、换 Embedding 或改 Prompt,没有候选快照和 final_context;
- 可继续追问:同一个 Query 只有某个节点偶发为空,你最先比较哪些字段?
问题 6:多租户检索中为什么不能先检索再过滤?
- 难度:高级;
- 考察点:安全边界与可见候选 Recall;
可直接口述的参考回答: 先跨权限检索会让未授权文档进入候选、缓存或日志,形成泄露面;同时全局 Top-k 可能被不可见文档占满,事后过滤后反而没有足够的可见相关结果。生产链路应由可信服务计算 ACL,在每路召回中 pre-filter,候选返回后二次授权,缓存键绑定完整权限指纹和策略版本,并对撤权、共享变化和同角色不同文档权限做回归。
- 常见错误:只在最终答案 UI 隐藏敏感文本;
- 可继续追问:高基数 ACL 如何在召回正确性、索引体积和延迟之间权衡?
问题 7:Top-K、固定阈值和 AutoCut 应该如何选择?
- 难度:中高级;
- 考察点:候选截断、分数校准、动态 K、证据拒答和容量治理;
可直接口述的参考回答: Top-K 控制固定数量,最适合做召回、重排和上下文的资源上限,但无答案问题也可能强行返回噪声;固定阈值控制绝对质量,适合校准后的 Reranker 和允许空召回的高 Precision 场景,但模型或分数分布变化后必须重标;AutoCut 根据单次查询排序分数的 Jump 动态选 K,适合分数组明显但跨查询尺度变化的场景,不过平滑曲线、多跳问题和重复 Chunk 会让切点不稳定。生产上我通常保留 Top-K 硬上限,在同口径排序分数上按风险选择 Threshold 或 AutoCut,并用 Recall、Precision、空召回率、最终证据覆盖、答案质量、Token 和尾延迟共同验证。
- 常见错误:认为 AutoCut 没有参数或一定优于 Top-K,或者把同一个阈值直接用于 BM25、向量和 RRF 异构分数;
- 可继续追问:为什么多跳问题可能需要保留 AutoCut 的多个分数组?模型升级后如何判断旧阈值还能否使用?
10. 递进追问
- 基础概念:BM25 为什么需要词频饱和和文档长度归一化?
- 原理细节:RRF 如何融合两路排名?它丢失了什么信息?
- 实现边界:Reranker 输入被截断时会出现什么可观测现象?
- 工程权衡:多查询扩展如何同时影响 Recall、延迟、成本和重复率?
- 系统设计:设计一个支持 BM25、Dense、Rerank 灰度与独立回滚的检索服务。
- 项目复盘:离线 Recall@20 上升但线上答案正确率下降,如何逐层定位?
参考回答线索:
- 避免高频词线性支配,并校正长文档偶然命中;
- 按各路 rank 的倒数平滑求和;不保留原始 score 幅度;
- 正确候选进入重排却被降权,实际 pair 文本缺答案,长度分桶退化明显;
- 查询路数放大检索与模型调用,需要预算、并行、去重和类型路由;
- 版本化检索配置、影子流量、层级指标、超时降级和路由开关;
- 查新增候选噪声、重排、上下文截断/冲突和生成忠实度,而非继续增大 k。
11. 实践任务
- [ ] 最小实现:运行第 6 节代码,加入字段权重和版本过滤;
- [ ] 融合实验:用自建查询标注相关文档,比较 BM25、教学 dense-like 与 RRF 的 Recall@k、MRR;
- [ ] 改写实验:制作含否定、版本、缩写和错别字的查询集,检查改写是否保持关键约束;
- [ ] 故障注入:模拟先 Top-k 后 ACL、Reranker 输入截断、某一路超时和重复 Chunk;
- [ ] 性能练习:逐步增加候选 K,记录重排耗时与质量,不预设最优值;
- [ ] 截断实验:在同一标注集上比较 Top-K、Reranker Threshold 与 AutoCut,分桶记录 Recall/Precision、空召回、上下文 Token、答案和尾延迟;
- [ ] 面试口述:用一分钟讲清“召回 → 融合 → 重排 → 上下文”的目标差异。
12. 相关知识与参考资料
12.1 相关知识
- 前置知识:RAG 基础链路;
- 前置知识:Token 与 Embedding;
- 后续主题:RAG 评测与生产工程。
12.2 参考资料
以下均为原始论文、官方文档或官方源码;第 1~8 项访问日期为 2026-07-10,第 9~10 项访问日期为 2026-08-20:
- Robertson and Zaragoza, The Probabilistic Relevance Framework: BM25 and Beyond, Foundations and Trends in Information Retrieval, 2009:BM25 系统推导;
- Cormack, Clarke, Büttcher, Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods, SIGIR 2009:RRF 原始论文;
- Karpukhin et al., Dense Passage Retrieval for Open-Domain Question Answering, EMNLP 2020:稠密双编码器检索;
- Nogueira and Cho, Passage Re-ranking with BERT, 2019:Cross-Encoder 式 Passage Reranking;
- Khattab and Zaharia, ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT, SIGIR 2020:Late Interaction 的质量/效率折中;
- Gao et al., Precise Zero-Shot Dense Retrieval without Relevance Labels, ACL 2023:HyDE 原始论文;
- Elastic, Reciprocal rank fusion documentation:官方 RRF 实现与参数说明;
- sentence-transformers, Cross-Encoder documentation:官方项目的重排实现说明;
- Weaviate, Additional operators: Autocut:官方定义、Jump 参数、
limit联动与 Hybrid Search 边界; - Chouhan et al., heiDS at ArchEHR-QA 2025: From Fixed-k to Query-dependent-k for Retrieval Augmented Generation:固定 K、AutoCut、Elbow 等 Query-dependent K 在特定临床数据集上的受控比较与失败边界。
13. 简明总结
一句话记忆: 检索优化要先用互补检索器“召得全”,再用融合和重排“排得准”,最后在权限与 Token 预算内“送得对”。
- BM25 擅长精确词,Dense 擅长语义,两者通常互补;
- RRF 适合融合不可比分数,Cross-Encoder 只重排有限候选;
- Top-K 负责硬上限,校准 Threshold 负责绝对质量门禁,AutoCut 负责查询内动态分组;三者都必须用分桶评测决定;
- ACL 必须在候选可见性边界内执行,不能生成后再遮盖;
- 面试中必须用 Recall、MRR/nDCG、延迟和端到端答案共同证明优化。