别在 Reranker 上死磕,RAG 效果差往往是因为召回阶段就丢了答案
我之前就掉进这个坑里整整三个月。当时为了提升检索精度,我几乎每两周就尝试一套新方案。我从最基础的 BM25 关键词检索开始,升级到混合检索(Hybrid Search),接着又尝试了各种 Cross-encoder 排序模型,甚至为了追求那一点点指标提升,换了四个不同的 Embedding 模型。
结果非常讽刺:每次调整后,我观察到文档的顺序确实发生了变化,但给 LLM 的最终答案依然是错的。
举个具体的实战场景,用户在问一个非常具体的技术问题:“为什么网关拒绝服务 X?”。在我的测试集里,正确答案其实藏在一篇具体的架构文档中。我当时陷入了一种逻辑误区:如果架构文档从第 10 名排到了第 5 名,我就觉得这是“进步”。但现实是,只要正确文档没有进入 Top-K 候选集,或者没有排在最前面,LLM 在处理长上下文时的“中间丢失”(Lost in the Middle)现象会导致它依然忽略掉关键信息,最终给出一个似是而非的错误回答。
这次踩坑让我意识到,排序算法(Ranking)本质上是在已有的候选集里做“优中选优”,它没有能力把一个根本没被选中的文档给“变”出来。如果你在第一步召回时就把正确答案过滤掉了,那么在第二步花再多精力优化 Reranker,也不过是在给一群错误答案“换件衣服”。
现在我对 RAG 检索流程的认知已经完全重构,建议大家在调优时严格按照以下优先级进行排查,不要跳级:
首先是 Selection(筛选/召回)层。这是整个链路的基石,决定了哪些文档有资格成为候选。如果这一步漏掉了正确答案,后面的所有优化都是徒劳。很多时候,问题不在于排序,而在于你的检索策略(比如单纯依赖向量检索)在面对专有名词或特定 ID 时失效了。
其次是 Assembly(组装/切片)层。这是最容易被忽视的环节。信息的索引方式、切片长度(Chunk Size)以及重叠度(Overlap)直接决定了语义的完整性。如果切片策略不对,导致关键信息被截断成碎片,那么即使语义模型再强大,也无法在向量空间中准确地将该碎片与用户问题匹配,从而导致召回失败。
最后才是 Ranking(排序)层。它是在候选集已经正确的前提下,决定谁排第一。这是最后一步,也是最容易被过度优化的部分。
总结来说,如果你发现更换了多种 Reranker 甚至尝试了不同的 Top-K 参数,效果依然没有明显提升,请立刻停止在排序算法上浪费时间。你应该回头检查你的切片策略是否导致了语义碎片化,或者你的召回机制是否在第一轮就丢失了关键文档。记住,召回决定了结果的上限,而排序仅仅是在这个上限之内做微调。