news 2026/7/2 4:11:04

RAG 召回 20 个文档不如 3 个?上下文压缩的 3 种姿势

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG 召回 20 个文档不如 3 个?上下文压缩的 3 种姿势

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%

召回越多,准确率反而越低。原因很简单:

  1. 大模型不是"把所有文档读完再回答"——它在做注意力加权,噪声文档抢走了注意力
  2. 20 个文档里可能有 15 个跟问题弱相关但关键词撞上了,它们干扰了模型判断
  3. 上下文窗口是稀有资源——喂满 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 个文档,全量注入docs=vector_store.similarity_search(query,k=20)context="\n".join([d.page_contentfordindocs])# → 12000 tokens 文档,其中 15 个弱相关,准确率 62%# ✅ 改造后:检索 20 → Rerank → 取 Top-5fromcohereimportClient docs=vector_store.similarity_search(query,k=20)# 粗筛reranker=Client(api_key="...")scores=reranker.rerank(query=query,documents=[d.page_contentfordindocs],model="rerank-v3.5")# 取相关性最高的 5 个top_docs=sorted(zip(docs,scores.results),key=lambdax:x[1].relevance_score,reverse=True)[:5]context="\n---\n".join([d[0].page_contentfordintop_docs])# → 3000 tokens 高相关文档,准确率 89%

对比数据

指标召回 20 不分Rerank Top-5
答案准确率62%89%
上下文 token12,0003,000
额外耗时0ms+200ms
额外费用$0~$0.001/次 (Cohere)

一句话:Reranking 是你应该加的第二个 RAG 步骤。第一个是向量检索,第二个就是它。


姿势二:LLM 摘要压缩——对付长文档的利器

什么时候用

Reranking 只解决了"选哪些文档"的问题,但没解决"文档太长"的问题。如果 Top-5 文档每个 3000 字,5 个加起来 15000 字,还是塞爆。

这时候用 LLM 做一步"浓缩"。

代码

defcompress_docs_with_llm(docs,query,max_tokens_per_doc=200):"""用 LLM 将每个文档压缩为与 query 相关的 1-2 句摘要"""compressed=[]fori,docinenumerate(docs):# 只压缩超过 max_tokens 的文档ifcount_tokens(doc.page_content)<=max_tokens_per_doc:compressed.append(doc.page_content)continueprompt=f"""将以下文档内容压缩为一句话要点。 只保留与用户问题直接相关的信息,无关细节全部删除。 用户问题:{query}文档内容:{doc.page_content}一句话要点:"""summary=llm.invoke(prompt)compressed.append(f"[文档{i+1}]{summary}")return"\n---\n".join(compressed)# 使用top_docs=rerank_and_pick(docs,query,top_k=5)# 先 Rerankcompressed_context=compress_docs_with_llm(top_docs,query)# 15000 字 → 约 800 字压缩版

效果

指标Rerank Top-5 (未压缩)Rerank + LLM 压缩
上下文 token4,5001,200
答案准确率89%91%
额外耗时+200ms+800ms
额外费用~$0.001~$0.003

准确率还涨了——因为 LLM 在摘要时帮模型排除了更多噪声。


姿势三:分层抽取——结构化数据的终局方案

什么时候用

当你的文档本身就是结构化的——法律法规条款、合同条款、订单信息、产品参数——不要保留原文,直接抽字段。

代码

# ❌ 渣方案:把整条法规原文注入"《个人信息保护法》第十七条:个人信息处理者在处理个人信息前,应当以显著方式、清晰易懂的语言 真实、准确、完整地向个人告知下列事项:(一)个人信息处理者的名称或者姓名和联系方式; (二)个人信息的处理目的、处理方式,处理的个人信息种类、保存期限;..."# ✅ 分层抽取:只保留结构化字段defextract_legal_clause(doc,query):"""从法规文档中抽取与 query 相关的结构化条款"""extracted=llm.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_laogao,10 年+ AI/架构经验,专注大模型应用落地与上下文工程。
你在 RAG 项目里召回几个文档?答案质量怎么样?评论区聊聊。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 4:09:32

【计算机毕业设计案例】基于 Java 的医用器械库存统计管理系统的设计与实现 基于 Java 的医院设备档案信息化管理系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/2 4:08:24

闵行区家政服务哪家服务好

在闵行区寻找可靠的家政服务时&#xff0c;许多家庭会关注服务人员的专业素质、公司的管理规范以及后续的保障。上海尚情家政服务有限公司成立于2021年7月&#xff0c;是一家专注提供多样化家庭服务的企业&#xff0c;服务范围覆盖闵行区及周边区域&#xff0c;涵盖保姆、钟点工…

作者头像 李华
网站建设 2026/7/2 4:05:14

小白从零学习漏洞挖掘!该掌握哪些技术?在哪挖、怎么挖一文讲透

小白从零学习漏洞挖掘&#xff01;该掌握哪些技术&#xff1f;在哪挖、怎么挖一文讲透 漏洞挖掘是合法合规的安全实践&#xff0c;核心是 “先学基础、再练靶场、合规实战”&#xff0c;新手不用怕门槛高&#xff0c;按步骤推进就能逐步上手。 一、新手必备&#xff1a;3 大核…

作者头像 李华
网站建设 2026/7/2 4:01:16

【每日一题】LeetCode 33. 搜索旋转排序数组 TypeScript

整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 向左旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], …

作者头像 李华