← 学习笔记

学习笔记 · 2026-10-07 · 进阶

向量检索:嵌入与近似最近邻(HNSW·Faiss)

向量检索是把句子和文档转换为承载语义的数字坐标(嵌入),并快速找出与问题相近坐标的技术。借助牺牲少量准确率、换取大幅速度提升的近似最近邻(ANN)索引,它可以处理数千万乃至数十亿个向量。

目录
要点
  • 向量检索按“相似的含义”而不是“相同的词”来查找。DPR 表明,即使词语不同,比如问题中的“bad guy”和文档中的“villain”,也能把它们关联起来。
  • 核心是为每个句子预先只计算一次向量的方式(双编码器)。SBERT 将在 1 万个句子中找出最相似句对的时间从约 65 小时缩短到约 5 秒。
  • HNSW 沿多层图从上层(远距离)向下层(近距离)逐层搜索,使得数据增长时搜索成本只按对数级别增长。
  • 借助向量压缩(乘积量化等)和 GPU 并行化,10 亿规模的检索已成为现实;近来研究正转向 SSD 存储、条件过滤、嵌入模型更换等运维问题。
  • 正如 MTEB 结果所示,目前还没有在所有任务上都胜出的嵌入,因此用自己的数据直接评估很重要。

为什么需要:词语匹配检索与缓慢句子比较的局限

长期以来,文档检索的标准是 TF-IDF 或 BM25 这类关键词方法。它们统计问题与文档中相同词语的重叠程度,并通过倒排索引(词→文档列表的表)快速查找。这种方法快速而稳健,但词语不同就会漏掉。DPR 论文(paper)举过一个例子:问题“Who is the bad guy in lord of the rings?”的答案在出现“villain Sauron”的句子里,但“bad guy”和“villain”没有重叠的词,关键词检索很难找到。

用 BERT 这类善于理解语义的模型不就行了吗?问题在于成本。用 BERT 衡量两个句子的相似度,必须把两个句子一起输入模型。根据 Sentence-BERT 论文(paper),要在 1 万个句子中找出最相似的句对,需要约 5000 万次推理,耗时约 65 小时。像检索这样每来一个问题都要立即作答的任务,无法使用这种方式。

还有规模问题。仅 DPR 实验使用的维基百科段落就有 2,100 万个,若是整个网络则有数十亿个。需要一种既按语义比较、又不必对每个问题逐一比较全部文档的方法。分别解决这两个课题的,就是“嵌入”和“近似最近邻检索”。

核心思想:把语义变为坐标,把检索变为“找最近的点”

打个比方,就是把图书馆里的每一个段落都标成一张巨大地图上的点。坐标的设定方式是:意思相近的段落放在附近,意思不同的段落放在远处。这个坐标就是嵌入(Embedding)。实际上它不是二维的,而是由数百维数字组成的列表。有问题进来时,把问题也标在同一张地图上,取出它周围最近的几个点,这就是检索结果。

这里叠加了两个想法。第一,文档坐标只需事先计算一次。问题进来时只需把这一个问题输入模型,因此用 BERT 两两比较所有组合的成本就消失了。第二,为了找到“最近的点”,并不逐一测量与所有点的距离。接受一种大多数时候正确、但偶尔会漏掉一两个的“近似”检索,以此换取速度的大幅提升。这就是近似最近邻(ANN,Approximate Nearest Neighbor)检索。

因此,向量检索的质量分为两层:坐标标得好不好(嵌入模型的质量),以及能否把近的点找回来(索引的召回率和速度)。只有其中一项好,做不成好的检索。

工作原理:建立索引,再用问题检索

先看准备阶段。① 把文档切成检索单位(分块)。DPR 把文档分成等长的段落,并报告说固定长度比自然段落在检索和最终答案准确率上都更好。② 把每个片段输入嵌入模型,转换为向量。③ 把这些向量放入可以快速查找的索引结构中。这一步即使耗时,也可以事先完成。

提问阶段如下。④ 把问题转换为同一嵌入空间中的向量。DPR 使用了问题和段落各用一个编码器的“双编码器”,SBERT 使用了共享同一网络的“孪生(siamese)”结构。无论哪种,都通过训练使两个向量可以用内积或余弦相似度进行比较。⑤ 在索引中找出与问题向量最接近的前 k 个。⑥ 需要时用重排序器重新排序,或交给 LLM 生成答案(RAG)。

索引方式大致分为两类。图方法的代表 HNSW(paper)把向量作为点、近邻关系作为边,构建多层图。每个向量所在的最高层由随机抽取决定,层越高概率下降越快,因此上层的点稀疏、连线长,下层则很密集。检索就像先走高速公路到附近城市,再转国道、小巷一样,从最上层开始,一层层往下,朝更近的方向移动。另一类是把向量空间划分成多个区域(IVF,倒排文件索引),只搜索与问题接近的几个区域;或者像乘积量化(PQ)那样把向量压缩成短编码,以减少内存和计算。GPU 相似度检索论文(paper)讨论的正是在 GPU 上快速完成这种压缩域检索和穷举比较的设计。

这里衡量性能的标准是召回率(recall),即在精确计算得到的真正前 k 个结果中,索引找回了多少个。扩大搜索范围,召回率上升,速度下降。选择这个平衡点是实际运维中的核心调参工作。

向量检索流水线文档集合 → 分块; 分块 → 文档编码器; 文档编码器 → ANN 索引(事先存储); 问题 → 问题编码器; 问题编码器 → 近似搜索; ANN 索引 → 近似搜索(搜索); 近似搜索 → 前 k 个; 前 k 个 → 重排序器·LLM(可选)事先建立的索引提问时文档集合分块切分为检索单位文档编码器片段 → 向量ANN 索引HNSW · IVF+PQ问题问题编码器同一嵌入空间近似搜索查找相近向量前 k 个重排序器·LLM可选步骤事先存储搜索可选
向量检索流水线 上面一行是事先完成的索引工作,下面一行是问题进来时的流程。文档和问题必须位于同一嵌入空间,才能进行比较。

发展脉络:五篇起点论文各自带来的新东西

先看索引方面。HNSW(2016)不再使用以往近邻图方法所依赖的单独“粗搜索”结构,仅靠图就完成检索。它按层划分连接距离的尺度,并从最上层出发,使搜索成本随数据规模呈对数级增长。此外,选择邻居时不是简单取最近的点,而是用启发式方法筛选,在高召回率区间和数据聚集的情况下大幅提升了性能。论文还指出,其结构与跳表类似,便于分布式实现。

GPU 相似度检索论文(2017)重新设计了妨碍充分利用 GPU 并行性的瓶颈,尤其是“选出最小的 k 个(k-selection)”。借助最高可达理论峰值性能 55% 的 k-selection,它实现了比此前 GPU 最佳记录快 8.5 倍的最近邻检索,并应用于穷举比较、近似检索和乘积量化压缩检索。用 4 块 Maxwell Titan X GPU,在 12 小时内构建了连接 10 亿个向量的图。该实现已开源。本文标题中的 Faiss 常被用来指代这一类开源相似度检索库。

嵌入方面,SBERT(2019)把 BERT 改造成孪生·三元组(triplet)结构,生成可直接用余弦相似度比较的句子向量。它把 1 万个句子的比较时间从约 65 小时缩短到约 5 秒,同时保持了准确率。DPR(2020)将其应用于开放域问答检索。此前人们认为,要获得好的稠密向量需要昂贵的额外预训练,但 DPR 仅用问题-段落对训练两个编码器,只靠在一个批次内让所有问题-段落对相互比较这一简单目标,就大幅超过 BM25(Top-5 准确率 65.2% 对 42.9%)。它还确认,检索准确率提升,最终答案准确率也会随之提升。

最后,MTEB(2022)处理的是评估问题。在嵌入只在少数几个数据集上评估的情况下,它用 8 类任务、58 个数据集、112 种语言比较了 33 个模型。结论是“没有一种嵌入方法能在所有任务上胜出”。也就是说,擅长相似度判断的模型,不能保证在聚类或重排序上也强。

DPR:学习得到的语义检索超越词语检索

BM25词语匹配
DPR问题·段落双编码器
开放域问答检索。正确段落进入前 5 个结果的比例。 Source: paper

最新方向:超出内存、带条件的检索、模型更换

最近的研究正从“快速查找”转向实际服务中遇到的运维问题。第一是内存装不下的规模。RaBitQ-SSD(paper)研究的是向量多于 DRAM 容量时,把向量放在 SSD 上进行检索的问题。它指出,图搜索是一步步发现候选的,因此难以事先规划 SSD 读取;而 IVF 会整块读取区域列表,造成浪费。它只把二进制编码的前面一部分放在内存中,用带误差范围的距离估计过滤候选,只从 SSD 读取真正需要的部分。在 90% 召回率下,吞吐量比基于图的方法最高提高 1.74 倍,SSD 页面读取最多减少 3.8 倍;并用一台机器加 SSD 构建并检索了 100 亿个向量的索引。

第二是带条件的检索。实际中常会同时加上过滤条件,比如“2025 年以后的文档中”“这个部门的资料中”。VADER(paper)指出,根据过滤条件放行多少向量(选择度)、过滤条件与向量空间如何交织(相关性),同一个问题的难度会差别很大,需要人工逐一调整参数。它提出“声明式召回率”:用户只需设定想要的召回率目标,预测器在搜索中估计召回率,达到目标就停止搜索;报告称比最好的基线方法最高快 53%,结果质量好 28%。

第三是更换嵌入模型时的成本。DGM(paper)把以下问题作为切入点:图索引的边由构建时的距离决定,因此索引被绑定在特定嵌入模型上。用新模型重新编码,就必须从头重建图。但它观察到,即使模型不同,描述的也是同一批对象,所以从旧图出发走几步,就能到达相当一部分新模型下的真正近邻(残余可达性),并据此提出了更快构建新索引的迁移方法。三项研究都以 HNSW 和 GPU 检索开启的“快速近似检索”为前提,处理规模、条件、变化这些现实约束。

走出内存:SSD 上的向量检索

100 亿个向量索引一台机器 + SSD
最高 1.74 倍吞吐量相比基于图的方法
最多 3.8 倍更少的 SSD 读取在 90% 召回率下
RaBitQ-SSD:只把二进制编码的前面一部分放在内存中,只从 SSD 读取真正需要的候选。 Source: paper
向量检索研究地图 按论文所处理的问题分组。依据中没有论文之间直接继承关系的信息,因此没有用箭头连接。

局限与争议

第一,近似终究是近似。ANN 偶尔会漏掉真正最近的文档。在 RAG 中,如果包含正确答案的段落没有进入前 k 个,LLM 就只能在没有依据的情况下作答,这可能导致幻觉。如何设定并验证召回率目标始终是个难题。VADER 这类研究出现,也正是因为这种调参很难。

第二,稠密检索并不能取代关键词检索。DPR 论文本身就写道,稠密表示与稀疏表示“在设计上是互补的”。它善于找到意思相近的句子,但对于产品代码、人名、精确数字这类需要字面完全匹配的查询,BM25 可能更强。这就是实践中普遍使用将两者结合的混合检索的背景。

第三,嵌入选择没有标准答案。MTEB 报告称没有任何方法能在所有任务上占优。公开排行榜第一的模型,不能保证在自己公司的文档上也排第一。另外,正如 DGM 所示,索引绑定在嵌入模型上,更换模型就会产生全部重新编码和重建索引的成本。模型选择不是一次性的决定,而是关系到长期运维成本。

第四,内存与成本的平衡。图索引很快,但需要把原始向量和边保存在内存中;压缩(量化)减少了内存,但会损失一些距离计算的精度。规模越大,就越需要像利用 SSD(RaBitQ-SSD)那样重新设计存储位置本身。

延伸学习

非专业读者建议先读 SBERT(paper)的摘要。“为什么要事先为每个句子生成向量”,通过 65 小时对 5 秒这一数字一目了然。接着读 DPR(paper)的引言,可以结合例子理解关键词检索与语义检索的区别,以及检索对 RAG 整体性能的影响。

对索引结构感兴趣的开发者,HNSW(paper)是起点。看懂分层结构和邻居选择启发式为什么必要之后,就能大致明白向量数据库的各项配置在调什么。大规模、压缩检索和 GPU 的利用,可以接着读 GPU 相似度检索论文(paper)。

如果要选择嵌入模型,先用 MTEB(paper)建立评估视角;如果面临运维阶段的问题,可按 RaBitQ-SSD(paper,大规模·SSD)、VADER(paper,过滤检索)、DGM(paper,模型更换)的顺序,挑选符合自身情况的阅读。

相关术语

嵌入 向量数据库 语义搜索 混合检索 分块 重排序器 RAG 幻觉

参考资料

奠基论文

最新研究

由 AI 根据所列参考资料撰写并经过审核。详情请查看原始资料。