RAG 检索优化实战:4 层漏斗让召回、排序、过滤、分层各司其职
【免费下载链接】RAG_TechniquesThis repository showcases various advanced techniques for Retrieval-Augmented Generation (RAG) systems. Each technique has a detailed notebook tutorial.项目地址: https://gitcode.com/GitHub_Trending/ra/RAG_Techniques
如果你正在做 RAG 检索优化,RAG_Techniques 这个开源项目值得翻一遍:混合检索、LLM 重排序、过滤、分层索引四套技术,每个都配了独立的 notebook。这篇文章不按教科书顺序走,而是把这四层串成一条"检索漏斗"逐层拆给你看:每层拦掉什么、出问题时该拧哪个旋钮。
先把翻车现场摆出来:为什么回答总差一步
用户问"怎么重置密码",系统返回 3 段注册流程。模型没变笨,是喂给它的材料错了。检索不准是 RAG 的第一死因——LLM 再强,拿着错误的上下文也答不出正确的事。问题往往不出在生成层,而在检索端:召回漏了、排序乱了、噪声没拦、文档规模把索引打爆。下面按漏斗顺序,一层一层修。
让召回更准:关键词 × 语义的双通道设计
alpha 权重到底怎么调
想象一下,用户搜"退款政策",纯向量搜索吐回来 3 段产品介绍——语义上"很近",但答非所问。这类翻车几乎都出在单通道召回上。
我的习惯是把两条通道分开理解:向量通道像"语义 GPS 定位",不要求字面相同,靠嵌入距离找语义近邻,擅长处理"为什么登录总是失败"这种口语化意图;BM25 通道像"精确词典查词",按词频和文档长度打分,专门抓住型号、报错码、专有名词这种一字不能差的词。两条通道各扫各的盲区。
坑在于两者的分数不同尺度:FAISS 返回的是距离,BM25 返回的是词频加权分,直接相加等于拿米和秒做加法。所以核心动作只有四步:
vector_scores = minmax_norm(vector_scores) # 距离统一映射到 [0,1] bm25_scores = minmax_norm(bm25.get_scores(q_tokens)) combined = alpha * vector_scores + (1 - alpha) * bm25_scores top_k = argsort_desc(combined)[:k]alpha 就是两通道的天平。查什么类型的问题,天平就往哪边压:
| 查询形态 | alpha 参考值 | 主导通道 | 例子 |
|---|---|---|---|
| 型号/版本/报错码密集 | 0.2~0.4 | 词典查词 | "vLLM 0.4.1 怎么配量化" |
| 混合型(术语+意图) | 0.5 | 两通道平权 | "混合检索怎么落地" |
| 抽象意图、口语化 | 0.7~0.8 | 语义定位 | "怎么让搜索快一点" |
落地要点:
- 两通道并行跑完再合并,归一化必须发生在加权之前,这个顺序错了后面全错;完整示例见 fusion_retrieval notebook。
- 别执着于一个固定值。先拿 20 条线上坏查询,对 alpha ∈ {0.3, 0.5, 0.7} 做一轮人工评估,哪组命中多就用哪组。
- 上线后把"用户追问了一遍"的会话当作负样本定期回收,这是调 alpha 最便宜的数据源。
召回准了只是"找出来了",接下来还得"排得对"。
让排序更懂你:用 LLM 给候选文档打分
Top-K 和 Top-N 的取舍
召回回来的 5 篇候选里,最对的那篇排在第 3,而 LLM 往往只认真看前两段——排名就是命中率。
这套做法是两阶段的:第一阶段用便宜的通道(向量或上面那套混合检索)粗筛出 Top-K,K 取 20~50;第二阶段让 LLM 当"面试官二面",对每篇文档单独打分、重排,只取 Top-N,N 取 3~5。为什么要分两步?让 LLM 直接对整个文档库逐篇判断,既慢又烧钱,而且它本来就不擅长"找",擅长的是"判"。粗排负责把候选圈出来,精排负责判断谁真的相关,各干各的活。
精排的全部秘密就藏在这段 prompt 里:
prompt = """在 1~10 分范围内给文档与查询的相关性打分。 重点看查询意图,而不是关键词重合度。 查询: {query} 文档: {doc} 相关性分数:""" chain = prompt | llm.with_structured_output(RatingScore) score = chain.invoke({"query": q, "doc": d}).relevance_score两个阶段的分工可以摆成一张表:
| 粗排(第一阶段) | 精排(第二阶段) | |
|---|---|---|
| 职责 | 把候选圈出来 | 判断谁真的相关 |
| 规模 | Top-20~50 | Top-3~5 |
| 单文档成本 | 毫秒级 | 一次 LLM 调用 |
| 容忍度 | 漏 1~2 篇可接受 | 头部必须准 |
落地要点:
- K 可以大方一点,因为粗排通道便宜;N 必须抠着点,因为精排后的文档要整个塞进生成上下文。
- LLM 温度设 0,输出走结构化解析,解析失败按 0 分处理——宁可少给一篇,别让流程崩掉。
- 把 (query, doc) 的打分结果做缓存。客服场景里 80% 的问法其实重复出现,缓存命中率会高得超出你的预期。
排名理顺后,还得把混进来的垃圾清掉。
让结果更干净:三道过滤器
想象一下,top-5 结果里有 2 段几乎重复的内容、1 段去年的旧版本、还有 1 段风马牛不相及的边缘匹配——上下文窗口就这么被垃圾占满了。三道过滤器各管一摊,顺序建议是:元数据 → 阈值 → 多样性,越靠前拦掉得越多。
元数据过滤器:搜索发生前,按来源、年份、类目这些字段圈定范围。它拦掉的是"根本不属于这个类别"的文档。比如只允许命中 2025 年发布的安全更新,旧版说明再相关也别进来。
相似度阈值:搜索发生后,把相似度低于下限的文档直接拒掉。它拦掉的是"语义上擦边、内容上无关"的长尾匹配。0.6~0.8 是常见区间,调太高召回会漏,调太低等于没设。
多样性过滤:选最终 N 篇时,每篇都要和已入选的文档算一次语义距离。它拦掉的是"三篇说同一件事"的冗余结果,保证结果集在观点、来源上铺得开。
落地要点:
- 阈值先粗设 0.6,跑一周线上查询,专门看"用户不满意"的那批,漏召回多就往下调,噪声多就往上调。
- 多样性权重从 0.2~0.3 起步,压得太高会把"相关但重复"的文档挤出排名,得不偿失。
- 过滤器是廉价操作,能前置就前置:元数据条件直接下推进度引擎,别等结果回来再在内存里筛。
过滤保证了"干净",但如果文档库涨到十万级,前面的通道本身就会开始打架。
让大规模检索不打架:分层索引
层级数量怎么选
文档库到 20 万 chunk 之后,每次查询都是全库向量比对:慢,而且一篇强相关文档的信号会被另外 19 万 9 千篇稀释掉。
把它类比成图书馆:你查资料不会把整栋楼的书全翻一遍。先看书架总目录,锁定 3 本候选书;再翻那几本书的章节摘要;最后才到具体段落。分层索引就是这个结构——顶层是全书摘要,中层是章节概览,底层才是正文块。每一层的检索空间比上一层小一个数量级,而且上层命中天然带着上下文:章节摘要告诉模型"我们在谈这本书的哪部分",这比孤零零的 chunk 信息量大得多。
导航逻辑本身非常朴素:
books = summary_store.similarity_search(query, k=3) # 总目录:先锁定书 for book in books: secs = section_store.similarity_search( query, filter={"book_id": book.id}, k=5) # 章节摘要 for s in secs: results += chunk_store.similarity_search( query, filter={"section_id": s.id}, k=3) # 落到具体段落落地要点:
- 两层(摘要 + chunk)通常够用;文档上万、层级结构复杂时再上三层。两层示例可直接参考 hierarchical_indices notebook。
- 关键在 metadata 联动:上层命中的 doc_id / section_id 必须能直接过滤下层检索范围,否则"分层"就退化成"多建了几个索引"。
- 将来要接图片、音频等多模态数据时,给每种模态并行建一套同构索引,共享同一套导航路径即可。
四层漏斗都修完,剩下的事就是按顺序把它们装进你自己的项目里。
落地路线:一份 3 周清单
第 1 周 · 检索层:给现有向量检索并联一条 BM25 通道,归一化后按 alpha=0.5 融合;同时收集 20 条真实坏查询(用户追问、点踩、无点击的会话都算),记录每条的召回命中情况,作为基线。
第 2 周 · 排序层 + 过滤层:接上 LLM 重排序,K=30、N=3,温度 0;加上元数据过滤和 0.6 的相似度阈值。用同一批 20 条坏查询复测,和基线对比——这一步通常能立刻看到命中率变化,也是最有正反馈的一周。
第 3 周 · 架构层 + 回归机制:文档量到几万级就建"摘要→chunk"两层索引;把这批坏查询固化为回归集,之后每次改索引、改参数、换嵌入模型,先跑回归集再上线。
最后一句收束:召回决定天花板,排序决定命中率,过滤决定干净度,分层决定规模上限。修的顺序也建议照这个漏斗来,别跳级。
【免费下载链接】RAG_TechniquesThis repository showcases various advanced techniques for Retrieval-Augmented Generation (RAG) systems. Each technique has a detailed notebook tutorial.项目地址: https://gitcode.com/GitHub_Trending/ra/RAG_Techniques
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考