这道题问的是检索模块的性能优化,我觉得本质上是在问一个三角权衡:精度、延迟、成本,这三者不可能同时做到最优,落地时必须根据业务场景做取舍。
先说索引层,这是最直接影响检索速度的地方。我一般会按数据规模来选型。可以把HNSW列为候选,但不只按百万级决定;要结合维度、内存、过滤与更新,把M、构建efConstruction和查询efSearch分开评测。但到了亿级,HNSW 的内存开销就太大了,这时候我会切到 [[IVF-PQ]] 或者 HNSW 加 [[Product Quantization]],PQ把向量分成子向量并用码字表示,代码长度取决于子向量数与每码位宽;8倍不是固定压缩比,总内存还含ID、码本与图。质量变化不能预设在1%以内。还有一个容易忽略的点是增量索引,知识库频繁更新时,全量重建代价太高。我会把更新分成新增、修改、删除三类:新增直接增量插入,修改当软删除加新增,删除不原地动图索引,而是维护一个删除标记,后台异步重建。整体用 base 加 delta 双索引,查询时合并过滤。Faiss的HNSW不支持直接删除,软删除与重建是一种方案;其它向量库是否支持修复图结构后的删除,要看具体实现,不能一概断言直接删除必崩。
再来看召回策略。单靠向量检索有时候不够稳,比如用户搜一个很冷门的实体词,向量可能找不到,但关键词能命中。所以我会做多路召回,把向量检索和[[BM25]]或者[[稀疏检索]]结合起来,比如用 [[Hybrid Search]]。召回之后还要粗排加精排,先用 [[IVF]] 快速筛出一个候选集,比如 Top-200,然后用精确距离计算或者 [[Cross-Encoder]] [[重排]]到 Top-10。这一步很关键,能有效提升最终结果的相关性。另外,查询扩展也是个好手段,比如用HyDE先生成假设文档再检索,但它可能偏题,是否更准应做消融并计入额外延迟与成本。
模型和计算层面,我重点做两件事。一个是 [[Embedding]] 量化,裸向量每维FP32、FP16、INT8分别是4、2、1字节,不能把总索引内存都按这个比例折算;近邻分数间隔小或校准不匹配时质量可能明显变化,上线前用一批测试 query 跑一遍 Recall@K,偏差不大就可以切。另一个是缓存,热点 query 的 embedding 和检索结果都可以缓存,尤其高频文档的向量可以预计算好,避免重复推理。批处理推理也能提升 GPU 利用率,把多个 query 拼成一个 batch 送进去。
工程架构上,我会考虑分片和分布式,按业务或者时间分片,每个分片独立建索引,查询时广播到所有分片再合并结果。多副本做负载均衡,避免单点瓶颈。硬件加速方面,[[Faiss]] 的 GPU 版本或者专用的[[向量数据库]]比如 Milvus 都值得用。还有流控和降级,超时了直接熔断,降级成关键词检索兜底,保证系统不挂。
最后我想说一个常见的失败场景:很多人一上来就把所有数据塞进一个索引,结果检索延迟高还经常超时。其实前提是数据分布和查询模式要先分析清楚,比如冷热数据分开,热数据用高精度索引,冷数据用压缩索引或者甚至不建向量索引只做关键词。上线后我会特别关注尾延迟和召回率波动,如果发现某个分片召回率突然下降,大概率是数据更新导致索引不一致,需要回滚或者重建。
还有一个方向值得深入:当业务需要实时更新知识库时,比如订单状态变化,增量索引和缓存失效策略怎么配合才能保证数据一致性?这个在电商客服场景特别常见。
所以我会把检索优化看成一套组合拳,没有银弹,核心是根据业务场景在精度、延迟、成本之间做取舍,上线后持续监控和调优。