3 为什么上下文里要去重、排序和压缩
1️⃣ 考察意图
面试官真正想看的不是你会背“去重、排序、压缩”三个词,而是考察你对RAG系统上下文构建这一关键环节的工程取舍和系统级理解。刁钻点在于:很多人只关注检索召回率,却忽略了上下文质量对LLM生成效果的致命影响——垃圾进垃圾出。答好了能展示:你不仅懂RAG流水线,还能量化每个预处理步骤对token成本、推理延迟、答案准确率的实际影响,具备从数据到模型的端到端优化思维。
2️⃣ 标准答
RAG中检索出的原始片段是脏数据:重复、噪声、排序混乱。直接喂给LLM会导致lost-in-the-middle(中间位置信息被忽略)、token浪费(上下文窗口被冗余填充)、幻觉放大(矛盾信息干扰)。去重、排序、压缩是上下文净化三件套,缺一不可。
1. 去重:消除冗余,稳定注意力分布
- 为什么做:多路检索(如同时用BM25和DPR)或重叠分块(chunk overlap)会产生大量语义重复片段。LLM看到重复信息会注意力坍缩——重复token的注意力权重被稀释,导致关键信息被淹没。
- 怎么做:两阶段去重。粗去重用MinHash LSH(Jaccard相似度阈值0.7-0.8),适合文本级去重;精去重用embedding余弦相似度(如bge-large-en-v1.5,阈值0.85-0.9),捕捉语义重复。实际落地坑:阈值设太低会误杀相关片段(如“苹果公司”和“Apple Inc.”),设太高则漏掉重复。解法:对query做动态阈值——query越长、信息密度越高,阈值调低(0.8→0.75)。
- 工程取舍:去重节省token但可能丢失多样性。例如法律合同条款,重复是刻意强调,去重会丢失上下文。此时应保留重复但标记频次,让LLM自行判断。
2. 排序:对抗lost-in-the-middle
- 为什么做:LLM对长上下文的注意力呈U型分布——开头和结尾效果最好,中间最差(Liu et al., 2023)。不排序的话,最相关片段可能被埋在中间,导致答案质量下降10-20%。
- 怎么做:两阶段排序。第一阶段用BM25或DPR做粗排(速度优先,top-100→top-20);第二阶段用交叉编码器(cross-encoder,如Cohere rerank-v3或BGE-reranker-v2)做精排(精度优先,top-20→top-5)。精排后按相关性降序排列,将最相关片段放在开头(LLM最关注位置)。
- 实际落地坑:交叉编码器推理慢,对20个片段rerank需要200-500ms。解法:级联排序——先粗排砍到top-10,再精排,延迟降低60%。另一个坑:排序后片段顺序打乱,丢失原始文档的局部连贯性。解法:精排后对相邻片段做滑动窗口重排,保持同一文档内的段落顺序。
3. 压缩:控制上下文,降低噪声
- 为什么做:LLM上下文窗口有限(如GPT-4o 128K,但长上下文推理成本高、延迟大)。检索出的片段中常含大量无关细节(如网页导航栏、广告),直接喂入会稀释信号。
- 怎么做:三种策略。抽取式压缩:用规则(如提取前N句)或模型(如BERT提取关键句)保留核心信息;生成式压缩:用LLM对每个片段做摘要(如“用50字概括”),但成本高;结构化压缩:将片段转为键值对或表格(如“时间:2023;事件:融资”),适合事实性问答。
- 工程取舍:生成式压缩质量高但延迟大(每片段需1次LLM调用)。实际落地:对高置信度片段(精排top-3)用生成式压缩,其余用抽取式压缩,平衡质量与速度。坑:压缩后可能丢失推理链(如多步计算过程),导致LLM无法推导。解法:对数学/逻辑类query,保留原始片段,不做压缩。
4. 综合策略:先粗排去重,再精排,最后压缩
- 标准流水线:检索→MinHash去重→BM25粗排→embedding精去重→交叉编码器精排→LLM生成式压缩(top-3)→拼接为上下文。
- 评估:在NQ数据集上做消融实验,去重提升F1约2-3%,排序提升5-8%,压缩提升1-2%(主要节省token)。关键指标:token节省率(去重+压缩可减少40-60% token)、首token延迟(排序+压缩降低30%)。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:去重解决冗余导致的注意力稀释和token浪费,常用MinHash+embedding相似度两阶段去重;排序对抗lost-in-the-middle,用BM25粗排+交叉编码器精排将最相关片段放开头;压缩控制上下文长度,对高置信度片段用LLM摘要、其余用抽取式。总结一句:这三步是RAG上下文净化的标配,缺一不可,能提升F1 5-10%并节省40% token。”
4️⃣ 高频追问 & 应对
追问 1:如果用户query很短(如“苹果股价”),去重阈值怎么调?
短query下检索出的片段语义相似度高(都讲苹果股价),去重阈值应调高(如0.9),避免误杀。同时,短query的意图模糊,去重后保留多样性——保留不同时间点的股价片段(2023 vs 2024),让LLM自行选择。具体做法:对embedding做聚类(k-means,k=3),每类保留1个代表性片段。
追问 2:排序后为什么还要压缩?直接截断前N个token不行吗?
直接截断是暴力解法,会丢失关键信息。例如一个片段前半段是背景、后半段是答案,截断后答案丢失。压缩是智能截断:用模型提取核心信息,保留推理链。工程取舍:压缩增加延迟(每片段50-100ms),但能提升答案完整度。实际落地:对事实性query(如“谁发明了电灯”)用截断即可;对推理型query(如“为什么苹果股价下跌”)必须用压缩。
追问 3:去重和排序谁先谁后?顺序能换吗?
标准顺序是先去重再排序。原因:去重减少片段数量(从100到60),降低排序阶段的计算量(交叉编码器复杂度O(n²))。如果先排序再去重,精排阶段要处理100个片段,延迟翻倍。但有一个例外:当检索结果噪声极高(如网页爬虫质量差)时,先粗排(BM25)过滤掉低质量片段,再去重,避免去重阶段被噪声干扰。
5️⃣ 避坑 · 常见错误答法
- ❌ “去重就是删掉完全一样的文本,排序就是按相似度降序,压缩就是截断前500字。” → ✅ “去重要考虑语义相似度(embedding阈值),排序要用交叉编码器对抗lost-in-the-middle,压缩要区分抽取式和生成式,不能一刀切截断。”
- ❌ “这三步顺序无所谓,反正最后效果差不多。” → ✅ “顺序有严格工程考量:先去重减少排序计算量,再排序保证相关性,最后压缩控制上下文。顺序错了会导致延迟翻倍或信息丢失。”
- ❌ “压缩用LLM摘要最好,质量最高。” → ✅ “LLM摘要成本高、延迟大,只适合高置信度片段;对低置信度片段用抽取式压缩更划算。要按片段重要性分级处理。”
6️⃣ 简历呼应
- 如果你有RAG项目:从“消融实验”角度切入,说明你在项目中对比了有无去重/排序/压缩的F1差异,并量化了token节省率(如40%)。强调你用了动态阈值去重和级联排序,解决了延迟问题。
- 如果你只做过传统NLP:用“文本预处理”类比——去重类似数据清洗(去停用词),排序类似特征选择(按重要性排序),压缩类似文本摘要。迁移到RAG时,强调LLM对上下文敏感性的特殊性(lost-in-the-middle)。
- 如果你是校招无项目:聚焦论文复现——读过Liu et al. (2023)的lost-in-the-middle论文,并实现了一个demo:用BM25+Cohere rerank在MS MARCO上验证了排序对答案准确率的影响。展示你对交叉编码器、MinHash等工具的理解。
- Liu et al. (2023) Lost in the Middle: How Language Models Use Long Contexts
- MinHash LSH for near-duplicate detection (Broder, 1997)
- Cohere Rerank API 文档与交叉编码器原理
- BGE-reranker-v2 论文与开源模型
- LangChain 文档:Contextual Compression Retriever 实现