应用层 · RAG 进阶
学习舱 / 应用层 / RAG 进阶

RAG 进阶:混合检索、重排与评估

整理中 深度 · 应用 更新 2026-09-22

前置 RAG

RAG 进阶:混合检索、重排与评估

一句话定位:给朴素 RAG 打四层补丁——切块谱系、查询优化、混合检索、重排,再用评估证明补丁真的有效。前置:RAG:检索增强生成——先跑通过骨架,这里的每个补丁才有对照物。

补丁要一层层打,还要验收

朴素 RAG 的三类失效你已经知道:召回不到、排序错、答案无据。

市面上每个 RAG 教程都会甩出一堆进阶名词——混合检索、HyDE、rerank、RAGAS——但很少有人说清两件事:每个补丁对应哪类失效,以及打了补丁之后怎么证明它有效。

不对应失效的优化是装饰,没有评估的优化是赌博。这篇按「失效 → 补丁 → 验收」的线索,把进阶版图拼完整。

进阶补丁地图:失效在哪里,补丁打在哪里 索引侧 · 切块谱系 固定长 / 段落 / 标题 语义 / 代码 AST / 元数据 查询侧 · Query 优化 改写 · 分解 · 澄清 HyDE · 多轮改写 召回侧 · 混合检索 向量(语义) + BM25(字面精确) 排序侧 · 重排 双塔粗筛 → 交叉编码器精排 评估环 召回 / 命中率 · 答案正确率 · 幻觉率 · 引用准确率 失效一(召回不到)→ 查询侧 + 召回侧 失效二(排序错)→ 重排 失效三(答案无据)→ 引用校验 + 评估 读法:补丁各管一段,评估环验收所有补丁——没有它,你不知道哪层在起作用

图:补丁地图——左下角是三类失效与各自对应的层,评估环守在最后验收一切

渐进拆解:五层各管一件事

索引侧:切块不是剪刀,是语义单元的划定

朴素管线的「每 500 字切一刀」只是切块谱系里最粗糙的一档。谱系往下走,每一档都在回答同一个问题:一块的边界画在哪,才能让「一个块 = 一个完整的意思单元」?

  • 固定长度:简单便宜,起点档;主题混杂是代价。
  • 段落 / 标题切块:尊重作者划好的边界——Markdown 标题、段落空行是现成的语义信号。
  • 语义切块:按句间相似度找「话题转折点」下刀,贵一点但边界更准。
  • 代码 AST 切块:代码不能按字数砍——按语法树沿函数、类的边界切,函数永远完整。给代码库建 RAG 的标配。
  • 元数据附加:切块时顺手挂上来源文件、章节、日期、权限标签——检索之后过滤全靠它。

各档都要配 overlap(相邻块重合几十个字,沿用上一篇 500/50 的做法),防关键句被边界斩断。

查询侧:先把问题修好,再拿去检索

用户的问题天然是「口语的、省略的、模糊的」,检索库却是「书面、完整、术语化」的——五个手段按需用:

  • 改写:把「钱怎么回来」改写成「退款流程」——对齐资料的语言。
  • 分解:把「A 和 B 哪个方案好」拆成两个子问题分别检索。
  • 澄清:歧义太大时反问用户而不是硬猜。
  • HyDE:先让模型凭空写一个假想答案,拿假想答案的向量去检索——答案和文档的语言风格更接近,命中率常优于用问题本身检索。
  • 多轮改写:把「那第二种呢」这类指代补全成完整问题——多轮对话的必需品。

召回侧:向量与关键词,双保险

向量检索管「意思接近」,BM25(基于词频的经典字面匹配算法,Elasticsearch 的看家本领)管「字面精确」——Embedding 与向量化说过「E-4021 被 embed 后可能和 E-4022 靠得很近」,BM25 就编号匹配而言几乎不会认错它们。

混合检索:两路并行,RRF 汇流 问题 同一个问题 向量路 · 语义 管「意思接近」 BM25 路 · 字面 管「编号精确」 RRF 融合 倒数排名融合 混合结果 两路各守一端 读法:两路互为补端;一个文档在两路里都靠前,RRF 里就排最前

图:混合检索——同一个问题分走向量与 BM25 两路,RRF 把两路排名融合成一份结果

两路并行检索、结果融合(常用 RRF,倒数排名融合:一个文档在两路里都靠前就排最前),就是混合检索。向量路补「字面岔开但意思仍近」的那一端,BM25 补「编号必须精确」的那一端——两个极端,一路守一个。

排序侧:两段式,先广撒网再精挑

混合检索找回了候选(比如 20 段),但谁最相关还得精挑细选。这就是重排(rerank)的舞台,两种架构的取舍是本层核心:

  • 双塔(bi-encoder):问题与文档各自编码成向量再算距离——文档可离线编码,检索飞快;但两段文字没有交互,「细粒度的相关性」判断不了。适合从百万级粗筛到百级。
  • 交叉编码器(cross-encoder):问题与文档拼在一起送进模型,逐对输出相关性分数——每一对都做深度交互,精度显著更高;代价是每对都要跑一次模型,慢且贵。适合从百级精选到个位数。

生产标配是两段式:双塔(或向量+BM25)召回 top-20 → 交叉编码器重排 → 取 top-3 进提示词。 rerank 模型有现成的(开源 reranker 系列与商用 rerank API 都是即插即用),不必自训。

两段式检索:先广撒网,再精挑 全库 百万级文档 混合召回 向量 + BM25 各 20 融合 交叉编码器精排 逐对深度打分 top-3 进提示词 快:毫秒级,先广撒网 准:逐对交互,只精挑几十个 分工逻辑:快的干粗活,准的干细活——反过来放(精排全库)延迟不可接受

图:检索漏斗——三层收窄;交叉编码器只对几十个候选逐对打分,精度与延迟各得其所

取舍的量级感受一下:双塔编码一条文档是毫秒级,而且可以离线批量做——建库时就算好,查询时零成本;交叉编码器每一对都要跑一次完整的模型前向,几十毫秒起步,30 个候选就是秒级的追加延迟。这就是精排只对几十个候选做的原因:精度买得起的范围,以候选数量为界——想给精排多喂几个候选,先想想用户愿不愿意多等一秒。

大白话:RAG 进阶就是招聘流程——切块决定简历库质量,查询优化是把岗位要求写清楚,混合检索是海选(快但粗),rerank 是面试官(慢但准),评估是试用期考核。五个环节都过硬,才招得到对的人。

技术定义:现代 RAG 在朴素管线上叠加四层:索引层按内容形态选择切块策略(文本按段落/语义,代码按 AST,全量附加元数据);召回层用混合检索(向量 + BM25/ES,RRF 融合);查询层做改写、分解与 HyDE 等前置优化;排序层用交叉编码器对召回候选精排。整条链路用检索指标(召回率、命中率)与生成指标(答案正确率、幻觉率、引用准确率)分层度量。

动手:两段式检索 + 一份不骗人的评估集

这就是补丁地图最下方的评估环——前四层补丁打完,靠它验收:

# 示意接口:rewrite / vector_search / bm25_search / rrf / cross_encoder
def retrieve(question, top_k=3):
    q = rewrite(question)                      # 查询侧:改写后进向量路
    candidates = rrf(                          # 混合召回:两路各取 top-20 融合
        vector_search(q, top_k=20),
        bm25_search(question, top_k=20),       # 字面路用原始问句
    )
    scored = cross_encoder.rerank(question, candidates)   # 精排
    return scored[:top_k]

# 评估集(golden set):先于功能开发。每条 = 问题 + 应命中的块 id + 标准答案要点
golden = [
    {"q": "过了七天还能退吗", "hit": ["chunk_42"], "answer_must": ["特殊商品除外"]},
    {"q": "E-4021 怎么解决",   "hit": ["chunk_108"], "answer_must": ["网络超时"]},
]
# 检索指标:hit 是否出现在召回结果里(命中率/召回率)
# 生成指标:答案是否含 answer_must 要点、是否带引用、编造了几处
# 生成端还有一层引用校验:答案里的每个关键断言,能否定位到某条引用原文——定位不到即视为无据

评估集从 20 条起步就能拦住大半回退:每次改切块、换检索、调 k,跑一遍看命中率与幻觉率的变化——变好的证据必须是数字,不是体感。评估环节也可以借助 RAGAS 这类开源评估框架跑自动化指标。

边界与取舍:别把 RAG 做成补丁堆

失效驱动打补丁

你的失效若只是「编号搜不到」,加 BM25 一层就够,HyDE 与语义切块可以先不上——每层都有延迟与维护成本。上补丁前先拿 20 条真实问题复现失效,确认打在哪层;这同一批题随后就是评估基线——先当探针,再当考卷,一鱼两吃。

评估先行

先建 20 条评估集再动手改系统——没有基线的优化无法证明有效,甚至无法发现退化。评估集的题目要来自真实用户问题(而不是开发自己编的),覆盖典型与边界两类。

评估时把两类失败分开记账,混在一起算总账,永远不知道该修哪一层:

  • 「该找到的没找到」是检索的锅——回去补召回与排序。
  • 「找到了答错」是生成的锅——回去补提示词约束与引用校验。

检索天花板

召回、排序都做对之后,剩下的失效往往在生成端(模型无视资料、综合过度)——那是引用校验与提示词约束的领地,继续堆检索层是无效内卷。

前沿钩子

  • Agentic RAG:把检索做成 Agent 的一个工具,由模型自己决定「要不要查、查什么、查完够不够」。
  • 代码库 RAG:AST 切块保住函数完整性、检索结果带行号引用,让模型「按行号读代码」。

后者在Codebase Agent 实战展开;前者涉及 Agent 与工具的编排方式,读完MCP:协议与工具接入会更好理解。

自测

合上文章先自己答,再展开对照:

纯向量检索的三个盲区分别被 BM25、Rerank、Query 改写中的哪个补上?

盲区一「术语体系岔开」(用户说「钱怎么回来」,资料写「退款流程」)——由 Query 改写补:检索前先把问题改写成资料的语言,或在多轮对话里补全指代。盲区二「字面精确场景失效」(E-4021 和 E-4022 被向量认为很近)——由 BM25 补:混合检索里关键词那一路就编号匹配而言分得清编号,两路结果用 RRF 融合。盲区三「意思近不等于最相关」(正确段落排在候选末位)——由 Rerank 补:交叉编码器对召回候选逐对精排,把真正相关的顶到前面。三者作用在不同环节:改写修问题、BM25 修召回、Rerank 修排序。

RAG 评估怎么做才不是自欺?

三个原则。其一,评估集先于优化:动手改系统前先建评估集(20 条起步),否则没有基线,一切「感觉变好了」都不可证。其二,题目来自真实用户问题,覆盖典型与边界两类——用开发自己编的题评估,等于照着答案出卷。其三,分层度量:检索层看命中率与召回率(该找到的找到了没),生成层看答案正确率、幻觉率与引用准确率(找到之后答得对不对、有没有出处)——混在一起看会互相掩盖。工具上可用 RAGAS 这类开源评估框架跑自动化指标,但题目与验收标准必须自己定。最后,每次改动跑同一份评估集对比数字——变好的证据是数字,不是体感。

参考与延伸

下一站:MCP:协议与工具接入——检索之外,模型接入外部世界的另一种标准化方式。

本节点大纲与自测题(6 个子点 · 2 问)

大纲

  • Chunking 谱系:固定长度 / 段落 / 标题 / 语义 / 代码 AST / overlap / metadata
  • 混合检索:向量 + BM25 / Elasticsearch,各自解决什么
  • Query 侧优化:改写、分解、澄清、HyDE、多轮改写
  • Rerank:双塔 vs 交叉编码器,延迟与精度取舍
  • RAG 评估:召回率、命中率、答案正确率、幻觉率、引用准确率
  • Agentic RAG 与 Codebase RAG(AST 切块、行号引用)

自测——答不上来就是缺口

  • 纯向量检索的三个盲区分别被 BM25、Rerank、Query 改写中的哪个补上?
  • RAG 评估怎么做才不是自欺?