想象你刚到一座拥有一千两百万人口的陌生城市,任务是在今天之内找到一位失联多年的老朋友。最简单的方法是挨家挨户敲门:保证能找到,但敲完最后一扇门时,你可能已经老了十岁。聪明人都会换思路——先打听这座城市的“百事通”,从认识人最多的关键人物问起,再顺着他们的人脉网一层一层往下找。可你马上会撞见一个难题:问的人越多,找到老朋友的概率就越高,但花掉的时间也越长。这其实就是向量检索世界的日常:每一条数据都变成一个高维坐标点,你的查询也变成一个坐标点,系统要在亿万坐标里找出“最像”的那几个。算法只能给你一个近似答案,而你必须在“找得准”(召回率)和“花得少”(延迟)之间反复拉扯。本文就用“找人”这条主线,带你认识 HNSW、IVF 这些检索算法,看懂召回率-延迟曲线,学会拧动“搜索宽度”之类的旋钮,最终在不同业务场景里找到那个刚刚好的平衡点。

岗位关联

学懂召回率与延迟的权衡,你就能在 RAG、电商搜索、推荐系统里科学地选索引、调参数,让系统又快又准——这是向量检索工程师的核心基本功。

目录
  1. 可视化演示
  2. 一、权衡内核
  3. 二、暴力搜索基准
  4. 三、ANN算法家族
  5. 四、召回延迟曲线
  6. 五、搜索宽度调优
  7. 六、多路融合重排
  8. 七、场景配置建议
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示近似最近邻搜索三大核心:HNSW层次化图搜索(多层小世界图从入口点逐层下降efSearch控制搜索宽度)、IVF聚类倒排搜索(K-Means聚类nprobe控制搜索簇数PQ量化压缩)、召回率-延迟权衡曲线(HNSW曲线最优靠左上IVF居中可调Pareto最优),三模式切换理解ANN检索全貌。

本节配有交互动效(进入视口后自动加载,约 3KB)。

'+C1+'

一、权衡内核

找人任务开始前,你得先跟亲戚约定两件事:一是“找到”的标准——老朋友必须出现在你最终交出的疑似名单里;二是“多久”的底线——几点之前必须回来。前者就是召回率,后者就是延迟。没有这两个指标,一切找人策略都无从比较。

在向量检索里,每个数据都变成一个高维空间中的坐标点,查询也变成坐标。检索引擎从海量坐标里挑出“最像”的前 K 个。召回率 Recall@K 就是“真正距离最近的那些点,有多少比例进了前 K 个结果”;延迟则是从收到查询到返回结果的毫秒数,通常由网络往返、距离计算、结果排序三部分叠加而成。两者天然互斥——看得越多越准,但越慢。

找人时你问得越细,名单越接近真相,但时间一分分流走;检索也一样。召回率和延迟就是撑起整个 ANN 世界的两根柱子,所有算法设计、所有参数调优,本质上都是在两根柱子之间找那个“刚刚好”的位置。

Recall@K=∣RK∩TK∣K\text{Recall@}K = \frac{\left|\mathcal{R}_K \cap \mathcal{T}_K\right|}{K}
召回率 = 返回的前 K 个结果中,真正的 K 个最近邻有多少个被找到。分子是两份名单的重叠人数,分母是总人数 K。
  1. 返回集合 R\mathcal{R}_K 是检索引擎实际返回的前 K 个候选的集合。
    RK={r1,r2,…,rK}\mathcal{R}_K = \{r_1, r_2, \dots, r_K\}
  2. 真实集合 T\mathcal{T}_K 是数据集中真正离查询最近的 K 个点的集合。
    TK={t1,t2,…,tK}\mathcal{T}_K = \{t_1, t_2, \dots, t_K\}
  3. 交集运算\cap 统计两份名单重合的人数。
    ∣RK∩TK∣\left|\mathcal{R}_K \cap \mathcal{T}_K\right|
  4. 归一化比例重合数除以 K,得到 0 到 1 之间的召回率。
    ∣RK∩TK∣K\frac{\left|\mathcal{R}_K \cap \mathcal{T}_K\right|}{K}

二、暴力搜索基准

最笨也最可靠的找人是挨家挨户敲门:拿全城户口本从第一户敲到最后一户,保证不漏掉老朋友。向量检索里的暴力搜索(精确最近邻)就是如此:查询向量与库中每一个向量逐一计算距离,排序后取前 K 个。召回率稳稳 100%,没有任何近似。

代价却高得离谱。假设库里有 N 条向量、每条 D 维,算一次距离要做 D 次减法和 D 次乘法累加,总耗时约等于 N×D 次运算。千万条、768 维的向量,单次查询就是几十亿次运算。更糟的是“维数灾难”:维度越高,向量在高维空间里分布越稀疏,任意两点之间的距离趋于平均,精确计算的区分度反而下降——精确变得又贵又“不太有意义”。

所以暴力搜索在真实系统里几乎不可行,但它仍是价值连城的“金标准”:用来离线标注真正的最近邻、衡量 ANN 的召回率、画对比曲线。就像“敲完所有门”没人真干,但它永远是判断其他方案正确性的唯一标尺。

Texact=N×D×topT_{\text{exact}} = N \times D \times t_{\text{op}}
暴力搜索的总耗时 = 数据条数 × 向量维度 × 单次运算耗时。三者相乘,规模一大就彻底失控。
  1. 数据总量 N库里所有向量的条数,对应城市的居民总数。
    NN
  2. 向量维度 D每条向量的特征数,相当于档案里的字段数。
    DD
  3. 单次耗时 t_op计算两个 D 维向量距离的平均时间。
    topt_{\text{op}}
  4. 总耗时 T三个量相乘,就是逐条扫描的总成本。
    Texact=N×D×topT_{\text{exact}} = N \times D \times t_{\text{op}}

三、ANN算法家族

既然不能全城敲门,聪明人各有各的找人策略。有人走“人脉路线”:先认识几个全城最有名的“百事通”,再顺着熟人网一层层往下问——这是 HNSW(分层可导航小世界图)。有人走“行政路线”:把城市划分成片区,先判断人可能在哪个区,再进区细找——这是 IVF(倒排文件)。还有人随身带“速写画像”快速比对——这是 PQ(乘积量化)。

HNSW 把全部向量组织成多层图:顶层节点少、连接稀疏但跨度大,相当于“市长—区长”的关系网;底层节点全、连接密集。查询从顶层开始,每层贪心走向最近的邻居,再进入下一层重复。IVF 用 K-means 把全库聚成 nlist 个桶,查询只探测最近的 nprobe 个桶,桶内再精细排序。PQ 则把向量切成若干子段、各自量化为码本索引,用查表代替完整距离计算。

三者的共同哲学是“用少量召回损失换数量级加速”。就像找人时先锁定几个片区、问几个关键人物,而不是真的敲遍千万扇门。不同策略在不同数据形态下各有胜负,这也为后面画“召回-延迟曲线”埋下伏笔。

T_{\text{HNSW}} \approx L \times \text{ef} \times D \times t_{\text{op}}, \qquadT_{\text{IVF}} \approx \text{nprobe} \times \frac{N}{\text{nlist}} \times D \times t_{\text{op}}
HNSW 的耗时只和层数、搜索宽度有关,与数据总量基本解耦;IVF 的耗时等于“探测的桶数 × 每个桶的平均大小”。
  1. 层数 LHNSW 多层图的层数,约为 log N 量级。
    L≈log⁡NL \approx \log N
  2. 搜索宽度 ef每层贪心搜索时保留的候选数量。
    ef\text{ef}
  3. 桶总数 nlistIVF 用 K-means 把全库划分成的桶数。
    nlist\text{nlist}
  4. 探测桶数 nprobe查询时实际走访的桶数。
    nprobe\text{nprobe}
  5. 单桶规模 N/nlist每个桶平均拥有的向量数。
    Nnlist\frac{N}{\text{nlist}}

四、召回延迟曲线

把各种算法在不同参数下的表现画到同一张图上:横轴是一次查询的延迟,纵轴是召回率。你会看到一条“先陡后平”的曲线:刚开始多花一点时间,召回率蹭蹭上涨;到 90% 以后,曲线几乎变成平地——想再多找回 1% 的真邻居,延迟要翻好几倍。

这条曲线的形态可以用一个简单模型解释。召回率 R 是搜索宽度 ef 的函数:当 ef 很小时,漏检概率高,召回率低;ef 增大,漏掉真邻居的概率 c/ef 不断减小,但减小的速度越来越慢。与此同时,延迟在持续上涨。

工程上把 90% 附近的点称为“拐点”:绝大多数业务把召回目标定在 90%-95%,而不是 99.9%。因为越过拐点后,追最后几个点的召回是“用金子换沙子”。暴力搜索的 100% 召回就像一条遥不可及的水平虚线,时刻提醒你近似算法到底换来了多少速度。

R(ef)=1−cefR(\text{ef}) = 1 - \frac{c}{\text{ef}}
召回率 ≈ 1 − 遗漏常数 / 搜索宽度。ef 每翻一倍,遗漏只减少一半,越往后越难提升。
  1. 函数依赖 R(ef)召回率是搜索宽度 ef 的函数。
    R(ef)R(\text{ef})
  2. 数据常数 c由数据分布决定的常数,c 越大曲线越平缓。
    cc
  3. 漏检概率 c/ef搜索宽度越大,漏掉真邻居的概率越低。
    cef\frac{c}{\text{ef}}
  4. 极限趋向 1ef 趋于无穷时,召回率趋于 100%。
    lim⁡ef→∞R(ef)=1\lim_{\text{ef} \to \infty} R(\text{ef}) = 1

五、搜索宽度调优

在城市找人时,你每到一个“圈子”最多愿意打听几个人?这个“每层问几个人”就是 HNSW 的搜索宽度 ef(ef_search)。ef 越大,每层保留的候选越多,越不容易错过真朋友;ef 越小,步子越快但容易漏。

ef 与延迟几乎成正比:L(ef) = L0 + α×ef,L0 是网络、协议等固定开销,α 是每多考察一个候选的平均成本。而召回率按 1 − c/ef 增长。把两个式子放一起看:延迟线性涨,召回按倒数收敛。所以“拉满 ef”绝不划算——最后那 5% 的召回,要用好几倍的延迟去换。

聪明的工程做法是“先粗后精”:第一轮用低 ef(如 16-32)快速捞出几百个候选,第二轮只对这几百个候选用高 ef 或精确距离细排。这就像先向几个街坊确认“人大概在这一片”,再蹲点细找。线上还可以根据流量动态调 ef:高峰期调低保延迟,低谷期调高提质量。

L(ef)=L0+α×ef,ΔR=c(1ef1−1ef2)L(\text{ef}) = L_0 + \alpha \times \text{ef}, \qquad\Delta R = c \left( \frac{1}{\text{ef}_1} - \frac{1}{\text{ef}_2} \right)
延迟 = 固定开销 + 边际成本 × ef;而召回增量 = c ×(两次 ef 的倒数差)。ef 越大,同样的提升换来的召回增量越小。
  1. 固定开销 L0网络、协议、序列化等与 ef 无关的耗时。
    L0L_0
  2. 边际成本 α每多考察一个候选多花的平均时间。
    α×ef\alpha \times \text{ef}
  3. 线性关系延迟随 ef 近似线性上升。
    L(ef)=L0+α×efL(\text{ef}) = L_0 + \alpha \times \text{ef}
  4. 召回增量 ΔRef 从 ef1 提高到 ef2 带来的召回提升。
    ΔR=R(ef2)−R(ef1)\Delta R = R(\text{ef}_2) - R(\text{ef}_1)
  5. 倒数递减ef 越大,同等的 ef 提升带来的收益越小。
    1ef1−1ef2\frac{1}{\text{ef}_1} - \frac{1}{\text{ef}_2}

六、多路融合重排

每个找人策略都有自己的盲区:人情网在小圈子灵,行政分区在大城市好用。与其赌一个,不如分头行动——同时让几路人马去找,最后把名单合到一起。这就是多路召回:把 HNSW、IVF、关键词、倒排索引等多路结果合并,取长补短。

各路打法给出的“分数”口径完全不同,不能直接相加。RRF(倒数排名融合)给出了优雅的解法:不看分数,只看名次。某条候选在第 i 路结果中排第几名,就贡献 1/(k + rank) 分,其中 k 通常取 60。

融合后一般再挂一个重排模型:对合并出的前 100-500 条用更精细的模型(cross-encoder 或业务规则)重新打分。因为候选规模小,重排成本可控。这样既保留了各路召回的广度,又用精排保证了头部的精度——整体效果往往超过任何单一路径,这也是工业界“粗排+精排”的标准姿势。

score(d)=∑i=1M1k+ranki(d)\text{score}(d) = \sum_{i=1}^{M} \frac{1}{k + \text{rank}_i(d)}
RRF 融合分数 = 各路“1 /(60 + 该文档在本路的名次)”之和。名次越靠前、出现的路数越多,总分越高。
  1. 路径数 M参与融合的召回路数。
    MM
  2. 排名 rank_i(d)候选 d 在第 i 路结果中的名次。
    ranki(d)\text{rank}_i(d)
  3. 平滑常数 k通常取 60,抑制第一名与第二名的巨大差距。
    kk
  4. 求和累加把候选在各路的倒数分数累加。
    ∑i=1M1k+ranki(d)\sum_{i=1}^{M} \frac{1}{k + \text{rank}_i(d)}
  5. 综合含义名次越靠前、出现的路数越多,融合后排名越靠前。
    score(d)\text{score}(d)

七、场景配置建议

同样是找人,任务不同打法完全不同。公安寻人(电商搜索、风控)漏掉一个都是大事,宁可慢一点也要高召回;发传单拉客(推荐系统)每秒几十万请求,必须极限压低延迟;带团找餐厅(RAG 问答)游客等不了太久,端到端必须控制在 1-2 秒内,检索只能分到几十毫秒预算。

配置前先算总账:端到端延迟等于各环节之和。先定产品能接受的端到端时间,再倒推检索引擎能分到多少。典型参考:RAG 场景用 HNSW(M=16、ef=64)即可在 30ms 内拿到 90%+ 召回;电商大库用 IVF(nlist=4096、nprobe=8~16)配合量化,把内存和延迟一起压下来。

上线不是终点。要持续监控 P99 延迟、平均召回率以及下游转化、准确率等指标,用 A/B 实验验证参数调整。向量检索调优是一场长期的“找人”复盘——数据分布变了、业务变了、流量变了,参数就要跟着重新校准。

Ttotal=Tembed+Tretrieve+Trerank+Tgen≤TbudgetT_{\text{total}} = T_{\text{embed}} + T_{\text{retrieve}} + T_{\text{rerank}} + T_{\text{gen}} \le T_{\text{budget}}
端到端延迟 = 查询编码 + 向量检索 + 融合重排 + 答案生成,总和必须小于产品设定的预算。
  1. 查询编码 T_embed把用户问题编码成向量的耗时。
    TembedT_{\text{embed}}
  2. 向量检索 T_retrieveANN 在索引中查找候选的耗时。
    TretrieveT_{\text{retrieve}}
  3. 融合重排 T_rerank多路结果融合与精排的耗时。
    TrerankT_{\text{rerank}}
  4. 生成 T_gen大模型生成答案的耗时。
    TgenT_{\text{gen}}
  5. 预算约束总和必须小于产品设定的端到端阈值。
    Ttotal≤TbudgetT_{\text{total}} \le T_{\text{budget}}

AI 应用场景

RAG 智能问答系统

阶段:检索增强生成(RAG)的知识库召回

解决的问题:传统 RAG 把用户问题与全库向量暴力比对,百万级知识块延迟动辄上百毫秒甚至秒级,问答体验差。用 HNSW 的 ef 旋钮把延迟压到几十毫秒,再配合多路融合重排保住召回。

具体案例:某企业把 500 万条文档块接入 HNSW(M=16、ef=64),P99 检索延迟从 320ms 降到 28ms;同时并行跑关键词和向量两路结果,用 RRF 融合后重排,问答准确率提升 12%,端到端回答稳定在 2 秒内。

电商商品搜索召回

阶段:商品语义向量召回

解决的问题:用户搜“黑色羽绒服”,光靠分词匹配会漏掉语义相近的商品。系统需要在几十毫秒内从千万级商品向量中召回候选,还不能让召回率掉太多。

具体案例:某电商大促期间,用 IVF-PQ 把 2000 万商品向量压到 1/8 内存,nlist=4096、nprobe=16,召回率 92%、P99 延迟 19ms,扛住每秒 4 万次查询;对高价值品类再切一条高 ef 的 HNSW 精标通道。

短视频推荐系统召回

阶段:推荐链路中的向量召回

解决的问题:推荐系统每秒要处理数十万用户请求,召回必须极快,又得保证候选多样性,否则后面的精排模型会“巧妇难为无米之炊”。

具体案例:某短视频 App 用 HNSW ef=32 在 8ms 内为每个用户召回 500 条候选,延迟只占整条推荐链路的 10%;配合向量、热榜、关注等多路召回做 RRF 融合,人均播放时长提升 5%。

Python 演示

python83 行
"""Demo: IVF approximate nearest neighbor search vs brute force.Compare recall@K and latency as nprobe grows."""import mathimport randomimport time  def dist(a, b):    return math.sqrt(sum((x - y) ** 2 for x, y in zip(a, b)))  def kmeans(data, nlist, iters=8):    centers = random.sample(data, nlist)    for _ in range(iters):        buckets = [[] for _ in range(nlist)]        for v in data:            bi = min(range(nlist), key=lambda i: dist(v, centers[i]))            buckets[bi].append(v)        for i in range(nlist):            if buckets[i]:                d = len(data[0])                centers[i] = [                    sum(p[j] for p in buckets[i]) / len(buckets[i])                    for j in range(d)                ]    return centers  def build_index(data, centers, nlist):    index = [[] for _ in range(nlist)]    for idx, v in enumerate(data):        bi = min(range(nlist), key=lambda i: dist(v, centers[i]))        index[bi].append(idx)    return index  def brute_force(q, data, k):    return sorted(range(len(data)), key=lambda i: dist(q, data[i]))[:k]  def ivf_search(q, data, centers, index, k, nprobe):    order = sorted(range(len(centers)), key=lambda i: dist(q, centers[i]))    cands = []    for b in order[:nprobe]:        cands.extend(index[b])    cands.sort(key=lambda i: dist(q, data[i]))    return cands[:k]  def recall_at_k(truth, found):    return len(set(truth) & set(found)) / len(truth)  def main():    random.seed(42)    n, d, k, q_num = 2000, 16, 10, 20    data = [[random.gauss(0, 1) for _ in range(d)] for _ in range(n)]    queries = [[random.gauss(0, 1) for _ in range(d)] for _ in range(q_num)]     nlist = 64    centers = kmeans(data, nlist)    index = build_index(data, centers, nlist)     t0 = time.time()    truths = [brute_force(q, data, k) for q in queries]    t_exact = time.time() - t0    print("brute force: %.1f ms/query, recall = 1.000"          % (t_exact / q_num * 1000))     for nprobe in [1, 2, 4, 8, 16, 32]:        t0 = time.time()        rs = []        for q, truth in zip(queries, truths):            found = ivf_search(q, data, centers, index, k, nprobe)            rs.append(recall_at_k(truth, found))        dt = time.time() - t0        print("nprobe=%2d  recall=%.3f  %.2f ms/query"              % (nprobe, sum(rs) / len(rs), dt / q_num * 1000))  if __name__ == "__main__":    main()
目的:实现一个微型 IVF 索引,对比暴力搜索与不同探测深度 nprobe 下的召回率和延迟,直观复现“召回-延迟权衡”。
  1. bi = min(range(nlist), key=lambda i: dist(v, centers[i]))把每个向量归入最近的桶,相当于给城市居民划分片区。
  2. index[bi].append(idx)构建倒排索引:桶号映射到桶内所有向量的下标。
  3. order[:nprobe]只探测离查询最近的 nprobe 个桶,对应“只走访最可能的几个区”。
  4. cands.sort(key=lambda i: dist(q, data[i]))对桶内候选按真实距离精细排序。
  5. len(set(truth) & set(found)) / len(truth)计算 Recall@K:名单重合数除以真实邻居数。
  6. for nprobe in [1, 2, 4, 8, 16, 32]遍历不同探测深度,观察召回率上升与耗时增长的节奏。

常见误区

误区“把 HNSW 的 ef 调到 1000,召回率接近 100%,检索质量肯定最好,为什么不一直用大 ef?”

正解召回率超过拐点(约 90%-95%)后,每提升 1% 要付出数倍延迟。延迟直接决定用户体验和系统吞吐。就像找人,为了 99.9% 的把握把全城问一遍,客户早走了。正确做法是设定业务目标(如 95%)后,反推满足目标的最小 ef。

为何常见:离线评测常只报召回率单指标,新手容易把单一指标当全部,忽略线上延迟和机器成本。

误区“ef 从 16 涨到 32 召回提升了 5%,那从 32 涨到 64 应该再提升 5%。”

正解召回率随 ef 按 1 − c/ef 的形态增长,增量越来越小;延迟却线性上涨。所以不存在固定增量,越往后性价比越低。必须实测召回-延迟曲线,找到自己的拐点,而不是凭直觉线性外推。

为何常见:人的直觉容易把“投入越多产出越多”套用到所有场景,忽略了收益递减的饱和效应。

误区“HNSW 是最先进算法,召回-延迟曲线全面占优,所以所有场景都该用 HNSW。”

正解HNSW 建图成本高、增量更新复杂、内存占用大;IVF 简单可控、易分布式、支持流式插入。数据规模、更新频率、内存预算、是否用 GPU 等都影响选型。就像找人,人脉法在小圈子高效,分区法在大城市更好并行。

为何常见:业界文章常拿 HNSW 当招牌,容易让人忽略不同场景的约束差异。

误区“同一查询同时走 HNSW、关键词、IVF 三路,延迟一定是原来的三倍。”

正解多路召回通常是并行执行的,总延迟近似等于最慢一路加上融合重排的时间。而且每路可以刻意压低 ef,单路极快,合起来反而比单路高 ef 更划算、召回更稳。

为何常见:把串行思维套到并行系统上,忽略了工程上并行执行与预算分配的作用。

误区“调完算法参数就万事大吉,延迟高就怪 ANN 实现不够快。”

正解延迟还受向量维度、数据类型、索引内存访问模式、网络、序列化、批处理等因素影响。量化压缩、降维、缓存、批量接口往往比调 ef 效果更明显。需要端到端剖析各环节耗时,再决定优化哪里。

为何常见:新手容易把问题局限在算法层,缺乏全链路性能意识。

面试题

Q1. 关于召回率 Recall@K,下列描述正确的是?

单选题 · easy

  • A.返回结果中正确邻居占比← 正确答案
  • B.系统每秒处理的查询数量
  • C.全部数据与查询的覆盖率
  • D.检索过程访问的节点数

答案:A。召回率衡量“返回的前 K 个结果里有多少是真正的最近邻”,对应找人名单中真朋友的比例。B 是吞吐(QPS),C 是覆盖率,D 是访问节点数,都与召回率定义无关。

Q2. 暴力搜索(精确最近邻)的时间复杂度约为?

单选题 · easy

  • A.复杂度 O(N×D),随数据量线性增长← 正确答案
  • B.复杂度 O(logN),随数据量对数增长
  • C.复杂度 O(1),与数据量完全无关
  • D.复杂度 O(N²),随数据量平方增长

答案:A。暴力搜索要把查询与每一个向量各算一次距离,所以耗时约等于 N×D 次运算,随数据量线性增长。B 是 HNSW 的理想形态;C、D 与实际线性扫描的开销不符。

Q3. HNSW 算法通过什么结构实现快速近似检索?

单选题 · mid

  • A.多层小世界图逐层导航← 正确答案
  • B.对向量做聚类分桶过滤
  • C.按位异或的哈希近似比较
  • D.维护一张全局的距离表

答案:A。HNSW 用多层小世界图,从顶层“人脉最广”的节点开始逐层下探。B 是 IVF 的做法,C 是哈希类方法,D 的全连接距离表在大规模下内存不可行。

Q4. 调大 HNSW 的搜索宽度 ef,最直接的影响是?

单选题 · mid

  • A.召回率上升同时延迟增加← 正确答案
  • B.召回率上升同时延迟下降
  • C.召回率下降且延迟保持稳定
  • D.召回率和延迟都基本不变

答案:A。ef 是每层保留的候选数,ef 越大候选越多,找到真邻居的概率上升,但每个候选都要算距离,延迟同步增加。B 的“延迟下降”与机理相反,C、D 与 ef 的作用方式矛盾。

Q5. IVF 索引中 nprobe 参数表示什么?

单选题 · mid

  • A.查询时实际探测的桶数量← 正确答案
  • B.建索引时划分的桶的总数
  • C.每个桶允许容纳的最大条目
  • D.向量量化压缩后的维度数

答案:A。nprobe 是查询时走访的桶数,nlist 才是建索引时划分的桶总数。C 是容量限制,D 是压缩维度,均不属于 nprobe 的语义。

Q6. 召回延迟曲线中“90% 拐点”的工程含义是?

单选题 · hard

  • A.超过该点延迟变贵而召回趋缓← 正确答案
  • B.超过该点召回开始快速下降
  • C.超过该点延迟突然大幅下降
  • D.超过该点两条曲线完全重合

答案:A。召回率随延迟先陡后平,90% 附近继续提升召回需要付出数倍延迟,这就是工程拐点。B“快速下降”、C“延迟骤降”、D“完全重合”都不符合曲线形态。

Q7. 下列哪些手段可以提升低延迟条件下的召回率?

多选题 · mid

  • A.适度增大搜索宽度 ef 参数← 正确答案
  • B.增加 IVF 的探测桶 nprobe← 正确答案
  • C.引入多路召回并做融合重排← 正确答案
  • D.把向量维度全部裁剪成 1 维

答案:ABC。增大 ef、增加 nprobe 都直接扩大候选规模,提升召回;多路召回 + 融合能互补各路盲区。D 把维度裁到 1 维会摧毁语义信息,召回必然暴跌,不是工程手段。

Q8. 关于 RRF 倒数排名融合,正确的说法是?

多选题 · hard

  • A.用排名倒数替代原始分数累加← 正确答案
  • B.各路分数无需统一归一化处理← 正确答案
  • C.结果必须依赖大模型重打分
  • D.排名越靠前对总分贡献越大← 正确答案

答案:ABD。RRF 只看名次不看原始分数,因此各路分数无需归一化,且名次越靠前贡献越大。C 错误——RRF 本身已能完成融合,重打分只是可选的后续精排步骤。

Q9. RAG 问答系统中,向量检索引擎通常需要满足?

单选题 · easy

  • A.端到端回答延迟控制在秒级← 正确答案
  • B.召回率必须严格达到百分百
  • C.不允许使用任何近似检索算法
  • D.检索延迟可以放宽到分钟级

答案:A。RAG 面向用户交互,端到端延迟通常在 1-3 秒内,检索阶段只占几十毫秒。B 追求 100% 召回不现实也没必要,C 排除近似算法不切实际,D 分钟级延迟用户无法接受。

Q10. 关于“高维灾难”对暴力搜索的影响,正确的是?

多选题 · mid

  • A.高维空间中数据分布趋于稀疏← 正确答案
  • B.距离区分度随维度升高而下降← 正确答案
  • C.树形索引在高维下加速失效← 正确答案
  • D.高维下暴力扫描反而更加快速

答案:ABC。维数越高,数据在高维空间中越稀疏,任意两点距离趋于平均,区分度下降,树形等索引加速失效,因此才需要 ANN。D 说高维下暴力扫描更快,与事实完全相反。