📑 本页目录(点开跳转)
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 前缀、截断率和归一化不对时,应优先修配置。领域训练需要正例、难负例、去重与保留集;点击不是天然相关标签,曝光位置会造成偏差。调温度、负例数量或训练轮数都要看未见文档上的效果。
✅ 检查点
- 为什么 Hit@3=1 不能说明所有证据都找齐?
- 加了重排,一道题改善、总体下降,怎么处理?
- ANN recall 很高但回答很差,下一步看哪层?
展开答案
- 一题可能需要多个文档,Hit 只要求命中一个;应看文档级 Recall 和证据完整性。
- 保留逐题结果,查语种、截断和训练域;在同候选上复测,达不到预定质量/延迟线就不采用。
- 先看精确检索的业务相关性,再定位证据是否被拼入、是否被正确使用;不能只继续调 ANN 参数。
先定义题型和 gold;一次改一个变量;平均数旁边保留退化题;速度、权限和答案质量都要验收。
🔗 接下来去哪
➡️ 下一站:11d · 生成引用与查询诊断。