详细解释
ANN(Approximate Nearest Neighbor,近似最近邻) 是所有向量检索 / RAG 系统里最”隐身”但最关键的基础设施。假设你有 N 条文档 embedding(N 通常是 100 万到 1 亿),每条向量维度 d=1536。暴力检索(Exact NN)是拿 query 向量和这 1 亿条每一条都算一次余弦距离或 L2 距离 → O(N×d) 运算量,哪怕是 A100 也要几十秒,不可能用在在线 RAG。ANN 的思路非常反人类:“我放弃一点精度,允许返回结果里混入 3% 到 10% 不是真正 Top-K 的邻居,但你能在 10 毫秒内出答案——对 RAG 够用吗?” 实际业务里 99% 的情况答案都是”完全够用,反正 RAG 重排时再把这些假邻居刷掉就行”。
ANN 三大主流索引家族(选型 2025)
| 索引算法 | 代表库 | 原理 | 召回 95% 时的相对 QPS | 内存/磁盘开销 | 构建索引速度 | 最佳场景 |
|---|---|---|---|---|---|---|
| HNSW(层级小世界图) | Faiss IndexHNSWFlat、HNSWlib、Weaviate、Qdrant、Milvus、pgvector HNSW | 构建多层邻近图(Skip List 的图版),查询时从顶层粗找 → 下层精找,每步只看相邻 k 个节点(ef_search)。 | 约 7000 QPS/单 A100 | 高(每向量额外存 M 邻居指针,~80% 向量体积) | 慢(大索引 1 亿条要数小时) | 在线查询密集型(90% 业务首选) |
| IVF / IVF-PQ(倒排聚类 + 乘积量化) | Faiss IVFPQ、ScaNN | 先把向量库用 K-Means 分成 K 个聚类中心(典型 K=1024 至 16384),查询时只去 query 最近的 nprobe 个聚类里做暴力;再加 PQ 把高维向量压成字节码子空间,内存缩 8 到 16 倍。 | 约 4000 QPS | 低(IVF-PQ 可缩到原尺寸 1/16) | 快 | 海量低成本、查询 QPS 不极端高(1 亿向量只给一台机器) |
| DiskANN(SSD 友好) | DiskANN / Microsoft SPTAG、FAISS DiskANN | 用压缩向量直接存在 SSD 上,内存只保留小图导航层;查询用顺序读 SSD,吞吐接近内存 HNSW,成本低 10 倍。 | 约 3000 QPS | 极低(1% 内存 + SSD) | 中 | PB 级超大规模(千万到十亿向量) |
99% 的业务都在用的 HNSW 调参三参数
HNSW 是 2016 年 Yury Malkov 提出的论文算法,至今仍是向量数据库默认选项,因为不用调就能跑出 95% 召回率 + 毫秒级。三个关键超参:
| 参数 | 构建时生效 | 查询时生效 | 推荐值 | 调参口诀 |
|---|---|---|---|---|
| M(每层邻居数) | ✅ 是 | ❌ 否 | M=16(128维)~ M=32(1536维) | 低维(文本 embedding1536 以内)M=16/24;高维(多模态 2048+)M=32/48。越大越准但越吃内存 |
| ef_construction(构建时候选扩展数) | ✅ 是 | ❌ 否 | 200 起步,土豪上 400 | 构建索引慢准程度:100 省钱,200 常用,400 接近精度天花板再涨意义不大 |
| ef_search(查询时候选扩展数) | ❌ 否 | ✅ 是 | 64(低 latency)~ 256(高精度) | 在线服务默认 100;召回不够的 case 就加到 256;低延迟场景缩到 64 |
经验:ef_search >= K(你要找多少条就至少扩多少条)。典型 RAG 取 top_k=20,ef_search 取 100 就够。
召回率 vs 延迟之间的业务折衷
很多同学会卡在”我要 99% 召回 + 1ms 延迟”,这在 ANN 里几乎是自相矛盾的——因为 ANN 的本质就是”你愿意给我多少算力预算,我换给你多少精度”。建议按业务链条分层:
- RAG 粗检索(第一阶段):召回率 ≥ 95%,延迟 ≤ 50ms,top_k=50 → HNSW ef_search=100 即可。
- Rerank 精排(第二阶段):拿 Rerank 模型 把粗检索来的 50 条重排成 3 条给 LLM——只要粗召回真邻居前 3 条都在这 50 条里(概率 ≥ 99.8%),Rerank 一定会把它们提上来。
- 结论:粗检索不用抠 ANN 到 99%,把剩下那 4% 交给 Rerank 去补,整体成本最低、效果最好。
唯元智创 的 RAG SDK 默认就是这样的 Pipeline:Query → HyDE 改写 → Embedding → ANN Top-50(HNSW ef_search=120,默认 97% 召回)→ Rerank Cross-Encoder Top-3 → LLM 生成答案,用户只需要在控制台上开开关即可,不用写任何 ANN 调参代码。
常见问题
pgvector 里用 HNSW 和 ivfflat 怎么选?
WITH (m=16, ef_construction=200) 直接建索引,线上 SET hnsw.ef_search = 100;,几乎没有理由再碰 ivfflat。余弦相似度(Cosine)和内积(Inner Product / dot)选哪个?
我能不能用 brute force 精确检索当 ANN 的兜底?
+> 操作符(精确)跑,延迟也才 5 到 20ms——完全能接受。等向量超过 50 万条以后再换 HNSW,不用上来就上 ANN。Semantic Chunking 把文档切得越精细,向量条数涨得越快——通常 1 万页 PDF 切出来会是 50 万到 200 万条 chunk,这时候你就必须上 ANN 了。