一文搞懂 RAG 检索后处理:重排 + 压缩 + 校正 三大模块全面解析

一文搞懂 RAG 检索后处理:重排 + 压缩 + 校正 三大模块全面解析
写在前面很多同学搭完朴素 RAG 后会发现 —— 召回率明明还可以但最终答案总是差点意思。问题往往不在召回而在「召回之后、生成之前」这段空白。本文系统拆解 RAG 检索后处理的三大支柱重排、压缩、校正配合代码示例 12 岁能听懂的类比带你彻底搞透。 目录一、痛点引入朴素 RAG 到底差在哪二、一张图看懂检索后处理三、模块 1重排Reranking—— 6 种技术详解四、模块 2压缩Compression—— 3 种粒度对比五、模块 3校正Correction—— CRAG 反思式检索六、生产实战4 套 Recipe 组合七、避坑指南八、面试速记 30 秒版九、总结一、痛点引入a id一痛点引入/a朴素 RAG 是一条单向流水线query → 检索召回 → 文档 → LLM 生成答案听起来很美好但实际跑起来有3 个核心痛点痛点表现后果排序不准相关文档排在 Top-50 后面LLM 看不到 → 答非所问prompt 太长召回几十个文档全喂给 LLMToken 成本爆炸 噪声污染检索失败库里根本没有相关文档LLM 硬编 → 幻觉检索后处理 在「召回」和「生成」之间加 3 类修补模块对症下药。二、一张图看懂检索后处理a id二一张图看懂检索后处理/a检索后处理Post-Retrieval Processing │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ ① 重排 ② 压缩 ③ 校正 (Reranking) (Compression) (Correction) │ │ │ 解决排序不准 解决prompt 太长 解决检索失败 │ │ │ 手段精排 / 融合 手段删冗余 手段评估 补救完整工业级 RAG Pipeline5 阶段用户 Query ↓ [Stage 1: 召回] BM25 向量检索Top-50~100 ↓ [Stage 2: 重排] RRF 融合 → CrossEncoder 精排Top-10 ↓ [Stage 3: 压缩] 文档级 → 句子级 → Token 级 ↓ [Stage 4: 校正] CRAG 评估 → 不合格则 web 补救 ↓ [Stage 5: 生成] 精炼 prompt → LLM 答案重要澄清5 阶段是完整工业级形态必须的只有 2 个召回 生成。重排、压缩、校正都是可选优化层按需添加。90% 的生产 RAG 实际是「召回 重排 生成」3 阶段。三、模块 1重排Rerankinga id三模块-1重排/a 核心洞察重排 在召回要快但糙和 LLM 生成要精之间加一层「精度放大器」朴素 RAG 的瓶颈往往不是召回而是排序召回能轻松 Recall50 80%但 Top-5 精度可能只有 40%。重排就是把 Top-5 精度从 40% 推到 80% 的关键环节。 6 种重排技术一览类别技术一句话类比适用场景排名融合RRF问 4 个朋友取共识多路检索融合深度交互CrossEncoder一个裁判仔细读完整段打分高精度精排深度交互ColBERT裁判拆词逐个找最像再求和学术/术语检索商业 APICohere花钱请专业公司打分快速 POC / 多语言LLM 推理RankLLM请院士读一遍直接排序复杂推理场景业务规则时效加权给新鲜内容加分新闻/促销3.1 RRF 重排倒数排名融合 12 岁版你问 4 个朋友山西有什么好玩的每人给你列一张推荐单。RRF 就是把这 4 张单子叠起来看 —— 哪个景点在所有单子里都靠前它就是大家公认最该去的。 公式score(d) Σ_i 1 / (rank_i(d) k)rank_i(d)文档 d 在第 i 个检索列表中的位置从 0 起k60平滑常数避免 top 位差距过大 代码实现defreciprocal_rank_fusion(results:list[list],k60):fused_scores{}fordocsinresults:forrank,docinenumerate(docs):doc_strdumps(doc)fused_scores.setdefault(doc_str,0)fused_scores[doc_str]1/(rankk)return[(loads(d),s)ford,sinsorted(fused_scores.items(),keylambdax:x[1],reverseTrue)]✨ 为什么神RRF 丢弃原始分数只用 rank所以能跨异构检索器融合BM25 返回 12.3向量返回 0.87尺度完全不可比但 rank 永远在 1~N 之间。3.2 CrossEncoder 重排精排之王 12 岁版把问题和候选答案拼成一段话交给裁判读完整段然后给个 0-10 分。裁判同时看到问题和答案能注意到细微联系。 架构对比Bi-Encoder (双塔): CrossEncoder (交叉编码): Query → BERT → q_vec [CLS] Query [SEP] Doc [SEP] → BERT → [CLS] → score Doc → BERT → d_vec ↑ 两段文本在模型内部通过 self-attention 全程交互 score cos(q_vec, d_vec)维度Bi-EncoderCrossEncoder输入query / doc独立编码querydoc拼成一对送入交互只在最后算点积/余弦每层 self-attention 全程交互预计算doc 向量可离线索引 ✅无法预计算 ❌精度中高速度快向量内积慢N 候选 → N 次前向 代码骨架fromtransformersimportAutoTokenizer,AutoModelForSequenceClassificationimporttorch tokenizerAutoTokenizer.from_pretrained(cross-encoder/ms-marco-MiniLM-L-12-v2)modelAutoModelForSequenceClassification.from_pretrained(cross-encoder/ms-marco-MiniLM-L-12-v2)defencode_and_score(query,docs):scores[]fordocindocs:inputstokenizer(query,doc,return_tensorspt,truncationTrue,max_length512,paddingmax_length)# [CLS] q [SEP] d [SEP]withtorch.no_grad():scoremodel(**inputs).logits[0][0].item()scores.append(score)returnscores⚠️中文场景的坑脚本默认的ms-marco-MiniLM是英文模型对中文效果差。中文场景必须换BAAI/bge-reranker-v2-m3。3.3 ColBERT后期交互 12 岁版裁判不直接给总分。把问题拆成一个个词每个词分别在答案里找最像的词记下分数最后所有词的最像分加起来。 MaxSim 公式score(Q, D) Σ_{i1..Lq} max_{j1..Ld} q_i · d_j对 query 每个 token找 doc 中最相似的 token 求点积再对所有 query token 求和。 折中优势像 Bi-Encoder像 Cross-Encoderquery/doc 独立编码保留 token 级矩阵交互doc 可离线索引精度高代价索引体积膨胀 10-100 倍适用学术论文检索、技术文档API/SDK 函数名、医学/化学术语。3.4 Cohere Rerank商业 API 12 岁版懒得自己打分花钱请专业公司帮忙。把问题和候选发给 Cohere 服务器几秒内返回分数。 代码骨架fromlangchain_cohereimportCohereRerankfromlangchain_community.retrieversimportBM25Retriever retrieverBM25Retriever.from_documents(documents)retriever.k3initial_docsretriever.invoke(query)rerankerCohereRerank(modelrerank-multilingual-v3.0)reranked_docsreranker.compress_documents(documentsinitial_docs,queryquery)优缺点✅ 零部署、原生多语言、低延迟❌ 数据出境合规问题、API 计费、强依赖网络3.5 RankLLM用大模型直接排序 12 岁版把所有候选答案直接列在一张单子里发给 ChatGPT让它读完后告诉你按相关性排序应该是 3、1、4、2。 代码骨架fromlangchain_community.document_compressors.rankllm_rerankimportRankLLMRerankfromlangchain.retrievers.contextual_compressionimportContextualCompressionRetriever compressorRankLLMRerank(top_n3,modelgpt,gpt_modelgpt-4o-mini)compression_retrieverContextualCompressionRetriever(base_compressorcompressor,base_retrieverretriever# 假设已建好 FAISS 检索器)适用医疗咨询、多跳问答、需要为什么这么排的可解释场景。杀鸡用牛刀的反例简单事实型查询。3.6 时效加权重排业务规则 12 岁版在原本的相似度评分基础上给最新的内容加分。新闻是 1 小时前的分数几乎不变1 年前的分数就打折很多。 公式final_score semantic_score × 1 / (1 decay_rate × hours_since_last_access) 代码骨架fromlangchain.retrieversimportTimeWeightedVectorStoreRetriever retrieverTimeWeightedVectorStoreRetriever(vectorstorevectorstore,decay_rate0.5,# 衰减率每小时约 39% 衰减k1)# 必须给文档带 last_accessed_at 元数据doc1Document(page_contenthello world,metadata{last_accessed_at:datetime.now()-timedelta(days1)})⚠️decay_rate 调参敏感从 0.01-0.1 起步过大会埋掉长青内容。四、模块 2压缩Compressiona id四模块-2压缩/a 核心问题召回的文档可能很长全喂给 LLM 会爆 token 噪声污染。 3 种粒度对比粒度技术一句话类比用 LLM速度文档级ContextualCompression整本书相关就留不相关就扔❌快句子级SentenceEmbeddingOptimizer扫一眼每段开头挑相关的段❌极快msToken 级LLMLingua聪明朋友按字划掉废话✅慢秒级三者可串联文档级 → 句子级 → Token 级逐层细化。4.1 ContextualCompression文档级 Wrapper 模式fromlangchain_cohereimportCohereRerankfromlangchain.retrievers.contextual_compressionimportContextualCompressionRetriever compressorCohereRerank(modelrerank-multilingual-v3.0)compression_retrieverContextualCompressionRetriever(base_compressorcompressor,# 任意 compressorbase_retrieverretriever# 任意 retriever)解耦设计base_retriever和base_compressor可自由组合BM25 Cohere / FAISS LLM 等。4.2 LLMLinguaToken 级压缩 核心原理困惑度Perplexity用小 LM 评估每个 token 的困惑度低困惑度 高度可预测 信息量低 →删除高困惑度 不可预测 信息量高 →保留例「我们公司」「根据相关规定」「的一些问题」这类高频词困惑度低可删除。 代码骨架fromllmlinguaimportPromptCompressor llm_linguaPromptCompressor(model_nameNousResearch/Llama-2-7b-hf,device_mapcpu)compressed_promptllm_lingua.compress_prompt(context云冈石窟位于中国北部山西省大同市...,instruction压缩并保持主要内容,question,target_token10)⚠️Llama-2-7b在 CPU 上跑要几秒到几十秒生产建议换llmlingua-2-bert-base-multilingual GPU。4.3 SentenceEmbeddingOptimizer句子级 LlamaIndex 一行接入fromllama_index.core.postprocessorimportSentenceEmbeddingOptimizer# 模式 1保留相似度前 50% 的句子SentenceEmbeddingOptimizer(percentile_cutoff0.5)# 模式 2保留相似度 0.7 的句子SentenceEmbeddingOptimizer(threshold_cutoff0.7)优点零 LLM 成本、ms 级速度、保留语义完整性、开箱即用。五、模块 3校正Correctiona id五模块-3校正/a 核心问题库里根本没相关文档时重排和压缩都无能为力LLM 会硬编造答案幻觉。 CRAGCorrective RAG腾讯 中山大学 2024 年提出arxiv 2401.15884核心贡献是把「检索质量评估 自动校正」做成独立模块。 工作流┌─────────────────────────┐ │ START (用户 question) │ └────────────┬─────────────┘ ▼ ┌────────────────┐ │ retrieve │ 本地向量检索 └────────┬───────┘ ▼ ┌────────────────┐ │ grade_documents │ LLM 评分每个文档 yes/no └────────┬───────┘ ▼ ┌────────────────┐ │ decide_to_gen │ 条件路由 └────────┬───────┘ ┌──────────────┴───────────────┐ (有相关文档) (全部不相关) ▼ ▼ ┌──────────┐ ┌──────────────────┐ │ generate │ │ transform_query │ 重写 query └──────────┘ └────────┬─────────┘ ▼ ┌──────────────────┐ │ web_search_node │ Tavily 搜 └────────┬─────────┘ ▼ generate 五大核心组件① 检索评分器CRAG 的灵魂fromlangchain_core.pydantic_v1importBaseModel,FieldclassGradeDocuments(BaseModel):binary_score:strField(descriptionyes or no)structured_llm_graderllm.with_structured_output(GradeDocuments)retrieval_gradergrade_prompt|structured_llm_grader关键设计用 Pydantic 结构化输出 二元判断yes/no比连续分数更稳定。② 触发 web 搜索的关键逻辑ifnothas_relevant_docs:web_searchYes# 只有「全部不相关」才触发CRAG vs Self-RAGSelf-RAG 逐文档评估CRAG 是集合级判断全不相关才补救。③ LangGraph 状态图编排fromlanggraph.graphimportEND,StateGraph,START workflowStateGraph(GraphState)workflow.add_node(retrieve,retrieve)workflow.add_node(grade_documents,grade_documents)workflow.add_node(generate,generate)workflow.add_node(transform_query,transform_query)workflow.add_node(web_search_node,web_search)workflow.add_edge(START,retrieve)workflow.add_edge(retrieve,grade_documents)workflow.add_conditional_edges(grade_documents,decide_to_generate,{transform_query:transform_query,generate:generate},)workflow.add_edge(transform_query,web_search_node)workflow.add_edge(web_search_node,generate)workflow.add_edge(generate,END)appworkflow.compile() CRAG vs Self-RAG vs 朴素 RAG维度朴素 RAGCRAGSelf-RAG检索质量评估❌ 无✅ LLM 二元评分✅ 训练专门 token检索失败补救❌ 没有✅ 重写 web 搜索✅ 内置是否需要微调❌❌纯 prompt 工程✅ 需训练 critic部署难度易易难六、生产实战4 套 Recipe 组合a id六生产实战/a Recipe A通用电商搜索中等流量全本地[Stage 1] BM25 向量双路召回 Top-100 [Stage 2] RRF 融合 → Top-50 [Stage 3] CrossEncoder 精排 → Top-10 [Stage 4] 时效加权 → 优先近期热销品 Recipe B跨境多语言 RAG创业 POC[Stage 1] Cohere Embed多语言→ Top-50 [Stage 2] Cohere Rerank → Top-5 [Stage 3] 生成答案优点1 天上线、无 GPU 投入、原生多语言。缺点API 依赖 数据出境。 Recipe C法律/医疗专家系统高精度可解释[Stage 1] ColBERT 召回 精排 → Top-10 [Stage 2] RankLLM 解释性重排 → Top-3 [Stage 3] LLMLingua 压缩长文档 [Stage 4] LLM 生成 引用 排序理由 Recipe D库内知识不全CRAG 兜底[Stage 1] 本地向量检索 [Stage 2] CRAG 评估 → 相关 ├─ 相关 → 走 Recipe A/B/C └─ 不相关 → 重写 query → Tavily web 搜索 → 生成七、避坑指南a id七避坑指南/a重排的坑坑规避❌ CrossEncoder 处理 10000 候选✅ 先 Bi-Encoder 粗排再精排❌ 中文场景用英文 reranker✅ 换BAAI/bge-reranker-v2-m3❌ RRF 只用单路检索✅ 至少双路单路无意义❌ decay_rate 设 1.0✅ 从 0.01-0.1 起步❌ GTX 1080 Ti 跑新 PyTorch✅ 强制.to(cpu)绕过 sm_61压缩的坑坑规避❌ LLMLingua 跑在 CPU✅ 上 GPU 或换更小 base LM❌ 压缩比设太高破坏语义✅ 从 30% 开始 A/B 测试校正的坑坑规避❌ LLM 评分不稳定✅ 降低 temperature用结构化输出❌ Web 搜索结果噪声大✅ 限制k3对结果再做一次压缩八、面试速记a id八面试速记/a提问一句话回答重排本质召回和生成之间的精度放大器RRF 公式1/(rankk)k60Bi vs Cross双塔独立编码 vs 拼接编码ColBERT 核心token 级矩阵 MaxSimLLMLingua 原理删除低困惑度 tokenCRAG 核心评分 重写 web 补救CRAG 触发条件全部文档都不相关Self-RAG 区别需训练 criticCRAG 纯 prompt时效加权公式score / (1 decay × hours)重排和压缩关系正交可叠加Pipeline 必须几阶段必须 2 个召回生成5 阶段是完整工业级九、总结a id九总结/a 5 大核心思想两阶段架构cascade retrieval召回要快→ 精排要准。这是搜索引擎 50 年的经典架构。多粒度处理文档级 → 句子级 → token 级可串联。反思与补救不能盲信召回结果需要评估 自动补救。正交模块化重排、压缩、校正可自由组合。速度 vs 精度权衡没有银弹按业务 SLA 取舍。 给不同读者的建议初学者先跑通01-RRF重排.py理解多路融合的威力工程师直接上 Recipe ARRF CrossEncoder覆盖 90% 场景架构师重点研究 CRAG理解反思机制如何提升可靠性研究者精读 ColBERT 和 Self-RAG 论文 参考资源必读论文CRAG: Yan et al. 2024ColBERT: Khattab Zaharia 2020LLMLingua: Jiang et al. 2023Self-RAG: Asai et al. 2023官方文档LangChain RAG TutorialLlamaIndex PostprocessorsMicrosoft LLMLinguaLangGraph写在最后RAG 不是召回 生成那么简单但也不必上来就全套 5 阶段。先用最小可用 pipeline 验证业务再按实际痛点逐步加层才是工程上的正解。如果觉得有帮助欢迎点赞 收藏 关注➕一键三连完整代码和笔记仓库rag-in-action有任何问题欢迎评论区交流