
向量搜索少算了距离延迟可能下降但对检索增强应用来说漏掉证据也会改变回答。我不想再只画一张“比全量扫描快”的图然后跳过正确性。Faiss索引说明列出Flat、IVF、PQ等索引及存储方式页面编辑日期为2025-07-28不是今年十月新发布。它适合用来理解结构不能替代当前版本、当前数据上的测量。本轮于2026-10-23重新阅读。两处近似要分开看IVF先把向量分到倒排列表查询只探测一部分列表。最近邻如果位于未探测列表后面的距离计算再精确也找不回来。PQ又对向量表示作压缩候选中的排序也可能改变。因此“漏桶”和“桶内距离误差”要分别分析。nprobe增加通常意味着检查更多列表但并不保证每次查询延迟单调也不能消除PQ的全部排序误差。相似度口径更不能混用未归一化的内积和余弦相似度不是一回事。先写一个召回验收下面只用一维点做可手算的反例不实现IVF-PQ。全量精确结果作为ground truth模拟候选列表故意漏掉最近的id1再算recall2。use std::collections::BTreeSet; fn top(query: f32, points: [(u32, f32)], k: usize) - Vecu32 { let mut scored: Vec_ points.iter() .map(|(id,x)| { assert!(x.is_finite()); (id,(x-query).powi(2)) }).collect(); scored.sort_by(|a,b| a.1.total_cmp(b.1).then(a.0.cmp(b.0))); scored.into_iter().take(k).map(|p|p.0).collect() } fn recall(truth: [u32], found: [u32]) - f64 { assert!(!truth.is_empty()); let t: BTreeSet_ truth.iter().collect(); let f: BTreeSet_ found.iter().collect(); t.intersection(f).count() as f64 / t.len() as f64 } fn main() { let all [(1,0.1),(2,0.2),(3,2.0),(4,3.0)]; let truth top(0.0,all,2); let selected [all[1],all[2],all[3]]; assert_eq!(truth, vec![1,2]); assert_eq!(recall(truth,top(0.0,selected,2)),0.5); assert_eq!(recall(truth,truth),1.0); assert_eq!(recall(truth,[2,2]),0.5); println!(recall checks passed; constructed recall20.5); }rustc 1.98.0运行通过构造例的recall2为0.5。重复返回同一id不会多算一次命中。内图演示的是另一个recall1漏检场景两者都是教学示意不是Faiss测评。真正比较时的表格我会固定训练集、查询集、索引训练样本与随机种子Flat参考索引和近似索引采用同一距离定义。先记recallk及其查询分布再记延迟分位数、构建时间和实际内存。训练样本不应该偷偷包含专门为提高分数挑出的测试查询。仅给出平均召回会藏住长尾失败。对RAG可以额外挑一批需要准确法规条款、版本号或函数签名的查询查看漏检是否造成证据缺失。但这属于应用层实验不能从向量召回数字直接推导模型答案正确率。本轮没有安装Faiss、训练PQ或运行真实向量库已验证的是评估函数和一个反例。等数据与版本固定后才讨论速度。如果召回下降无法接受先调整探测范围或索引设计而不是把它包装成“免费加速”。