检索、重排与降级编排
本节目标
- 将硬过滤、召回、融合、重排和证据选择分成可观测阶段;
- 区分 candidate window、rerank window 与最终 evidence;
- 为超时、空响应和依赖故障设计安全 fallback;
- 用总 deadline 控制并行、重试与尾延迟。
一条正确排序的候选链
可信身份 → tenant/ACL/状态/有效期过滤
→ sparse 与 dense 召回
→ 融合与 canonical 去重
→ 有限窗口 rerank
→ 上下文选择这里有两个“排序”:
- 硬约束优先级:无权访问、已删除、未发布或已过期的文档先排除;
- 相关性排序:只在合法集合内比较“哪篇更能回答”。
不能用 reranker 的低分替代 ACL,也不能让高相关文档越过权限。
Filter 必须限制“可搜索集合”
将 tenant、角色、资源状态、有效期和授权 revision 作为检索请求的可信约束,而不是把全库近邻返回给应用后再做展示层过滤。可接受的实现包括由检索引擎执行的元数据 filter、按授权域隔离的 collection/namespace,或在受控服务端先求得可检索 ID 集;具体取舍取决于规模和策略复杂度。无论采用哪种方式,都要在 rerank、上下文和 citation 渲染前重检,因为 ACL、墓碑和有效期可能在请求期间或缓存生命周期内变化。
若第三方 reranker 会看到候选正文,它也是数据处理方:只发送当前主体可读、且该服务被允许处理的最小文本窗口,记录模型/区域/保留策略;绝不能以“排序服务需要输入”为由扩大可见数据域。
多路召回
Sparse
BM25/关键词对专名、编号、错误码和逐字短语通常很强,易解释,也可作为模型服务失败时的基线。
Dense
Embedding 检索擅长语义改写,但可能把“同主题却未回答”的内容排得很高。模型、归一化、距离、维度和索引版本必须一致。
结构化检索
时间、类别、产品、文档类型和实体关系有时更适合数据库、倒排过滤或图查询。RAG 不要求所有知识都变成向量。
融合时不要直接混分数
不同召回器的原始分数通常不在同一量纲。RRF(Reciprocal Rank Fusion)用 rank 融合:
其中 r_i(d) 是文档在第 i 个通道的排名,k 是平滑常数。它减少分数校准依赖,但 k、通道权重和候选深度仍需本地评测。
保存每个候选的:
- source/document/chunk/canonical ID;
- 通道、原 rank/score;
- filter revision、index revision;
- fusion rank/score;
- 重排前后 rank 与 reranker revision。
Candidate 不等于 Evidence
| 名称 | 作用 | 常见规模 |
|---|---|---|
| recall window | 第一阶段返回候选 | 较大,优先高召回 |
| rerank window | 送入昂贵模型的候选 | 受延迟/成本限制 |
| output top-n | 重排后的前排 | 较小 |
| selected context | 真正进入生成上下文的证据 | 受预算、去重与覆盖限制 |
若 gold 文档不在 recall window,reranker 无法创造它;若它在重排前排但被 context budget 裁掉,则问题在上下文层。
降级不是“随便返回”
| 故障 | 可接受的候选策略 | 必须保留 |
|---|---|---|
| Dense 超时 | 只用已授权 sparse | degraded 标志与通道缺失 |
| Sparse 失败 | 只用已授权 dense | 关键编号类 query 的风险 |
| Reranker 超时/畸形 | 使用已评测的融合顺序 | 同一安全候选集 |
| 一个分片失败 | 视产品决定部分结果或拒答 | coverage/partial 标志 |
| 所有检索不可用 | 明确暂不可检索 | 不允许自由生成内部事实 |
| 生成服务失败 | 可返回经授权原文片段或拒答 | 产品策略和来源链接 |
Fallback 自己也要测 relevance、权限、延迟和容量。若只在事故时首次运行,它不是可靠方案。
缓存也是一条 fallback 路径
语义缓存、候选缓存和答案缓存能降低延迟,却会把旧的检索决定重新送回线上。缓存值至少要带入生成它的 authorization_revision、source/index generation(或等价快照)、路由/输出模式和到期策略;命中前仍要核验调用者的可见范围。撤权、删除、策略收紧与高风险来源更新应能使相关条目失效或拒绝命中。缓存无法被可靠地按授权和版本隔离时,宁可 miss,也不要返回可能来自另一主体或旧知识快照的答案。
总 deadline 与重试预算
假设端到端预算为 2 秒,可先分配而非写死:
| 阶段 | 示例预算 | 超时策略 |
|---|---|---|
| 路由/改写 | 150 ms | original query |
| sparse+dense 并行 | 350 ms | 保留成功通道 |
| rerank | 250 ms | 融合顺序 |
| 上下文与校验 | 100 ms | 确定性本地处理 |
| 生成 | 900 ms | 拒答/受控重试 |
| 余量 | 250 ms | 网络抖动与序列化 |
这些数字只是分配示例,必须用自己的 p50/p95/p99 测量。重试要遵守剩余 deadline;无抖动的同步重试会在依赖故障时放大流量。
可诊断 trace 示例
{
"retrieved": [
{"id": "S8", "channel": "dense", "rank": 1, "score": 0.82},
{"id": "S1", "channel": "bm25", "rank": 1, "score": 12.7}
],
"reranked": [
{"id": "S1", "rank": 1, "model_revision": "ce-v3"}
],
"selected": [
{"id": "S1", "reason": "top_relevant_current"}
],
"fallback": null
}JSON 不能写入合法行尾注释:retrieved 保存各召回通道自己的 rank/score,reranked 保存模型后的顺序与 revision,selected 说明真正进入上下文的原因,fallback 明确是否启用降级。不同通道的数值不能跨字段直接比较。
分数字段只在各自模型/查询语境内解释;不要看到 12.7 > 0.82 就断言 BM25 更相关。
动手练习
- 为 2 秒预算写出自己的阶段表与理由。
- 在离线项目中运行:
$env:PYTHONDONTWRITEBYTECODE = '1' # 避免运行练习时在知识库写入 Python 缓存。
$script = '.\docs\RAG\examples\offline_cited_qa.py' # 保存离线 RAG 项目脚本路径。
$fixture = '.\docs\RAG\examples\rag-fixture.json' # 保存可复现的严格 fixture 路径。
python -B $script --fixture $fixture inspect --query-id Q-refund --operator-view # 查看无故障时的受保护阶段 trace。
python -B $script --fixture $fixture inspect --query-id Q-refund --failure reranker_error --operator-view # 模拟重排器失败,确认使用已授权融合顺序。
python -B $script --fixture $fixture inspect --query-id Q-refund --failure retrieval_error --operator-view # 模拟检索失败,确认不会自由生成内部事实。- 在受保护的
audit_trace中对比retrieved、reranked、selected、degraded和fallback;真实服务必须先做 operator 身份与审计授权,不能把 CLI 标志本身当作权限。 - 解释为何 retrieval_error 返回拒答,而不是让生成器凭记忆回答。
常见错误
- 对未授权全库先检索、后过滤;
- 混合 BM25、cosine 与模型 logit,却不做校准或 rank fusion;
- 重排返回未知/重复 ID 时仍信任输出;
- fallback 改用了更宽 ACL 或陈旧索引;
- 每个并行分支都独立重试,超过总 deadline;
- 只监控平均延迟,忽略 p99 与 fallback 比例。
自测
- 为什么硬过滤必须先于相关性评分?
- Candidate Recall@window 对 reranker 有什么上限约束?
- RRF 解决了什么,又没有解决什么?
- Reranker 失败时,为何保留融合顺序通常比返回空更合理?
- 哪些情况下应该停止回答而不是降级?
- 缓存命中前为什么仍要检查当前主体、授权 revision 与知识 generation?
小结与下一步
检索编排的目标是形成高召回、已授权、可降级、可诊断的候选链。候选仍不能直接塞满 prompt;下一节处理预算、去重、顺序与冲突:上下文选择与组装。
参考资料
- Karpukhin et al., Dense Passage Retrieval for Open-Domain Question Answering
- Thakur et al., BEIR
- Cormack, Clarke & Büttcher, Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods
- OWASP RAG Security Cheat Sheet:强调 chunk 级 ACL 继承、检索时执行授权,以及缓存可能带来的跨用户泄露和陈旧策略风险。
来源获取日期:2026-07-22。论文中的特定性能数字依赖数据集与实现,本节不把它们外推为本地结论。