🏠 总目录📚 本教程 11c · 检索调优实验 ← →
📑 本页目录(点开跳转)

11c · 检索调优:保留失败样本的实验台

⏱ 按实验推进 | 先比较基线,再改一个变量

🎯 一句话

调优要回答“哪类问题改善了、代价是什么、有没有退化”,而不是宣布加了新组件。 本页能实际比较 BM25、中文向量、融合与重排,并导出逐题结果。

🔗 先完成入库与数据治理,环境见共同项目。代码见 lab.py 与 models.py。命令在仓库根目录运行。

🔬 一、让实验产生文件

先跑不需要下载模型的基线:

python examples/knowledge-assistant/lab.py evaluate --report output/rag-bm25.json

安装项目依赖后,下面命令首次下载公开 ONNX 模型,需要联网和额外磁盘空间;不调用付费 API:

python examples/knowledge-assistant/lab.py evaluate --neural --rerank --report output/rag-neural.json

每次评测使用临时数据库,不覆盖日常练习的文档。默认 embedding 为 BAAI/bge-small-zh-v1.5,带中文查询前缀;默认重排器 Xenova/ms-marco-MiniLM-L-6-v2 面向英文,在这里故意测中文迁移是否成立。模型不匹配是可检验的假设,不能因为接口成功就忽略它。

报告包含配置、包版本、模型文件哈希、语料与代码哈希、每道题的候选和最终文档,以及各阶段组合的延迟与质量。模型缓存目录可以用 --cache 指定;离线运行应提前准备权重并记录来源与许可。

本轮看到的反例

2026-09-06 的这套小型开发语料有 20 题,其中 16 题有授权范围内的答案。最终代码复测中,BM25、向量和融合在 K=3 的文档级 Recall 都为 1,而英文重排器为 0.90625(Hit 为 0.9375)。表头与说明一起保留的解析修复也改变了重排结果,体现了上游处理与下游排序之间的关联。这只是小语料结果,绝不是业务准确率 100%。

在型号题中,XR-300 文档反复提到与 XR-200 的差异,可能先于正确的 XR-200 文档被召回;重排修好这一题,却可能弄坏别的中文问题。查报告中的逐题排序,比只看平均数有用。最终复测文件与测量边界见项目说明。

二、先定义题集和指标

题型 构造方法 必须检查
精确实体 相近型号、版本、错误码 XR-200 与 XR-300 不能混答
语义改写 同一需求不同措辞 同义词变化后证据仍命中
多文档条件 报销政策 + 额度表 多个 gold 文档是否同时进入上下文
无答案 语料没有相应政策 能否拒答/澄清,不能硬造 gold
权限负例 普通用户问 HR、租户 A 问 B 候选、引用、生成、缓存均不泄漏
时间变化 旧版与新版、撤权后重问 当前版本优先,旧引用不再被认可

Hit@K 只看是否至少命中一个相关文档;Recall@K 是命中的不同相关文档数除以全部相关文档数。两者只有每题一个 gold 时才会一致。MRR 看第一个正确文档排得多靠前;本项目的 NDCG 用二元相关标签衡量顺序,不冒充细粒度人工相关性评分。

同文档的多个块不能刷高文档召回率。无答案题没有 Recall 的有效分母,本项目返回空指标,另报候选;还需在生成阶段计算应拒答时回答的比例。空测试集应失败,不能显示完美成绩。

这 20 题属于公开开发集。求职项目需要另建保留集:按文档来源、时间或用户会话切分,避免同一问法的改写跨集合;加入难负例,保留双人标注分歧与裁决。先定验收线,再查看保留集结果。反复用保留集调参数,它就变成了开发集。

三、消融只改一个变量

实验 命令中的变化 对照与诊断
候选量 --candidate-k 6 与 12 目标不在候选中时,重排无从补救
最终 K --k 1 与 3 Recall 增益是否抵得过噪声与上下文
切块长度 --chunk-chars 250 与 450 表格保留时可能超目标;实际 token 另测
上下文预算 --context-chars 800 与 2400 候选正确却没进 prompt,属于拼装损失
检索路线 基线与 --neural BM25、dense、RRF 在同题集独立比较
重排 --neural --rerank 候选固定,比较入选文档、顺序和延迟

例如只缩小候选量,输出到另一个文件:

python examples/knowledge-assistant/lab.py evaluate --neural --rerank --candidate-k 6 --report output/rag-candidates6.json

本项目融合用 RRF:每路按名次贡献分数,常数为 60;每路先去重,避免重复项多次加分。它不要求 BM25 与余弦分数同量纲。若改线性加权,先校准分数分布,再用开发集调权重。原始相似度没有通用的“0.8 以上可信”含义。

不要把逐个单因素最佳值直接拼成最终配置。 切块、K、上下文预算有交互;最终组合要再跑全套和保留集,记录退化题。报告失败样本、每题差值和按题型的表现,小样本置信区间应宽,不能多报几位小数制造确定感。

🛑 现在可以停:你已经有可复现的效果对照。数据库岗位再继续看近似检索;模型岗位去看 embedding 数据与训练。

四、向量数据库慢与召回差,要分开测

当前代码对授权候选做精确向量打分,没有实现 ANN。迁移 Qdrant、pgvector 或其他引擎时,先用相同向量、距离与过滤条件的精确搜索建立参照。

参数或机制 影响 实验必须同时记录
HNSW 的 M、构建 ef 图连边、构建开销与内存 构建时间、内存、ANN recall
查询 ef 探索范围 p50/p95/p99 与相对精确搜索的召回
IVF 的 nlist / nprobe 分区与探测范围 不同过滤选择率、冷热点分布
量化 / 磁盘索引 内存与 IO,可能引入近似误差 重评分开关、量化前后误差
filter 前置 / 后置 / 迭代扫描 ACL 与有效候选量 严格过滤下是否不足 K、是否越权
批量写入 / 刷新 / 删除整理 吞吐与新鲜度 写入到可见延迟、查询尾延迟

ANN recall 是“是否找回精确近邻”,业务 Recall 是“是否找回有用证据”。精确近邻本来就不相关时,把 ANN recall 调到 1 也不能让答案变正确。参照 Qdrant 的 ANN recall 测量与AI 全栈的落库章节。

五、性能与模型选型记录什么

分开冷启动与热请求;记录 CPU/GPU、内存、并发、文本 token 长度、模型权重与线程数。对请求做分层抽样,观察检索、重排、首 token、生成和总耗时。16 题的 p95 只是开发观察,不能用来承诺生产 SLO。

先修漏索引、权限错误、分词和型号丢失,再判断是否换模型。语种、领域、query 前缀、截断率和归一化不对时,应优先修配置。领域训练需要正例、难负例、去重与保留集;点击不是天然相关标签,曝光位置会造成偏差。调温度、负例数量或训练轮数都要看未见文档上的效果。

✅ 检查点

  1. 为什么 Hit@3=1 不能说明所有证据都找齐?
  2. 加了重排,一道题改善、总体下降,怎么处理?
  3. ANN recall 很高但回答很差,下一步看哪层?
展开答案
  1. 一题可能需要多个文档,Hit 只要求命中一个;应看文档级 Recall 和证据完整性。
  2. 保留逐题结果,查语种、截断和训练域;在同候选上复测,达不到预定质量/延迟线就不采用。
  3. 先看精确检索的业务相关性,再定位证据是否被拼入、是否被正确使用;不能只继续调 ANN 参数。
⚡ 走神救援

先定义题型和 gold;一次改一个变量;平均数旁边保留退化题;速度、权限和答案质量都要验收。

🔗 接下来去哪

➡️ 下一站:11d · 生成引用与查询诊断。

打卡记录保存在你的浏览器里,首页能看到总进度