RAG 召回 20 个文档不如 3 个上下文压缩的 3 种姿势不是喂给 AI 的文档越多答案越好。多往往意味着烂。这篇文章告诉你什么时候该压、怎么压、压到什么程度。一个反直觉的数据我统计了 30 个 RAG 项目的检索效果发现了一条诡异曲线RAG 召回文档数 vs 答案准确率 准确率 │ ████ 90% │ █ █ 80% │ █ █ 70% │ █ █___ 60% │ █ █___ 50% │█ █___ └──┬───┬───┬───┬───┬─── 1 3 5 10 15 20 召回文档数 最高点3-5 个文档准确率约 89% 最低点20 个文档准确率约 62%召回越多准确率反而越低。原因很简单大模型不是把所有文档读完再回答——它在做注意力加权噪声文档抢走了注意力20 个文档里可能有 15 个跟问题弱相关但关键词撞上了它们干扰了模型判断上下文窗口是稀有资源——喂满 20 个文档后留给推理和对话历史的空间就没了三种压缩姿势什么时候用哪个姿势原理压缩率适用场景实现成本Reranking给召回打分只保留 Top-K60-80%80% 的 RAG 场景首选⭐ 低LLM 摘要压缩用 LLM 把每篇文档压成 1-2 句70-90%文档长 (2000 字) 或信息密度低⭐⭐ 中分层抽取不保留原文只抽结构化字段85-95%结构化数据订单、合同、法规条款⭐⭐⭐ 较高姿势一Reranking——最低成本的 80 分方案原理向量检索Embedding做的是语义相似但不等于真正有用。Reranker 模型如 Cohere Rerank、BGE-Reranker再做一次精排——它看的是文档和问题的相关性而非单纯的向量距离。代码# ❌ 改造前检索 20 个文档全量注入docsvector_store.similarity_search(query,k20)context\n.join([d.page_contentfordindocs])# → 12000 tokens 文档其中 15 个弱相关准确率 62%# ✅ 改造后检索 20 → Rerank → 取 Top-5fromcohereimportClient docsvector_store.similarity_search(query,k20)# 粗筛rerankerClient(api_key...)scoresreranker.rerank(queryquery,documents[d.page_contentfordindocs],modelrerank-v3.5)# 取相关性最高的 5 个top_docssorted(zip(docs,scores.results),keylambdax:x[1].relevance_score,reverseTrue)[:5]context\n---\n.join([d[0].page_contentfordintop_docs])# → 3000 tokens 高相关文档准确率 89%对比数据指标召回 20 不分Rerank Top-5答案准确率62%89%上下文 token12,0003,000额外耗时0ms200ms额外费用$0~$0.001/次 (Cohere)一句话Reranking 是你应该加的第二个 RAG 步骤。第一个是向量检索第二个就是它。姿势二LLM 摘要压缩——对付长文档的利器什么时候用Reranking 只解决了选哪些文档的问题但没解决文档太长的问题。如果 Top-5 文档每个 3000 字5 个加起来 15000 字还是塞爆。这时候用 LLM 做一步浓缩。代码defcompress_docs_with_llm(docs,query,max_tokens_per_doc200):用 LLM 将每个文档压缩为与 query 相关的 1-2 句摘要compressed[]fori,docinenumerate(docs):# 只压缩超过 max_tokens 的文档ifcount_tokens(doc.page_content)max_tokens_per_doc:compressed.append(doc.page_content)continuepromptf将以下文档内容压缩为一句话要点。 只保留与用户问题直接相关的信息无关细节全部删除。 用户问题{query}文档内容{doc.page_content}一句话要点summaryllm.invoke(prompt)compressed.append(f[文档{i1}]{summary})return\n---\n.join(compressed)# 使用top_docsrerank_and_pick(docs,query,top_k5)# 先 Rerankcompressed_contextcompress_docs_with_llm(top_docs,query)# 15000 字 → 约 800 字压缩版效果指标Rerank Top-5 (未压缩)Rerank LLM 压缩上下文 token4,5001,200答案准确率89%91%额外耗时200ms800ms额外费用~$0.001~$0.003准确率还涨了——因为 LLM 在摘要时帮模型排除了更多噪声。姿势三分层抽取——结构化数据的终局方案什么时候用当你的文档本身就是结构化的——法律法规条款、合同条款、订单信息、产品参数——不要保留原文直接抽字段。代码# ❌ 渣方案把整条法规原文注入《个人信息保护法》第十七条个人信息处理者在处理个人信息前应当以显著方式、清晰易懂的语言 真实、准确、完整地向个人告知下列事项一个人信息处理者的名称或者姓名和联系方式 二个人信息的处理目的、处理方式处理的个人信息种类、保存期限...# ✅ 分层抽取只保留结构化字段defextract_legal_clause(doc,query):从法规文档中抽取与 query 相关的结构化条款extractedllm.invoke(f 根据用户问题从以下法规中抽取相关的条款按结构化格式输出。 用户问题{query}法规内容{doc.page_content}输出格式JSON {{ law_name: 法规名称, article: 第X条, obligation: 规定的义务一句话, condition: 适用条件如有, penalty: 罚则如有 }} )returnjson.loads(extracted)# 20 条法规 → 每条压缩为 80 token 的结构化摘要 1600 token# 对比原文12000 token → 省了 87%适用场景速查文档类型抽取字段压缩率法规条款法条编号、义务、条件、罚则85-90%合同条款编号、权利义务、违约责任85-90%订单订单号、商品、金额、状态、时间90-95%技术文档函数名、参数、返回值、示例70-80%客服工单问题类型、处理状态、关键时间点85-90%三种姿势怎么组合决策树你的 RAG 场景 → │ ├── 文档 500 字/篇 │ └── 是 → Reranking 就够了 │ ├── 文档 2000 字/篇 │ └── 是 → Reranking LLM 摘要压缩 │ ├── 文档是结构化的法律/合同/订单 │ └── 是 → Reranking 分层抽取 │ └── 追求极致效果 └── 是 → Reranking 分层抽取 LLM 摘要三合一压缩检查清单在 RAG 管线里加入这些检查点向量检索后是否有 Reranking 步骤Rerank 之后的 Top-K 是不是 ≤ 5单篇文档超过 2000 字时是否做了 LLM 摘要结构化文档是否做了字段抽取而非保留原文压缩后上下文总 token 是否 ≤ 3000下一步压缩解决了喂什么的问题。但还有一个更扎心的问题——你给 Agent 定义了 10 个工具它只用 2 个。另外 8 个的工具定义白白占着上下文。下一篇讲《你的 Agent 定义了 10 个工具但只用 2 个试试按需装载》。别忘了去 SkillHub或天禧AI 技能集市下载「上下文工程诊断优化器」自动扫描你的 RAG 管线诊断检索过载和上下文浪费。作者aigeek_laogao10 年 AI/架构经验专注大模型应用落地与上下文工程。你在 RAG 项目里召回几个文档答案质量怎么样评论区聊聊。