这道题问的是[[RAG]]系统里检索模块的完整流程,本质上是在考察「如何把用户的一个自然语言查询,精准、高效地映射到知识库里最相关的文档片段上」。整个链路我拆成四段来说:查询预处理、[[向量化]]、检索、排序。
先说查询预处理。用户输入往往很随意,比如在电商客服场景,用户问「这个多少钱」,你得结合上下文补全商品名。这里有个常用手段叫 HyDE,就是让大模型先生成一个假设的答案文档,再拿这个文档去向量化检索,能大幅缓解查询和文档之间的语义鸿沟。另外我还会做查询扩展,比如同义词替换,或者拆成多个子问题并行检索,但扩展太多会引入噪声,得控制节奏。
第二步是向量化。模型选型上,通用场景用 BGE 或 M3-Embedding 就够了,但如果是垂直领域比如金融合规,最好在领域语料上微调。这里有三个细节:一是截断长度,超了会丢信息;二是要不要加指令前缀,比如「Represent this sentence for retrieval」,加了能提升检索精度,但不同模型要求不一样;三是动态更新,如果用户反馈回流,可以做对比学习微调,让 Embedding 更贴合当前业务。
第三步是向量检索。索引结构我常用 [[HNSW]],它召回率高但吃内存,适合数据量在千万级以内的场景;如果数据上百亿,可以考虑 [[IVF-PQ]],牺牲一点精度换内存。检索参数比如 ef_search 和 nprobe 直接影响延迟和召回率的平衡,上线前我会做压力测试找最优值。另外,前置元数据过滤很重要,比如按时间范围或权限标签先筛一遍,能大幅缩小搜索空间,而不是把几亿条向量全扫一遍。
第四步是候选排序。我一般不会只依赖向量检索,因为稀疏特征比如关键词匹配也很重要。所以会做 [[混合检索]],把向量 + [[BM25]] 的结果线性加权融合,或者用学习模型动态调权。然后[[重排序]],用 [[Cross-Encoder]] 比如 bge-reranker 对 Top-100 精排到 Top-20,这一步很关键,能显著提升最终回答的质量。最后是去噪,设定置信度阈值,低于阈值的直接丢掉,或者对语义重复的聚类去重。
这里有个落地风险:重排序虽然效果提升明显,但二次编码带来的延迟可能是向量检索的几倍。所以实际系统里我倾向做分级处理,快路径只走纯向量检索,慢路径加上重排,根据业务容忍的延迟决定。比如客服场景,用户等不了太久,我会把重排的候选集从 100 截断到 20,甚至直接用轻量模型替代。
另外,我最近在关注一个问题:当知识库频繁更新时,增量索引怎么做才不会影响线上召回质量。比如新增文档直接插入 HNSW 图,但删除和修改如果原地操作,图结构会崩。我的思路是分三类处理:新增直接走增量,删除用软删除加异步重建,修改则视为旧版本软删除加新版本新增。同时维护 base 和 delta 双索引,查询时合并,构建完用固定 query 回放对比 Recall@K,通过才原子切换。千万别原地动图索引,否则召回质量会断崖式下跌。
所以整体上,我会把检索模块看成是一个权衡系统,核心是在召回率、延迟、成本之间找平衡点。没有银弹,关键是根据业务场景做配置和取舍。