LLM 面试备考
首页/RAG

嵌入模型与向量库 Embedding Models & Vector Databases

所属:01-fundamentals / 03-rag
面试权重:★★
来源:通用领域知识(B站「RAG 面试」合集高频);未做一手考证

一句话#

Embedding 模型决定「语义距离」这件事可不可靠(它是一对独立的 bi-encoder,训练靠对比学习 + 难负例挖掘);向量库决定「在几百万~几十亿条里多快找到最近邻」—— 而 ANN 索引的本质,是用可调的召回损失换取数量级的延迟与内存收益,HNSW 与 IVF 是这条权衡轴上的两种典型解法。

为什么重要(面试角度)#

这道题考的是你对 RAG 里那个「黑盒相似度」到底懂多少。面试官通常不会只问「你用什么向量库」,而会顺着往下钻:

  • bi-encoder 和 cross-encoder 在训练目标与推理成本上的差别(见 hybrid-rerank.md)
  • 对比学习里负例的质量为什么比数量重要,hard negative 怎么挖
  • 为什么 query 要加指令前缀(BGE 等模型的 query/document 非对称编码)
  • HNSW 为什么快、M / efSearch 动了会怎样
  • IVF 的 nlist / nprobe 怎么影响召回与延迟
  • 「ANN 不是精确最近邻」—— 你能不能量化它的召回损失

在实际项目里,embedding 模型选错往往比索引参数调错更致命:参数顶多影响速度与召回率几个点,模型域不匹配会让整类问题系统性失效。

核心内容#

Bi-Encoder 的训练目标#

Bi-encoder 把 query 和 document 各自独立编码成向量,相似度用余弦/点积。训练的核心是对比学习(contrastive learning):

  • 正例:语义匹配的 (query, passage) 对。
  • 负例:不匹配的 passage。主流做法是 in-batch negatives —— 把同一 batch 内其他样本的 document 当作当前 query 的负例,几乎零成本地放大负例数。
  • 损失:常见 InfoNCE / 对比损失形式,把「拉近正例、推远负例」变成一个 softmax 分类问题(温度系数 τ 控制分布锐度)。
−log⁡exp⁡(sim(q,d+)/τ)exp⁡(sim(q,d+)/τ)+∑jexp⁡(sim(q,dj−)/τ)-\log \frac{\exp(\text{sim}(q, d^+)/\tau)}{\exp(\text{sim}(q, d^+)/\tau) + \sum_{j} \exp(\text{sim}(q, d_j^-)/\tau)}

Hard negative(难负例) 是关键:随机负例太容易区分,模型学不到细粒度分辨力。真正有用的是当前模型排得很靠前、但不相关的文档 —— 挖法是先用现有模型检索 top-k,再人工/规则筛出其中的「假阳性」作为负例。这也是为什么 embedding 模型的训练通常是迭代的(挖负例 → 训练 → 再挖)。

另一个常见技术是从 cross-encoder 蒸馏:cross-encoder 精度高但慢,把它给出的相关性分数当作 soft label 去训 bi-encoder,是 BGE 等模型常用的做法(细节随模型与论文差异较大,面试里说清"用更强模型蒸馏弱模型"这个思想即可)。

BGE 风格模型与几个常见家族#

BGE(BAAI General Embedding)是中文/多语场景里非常常见的一族 bi-encoder,值得知道的几点:

  • 非对称编码:检索类模型常对 query 加指令前缀(如「为这个句子生成表示以用于检索相关文章:」),document 不加。query 和 document 的编码方式不同,且必须与训练时一致 —— 这是很多人「直接调 API 效果就不好」的原因。
  • 训练分阶段(预训练 + 通用微调 + 任务微调),并大量使用难负例与蒸馏。
  • 多语/长文本变体:如 BGE-M3 走向多语、多粒度(同时支持稠密、稀疏、多向量检索)与更长输入;具体能力以 model card 为准。
  • 横向可比的家族:E5、GTE、text-embedding-ada-002 之后的闭源系列等 —— 选型应在自家语料上跑评测(检索命中率),而不是照抄排行榜,因为榜单数据域可能与你的语料不同。

选型要看的维度:语言覆盖(中英混排)、max length、向量维度(影响内存与检索速度)、是否开源可本地部署、是否有指令前缀约定、以及是否支持微调(领域适配)。

相似度度量与归一化#

  • 常用 cosine 相似度;若向量已 L2 归一化,cosine 与内积(dot product)等价,而点积检索是 ANN 库最擅长优化的形式,所以实践中常常归一化后用内积。
  • 欧氏距离与 cosine 在归一化后单调相关,不要混用训练与检索时的度量。
  • 度量必须与模型训练时一致(模型是对 cosine 训的还是对点积训的),不一致会静默地掉点。

ANN 索引:HNSW 与 IVF#

暴力检索(flat / brute-force)是精确的,复杂度 O(N·d),N 上到百万级就不可接受。ANN(Approximate Nearest Neighbor)用近似换速度:

HNSW(Hierarchical Navigable Small World) —— 基于图的索引:

  • 建多层图,上层稀疏用于「长跳」快速接近,下层稠密用于精细定位;查询从顶层入口点逐层下降。
  • 关键参数:M(每个节点的连接数,越大图越密、召回越高、内存越大)、efConstruction(建索引时的候选队列大小,影响索引质量与构建时间)、efSearch(查询时的候选队列大小,是在线可调的 recall/latency 旋钮)。
  • 优点:召回率高、查询快,efSearch 可在线调;缺点:内存占用高(要存图结构),插入/删除相对麻烦。
  • 直觉:HNSW 像「先坐高铁(上层)到城市,再走街巷(下层)到门牌」。

IVF(Inverted File Index) —— 基于聚类的索引:

  • 先用 k-means 把向量空间聚成 nlist 个簇,每个簇是一个倒排列表;查询时只访问离 query 最近的 nprobe 个簇内的向量。
  • 关键参数:nlist(簇数,经验上常取 ~√N 量级,需实测)、nprobe(探测簇数,越大越接近精确检索、延迟越高)。
  • 优点:内存友好、易与 PQ(Product Quantization) 组合压缩 —— PQ 把向量切成子段分别量化编码,把每条向量的存储从 d×4 字节压到几字节,代价是精度损失。
  • 缺点:簇边界上的点容易漏(边缘效应);nprobe 小的时候召回下降明显。

其他:DiskANN(面向 SSD 的图索引,省内存)、ScaNN、以及各家向量库自研的变体。产品层面 FAISS(库)、Milvus / Qdrant / Weaviate / pgvector / Chroma 等各有取舍,选型主要看规模、是否需要过滤(metadata filtering)、运维成本。

Recall–Latency–Memory 三角#

这三者互相拉扯,任何 ANN 参数调整都是在它们之间移动:

想要 代价
召回更高(HNSW 调大 efSearch/M) 延迟上升、内存上升
延迟更低 降低 efSearch/nprobe → 召回下降
内存更低(IVF-PQ 压向量) 精度下降、召回下降
索引构建更快(efConstruction/nlist 调小) 索引质量下降、查询召回下降

必须能量化召回损失:做法是拿暴力检索的结果当 ground truth,算 ANN 的 Recall@k(ANN 返回的 top-k 里有多少真的在精确 top-k 里)。生产里通常接受 95%+ 的 ANN 召回,剩余用 reranker 和更大的 top-k 兜底 —— ANN 的近似损失与 RAG 的整体召回目标是要一起看的。

什么时候该微调 embedding 模型#

领域术语密集(医疗、法律、金融、内部黑话)场景下,通用 embedding 常常「语义对不上」。这时按性价比排序:

  1. 加 hybrid 检索(BM25) —— 成本最低,先试。
  2. query rewriting —— 把口语改成领域术语。
  3. 微调 embedding —— 用「(query, 正例 doc, 难负例 doc)」三元组在你自己的数据上微调,通常收益最大也最贵(要构造训练对、要重跑全量 embedding、要维护版本)。
  4. 换更强的通用模型 —— 若领域数据不足以微调,换更大/更好的模型可能更划算。

常见面试问法#

Q:bi-encoder 是怎么训出来的? A:对比学习。正例是语义匹配的 (query, doc) 对,负例用 in-batch negatives 和难负例挖掘(用当前模型检索出排名靠前但不相关的文档当负例),损失是 InfoNCE 形式;很多模型还从 cross-encoder 蒸馏软标签。难负例之所以关键,是因为随机负例太容易区分,学不到细粒度分辨力。

Q:HNSW 和 IVF 怎么选? A:HNSW 召回率和延迟更好、efSearch 可在线调,但内存占用高(存图);IVF 内存友好、易与 PQ 组合压缩,适合超大规模或内存受限,但簇边缘点会漏、nprobe 调小召回掉得快。没有普适答案,取决于规模、内存预算和能否接受召回损失 —— 大表 + 省内存偏 IVF-PQ,中小规模 + 要低延迟高召回偏 HNSW。

Q:你们的向量检索是近似最近邻,会不会漏掉正确结果? A:会,这是 ANN 的定义。所以我会(a)用暴力检索做 ground truth,测 ANN 的 Recall@k,通常控制在 95%+;(b)用略大的 top-k + reranker 兜底;(c)把 ANN 召回损失纳入检索层的整体 Recall@k 一起看。关键是知道并量化这个损失,而不是假设向量库给的就是精确 top-k。

Q:向量维度是不是越高越好? A:不一定。维度高理论上表达能力更强,但内存与计算成比例上升,检索变慢;而且高分维度不等于高检索质量 —— 训练目标、数据、难负例质量往往比维度更决定成败。选型要在自家语料上实测命中率,而不是比维度数字。

Q:为什么有时候直接调 embedding API,效果不如预期? A:常见原因:①query 与 document 的编码方式不一致(该加指令前缀的没加);②相似度度量与训练时不一致(该归一化用内积的用了未归一化的欧氏);③max length 不匹配导致截断;④领域不匹配 —— 通用模型对内部术语的语义表示不占优,需要 hybrid 或微调。

易错点#

  • ❌ 认为向量维度越高、模型越大检索就越好 —— 数据域匹配与训练目标更关键。
  • ❌ 忘记 query 侧的指令前缀 / 非对称编码,直接拿模型裸用。
  • ❌ 把 ANN 当精确检索,不知道有召回损失、也不去量化。
  • ❌ 用未归一化的向量做点积,或训练/检索度量不一致。
  • ❌ 一上来就微调 embedding,跳过更便宜的 hybrid 与 query rewriting。
  • ❌ 把某个排行榜名次当作「我们的场景也适用」的依据 —— 榜的数据域可能与你的语料无关。
  • ❌ 引用具体的 BGE / HNSW 参数默认值当定论(版本与实现相关,应以官方文档为准)。

自测#

1. 为什么「难负例(hard negative)」比「更多随机负例」更有价值?

答案

随机负例与正例差异大,模型很容易区分,梯度信号弱,学不到细粒度分辨力。难负例是当前模型排得靠前、但实际不相关的文档,正好落在决策边界附近,逼模型去学「细分差别」。挖法是先用现有模型检索 top-k,筛出众包中的假阳性当负例,然后迭代训练(挖一批、训一轮、再挖)。这也是训练常做成多阶段的原因。

2. HNSW 的 efSearch 和 IVF 的 nprobe 都是「在线旋钮」,它们分别在调什么?

答案

两者都是查询时扩大候选搜索范围以提升召回的参数。efSearch 控制 HNSW 查询时维护的候选队列长度 —— 越大越可能找到真正的近邻、延迟越高;nprobe 控制 IVF 查询时访问的簇数 —— 越大越接近精确检索、延迟越高。共同点:不改索引、可在线按 QPS 压力动态调,是召回/延迟权衡的主要把手。

3. ANN 检索「漏掉」了正确结果,你怎么证明这件事、又怎么缓解?

答案

证明:用暴力(flat)检索在小规模或抽样上算精确 top-k,与 ANN 返回的 top-k 求交集,得到 ANN Recall@k,量化损失。缓解:①调大 efSearch/nprobe(用延迟换召回);②把初筛 top-k 开大,再用 cross-encoder 在更宽的候选池里重排,把 ANN 漏掉的近邻风险摊薄;③换索引类型或增加内存;④若损失集中在某类查询,考虑该查询做精确检索。核心是把近似损失纳入检索层指标统一监控,而不是假设向量库结果就是精确的。

4. 你的语料是企业内部的术语密集文档,通用 embedding 检索效果很差。按性价比给出你的处理顺序。

答案

①先加 BM25 混合检索(成本最低,能救回大量关键词/专有名词匹配);②做 query rewriting,把口语问题改写成含领域术语的查询;③若仍不够,在自有数据上微调 embedding(构造 (query, 正例, 难负例) 三元组),收益最大但要重跑全量索引、维护版本;④或在领域数据不足时换更强的通用多语模型。顺序原则是先改便宜的环节,把微调留到最后。

5. 向量库选型时,除了「能不能搜得快」,还要考虑哪些工程因素?

答案

①规模与内存预算(决定 HNSW vs IVF-PQ);②元数据过滤(metadata filtering) 的性能 —— 生产中几乎都要「先按租户/时间/权限过滤再检索」,过滤与 ANN 的配合方式对性能影响很大;③增删改支持(是否要频繁更新、能否增量 upsert);④运维复杂度与可水平扩展性;⑤部署形态(自建 / 托管,数据合规要求能否出内网);⑥与 reranker、hybrid 检索的集成成本。选型不是纯性能题,而是系统工程与运维的取舍。