首页/AI/RAG 与向量库速查/efSearch 召回与延迟调优
Embedding 与检索50 条

efSearch 召回与延迟调优

efSearch 控制 HNSW 查询时候选队列的长度:数值越大越接近精确搜索、延迟越高;调优时从 32 或 64 起测,在召回曲线趋缓处停下,并把取值写入服务配置固化。

RAG 与向量库速查AI更新于 2026-10-13

efSearch 是什么

HNSW 是图索引:查询时从入口点出发在图上贪心游走,efSearch 决定候选队列的长度——队列越长,越有机会跳出局部最优、越接近精确结果,同时耗时也越长。它是典型的召回与延迟旋钮,调法不是凭感觉取一个值,而是从 32 或 64 起测,画出召回率与延迟随参数变化的曲线,在召回开始变缓的地方停下。取值要写进部署配置固化,避免每次发布都被顺手改动。

基本信息

作用HNSW 查询阶段的候选队列长度
影响数值越大召回越高、延迟越高
调优起点32 或 64,按召回曲线找拐点
区分参数efConstruction 管构建,efSearch 管查询,改错位置不生效
固化方式写入服务配置并纳入回归评测

典型使用场景

  • 检索质量不达标:先看提高 efSearch 能否补回召回,判断是索引参数还是数据问题
  • 延迟超标:在不明显掉召回的前提下逐档下调,找到可接受的平衡点
  • 索引选型对比:同一份数据在 HNSW 与 IVF 上做等召回延迟对比
  • 版本回归:参数改动后必须跑评测集,避免“调快了但答错了”
  • 容量规划:按不同 efSearch 档位实测 QPS 与 p95 延迟,作为扩容依据

用召回率选 efSearch

用召回率选 efSearch
import faiss, numpy as np

d = 128
xb = np.random.rand(50000, d).astype('float32')
q = np.random.rand(200, d).astype('float32')
flat = faiss.IndexFlatL2(d); flat.add(xb)
_, exact = flat.search(q, 10)                  # 精确 top-10 作为基线
index = faiss.IndexHNSWFlat(d, 32); index.add(xb)
for ef in (16, 32, 64, 128, 256):
    index.hnsw.efSearch = ef
    _, got = index.search(q, 10)
    print(ef, recall_at_k(exact, got, 10))     # 记录 (ef, 召回, 平均延迟)

Qdrant 查询期参数

Qdrant 查询期参数
res = client.query_points(
    collection_name='kb', query=query_vec, limit=10,
    search_params=models.SearchParams(hnsw_ef=128))   # 仅在本次查询生效
# 想要全局档位则在集合的 hnsw_config 中设置

参数与收益

efSearch召回延迟适用
16~32偏低最低高并发、允许近似
64~128接近精确中等大多数生产场景的默认档
256+基本等于精确明显上升离线评测或低 QPS 场景
不设(用默认)取决于实现默认值—上线前必须显式确认
efSearch 只影响查询侧,调它不需要重建索引,所以适合作为线上应急手段;但要把它固化成配置并记录版本,否则每次发布都可能悄悄换档。

易错点

  • 只测延迟不测召回,把参数一路调小直到答案质量明显下滑
  • 构建参数 efConstruction 与查询参数 efSearch 混为一谈,改错位置不生效
  • 依赖实现默认值上线,默认档位偏保守而无人知晓
  • 在小规模测试集上选出的档位直接用于生产,数据量放大后召回掉档
  • 调参后未同步更新回归基线,下次发布无法判断质量变化来自哪里

数据来源与参考

  • FAISS wiki(HNSW 参数)
  • Qdrant 官方文档(hnsw_ef 查询参数)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌