上下文压缩与检索优化
深入分析LLM上下文压缩技术,包括KV Cache压缩、Prompt压缩、RAG增强检索等方案,以及层次化摘要等工程实践。
KV Cache压缩:减少显存占用的核心手段
H2O:Heavy-Hitter Oracle
H2O基于一个关键观察:少量KV对贡献了绝大部分注意力权重。在典型注意力分布中,前20%的KV对占据约85%的注意力质量。
核心算法:
- 累积注意力分数:追踪每个KV对在所有query中的累积attention score
- 保留Heavy Hitters:只保留分数最高的个KV对(如)
- 滑动窗口:始终保留最近的个token(保证局部连贯性)
flowchart TD
A[输入KV Cache<br/>长度L] --> B{计算累积注意力分数}
B --> C[全局Top-K<br/>保留Heavy Hitters]
B --> D[局部滑动窗口<br/>保留最近W个]
C --> E[合并保留集合]
D --> E
E --> F[压缩后KV Cache<br/>长度≈K+W]
F --> G[后续层使用<br/>压缩KV]
性能数据(在LLaMA-2-7B上):
| 配置 | KV Cache大小 | 长文本QA准确率 | 压缩率 |
|---|---|---|---|
| 无压缩 | 100% | 82.5% | - |
| H2O (K=10%, W=256) | 12.5% | 80.1% | 87.5% |
| H2O (K=20%, W=512) | 25.0% | 81.8% | 75.0% |
| H2O (K=30%, W=1024) | 37.5% | 82.2% | 62.5% |
关键发现:保留20% Heavy Hitters + 512滑动窗口,可在减少75%显存的同时保持99%的准确率。
SnapKV:自适应压缩
SnapKV改进了H2O的静态策略,采用自适应压缩率:
- 对注意力稀疏的层使用更高压缩率
- 对注意力密集的层保留更多KV
- 根据输入动态调整保留比例
自适应公式:
其中为第层的注意力矩阵,衡量注意力分布的集中程度。
优势:
- 平均压缩率提升至80-85%
- 准确率损失<2%
- 支持动态长度输入
KV Cache量化
量化是另一类压缩手段,将FP16的KV Cache压缩到更低精度:
| 精度 | 每token存储 | 相对FP16 | 准确率损失 |
|---|---|---|---|
| FP16 | 2 bytes/dim | 100% | 0% |
| INT8 | 1 byte/dim | 50% | <1% |
| INT4 | 0.5 bytes/dim | 25% | 2-3% |
| 2-bit | 0.25 bytes/dim | 12.5% | 5-8% |
KVQuant技术:
- 分组量化:每64个token为一组共享缩放因子
- 离群值保留:对极端值使用FP16单独存储
- 动态范围调整:根据激活分布调整量化范围
实际效果:
- 4-bit量化可将128K上下文的KV Cache从64GB压缩到16GB
- 在A100 40GB上可支持64K上下文推理
- 延迟增加<5%(量化/反量化开销)
Prompt压缩:减少输入长度
LLMLingua:基于困惑度的压缩
LLMLingua采用小型语言模型(如GPT-2)对prompt进行压缩:
- 分块计算困惑度:将prompt分块,计算每块的perplexity
- 保留信息密度高的块:移除低困惑度(信息量少)的块
- 语义连贯性检查:确保压缩后的prompt语义完整
压缩效果:
| 任务类型 | 原始长度 | 压缩后 | 压缩率 | 准确率保持 |
|---|---|---|---|---|
| 多文档QA | 16K | 6K | 62.5% | 96% |
| 代码生成 | 12K | 5K | 58.3% | 94% |
| 长对话 | 20K | 7K | 65.0% | 92% |
Selective Context:基于自信息
Selective Context利用token级别的自信息(self-information)进行压缩:
自信息低的token(即模型容易预测的token)通常信息量小,可以移除。
优势:
- 细粒度压缩,可精确到token级别
- 保持关键实体和术语
- 支持结构化压缩(保留句子边界)
LongLLMLingua:面向长上下文的优化
针对长文档检索任务,LongLLMLingua引入:
- 问题感知压缩:根据query调整压缩策略
- 重排序增强:压缩后重新计算文档与query的相关性
- 多粒度压缩:文档级→段落级→句子级分层压缩
flowchart LR
subgraph 原始文档["原始文档 (100K)"]
D1[Doc1] --> D2[Doc2]
D2 --> D3[Doc3]
D3 --> D4[...]
end
subgraph 粗筛选["文档级筛选 (20K)"]
S1[Doc1] --> S3[Doc3]
S3 --> S5[Doc5]
end
subgraph 精压缩["段落级压缩 (8K)"]
C1[Para1] --> C2[Para3]
C2 --> C3[Para7]
end
subgraph 最终Prompt["最终Prompt (4K)"]
F1[压缩结果]
end
原始文档 -->|BM25粗筛| 粗筛选
粗筛选 -->|LLM重排序| 精压缩
精压缩 -->|困惑度过滤| 最终Prompt
RAG增强:检索而非记忆
基础RAG架构
检索增强生成(RAG)将长上下文问题转化为检索问题:
flowchart TD
A[长文档集合] --> B[文档切分<br/>Chunking]
B --> C[向量化<br/>Embedding]
C --> D[向量数据库<br/>FAISS/Milvus]
E[用户Query] --> F[Query向量化]
F --> G[相似度检索<br/>Top-K]
D --> G
G --> H[检索结果<br/>K个Chunks]
H --> I[Prompt构建<br/>Query + Chunks]
I --> J[LLM生成<br/>短上下文]
关键参数:
- Chunk大小:通常256-512 tokens
- 重叠:20-50%以避免边界信息丢失
- Top-K:5-10个chunks
长上下文RAG优化
标准RAG在超长文档(如整本书)上的局限:
- 检索粒度太细,丢失全局结构
- 多跳推理困难(需要跨多个chunk推理)
改进方案:
-
分层索引:
- 第一层:章节级粗粒度索引
- 第二层:段落级细粒度索引
- 先粗筛再精排
-
摘要增强检索:
- 为每个chunk生成一句话摘要
- 先检索摘要,再获取完整chunk
- 减少向量噪声
-
重排序(Reranking):
- 初筛:向量相似度召回Top-100
- 精排:Cross-encoder计算query-document相关性
- 最终保留Top-5
Self-RAG:自适应检索
Self-RAG让模型自己决定何时检索、检索什么:
- 反思token:模型在生成过程中输出特殊token(如[Retrieve])
- 按需检索:只在需要事实验证时触发检索
- 多次检索:支持多跳推理的多次迭代检索
效果对比(在Natural Questions上):
| 方法 | 准确率 | 平均检索次数 | 延迟 |
|---|---|---|---|
| 无RAG | 42.3% | 0 | 1x |
| 标准RAG | 58.7% | 5 | 2.5x |
| Self-RAG | 62.1% | 2.3 | 1.8x |
关键优势:Self-RAG用更少的检索次数获得更高的准确率,延迟降低28%。
层次化摘要:渐进式压缩
多级摘要架构
对于超长文档(如100K+),采用金字塔式摘要:
flowchart TD
L0[原始文档<br/>100K tokens] --> L1
subgraph L1["第1层摘要 (20K)"]
S1[段落摘要1<br/>~200字]
S2[段落摘要2<br/>~200字]
S3[...<br/>100个段落]
end
L1 --> L2
subgraph L2["第2层摘要 (4K)"]
SS1[章节摘要1<br/>~500字]
SS2[章节摘要2<br/>~500字]
SS3[...<br/>8个章节]
end
L2 --> L3[全局摘要<br/>1K tokens]
查询流程:
- 基于全局摘要定位相关章节
- 在章节摘要中定位相关段落
- 读取原始段落获取细节
动态摘要生成
不预先生成所有摘要,而是按需生成:
- 流式处理:边读取文档边生成摘要
- 增量更新:新信息到来时更新摘要
- 遗忘机制:移除过时或低优先级信息
Map-Reduce摘要:
- Map阶段:并行生成段落摘要
- Reduce阶段:递归合并摘要
- 支持任意长度文档
混合策略:组合多种技术
最佳实践架构
flowchart TD
A[长文档输入<br/>>32K] --> B{长度判断}
B -->|<32K| C[直接输入]
B -->|32K-128K| D[RAG + 压缩]
B -->|>128K| E[分层摘要 + RAG]
D --> D1[LLMLingua压缩<br/>50%]
D --> D2[H2O KV Cache<br/>保留30%]
D1 --> D3[LLM处理]
D2 --> D3
E --> E1[三级摘要]
E --> E2[向量检索Top-10]
E1 --> E3[构建Prompt]
E2 --> E3
E3 --> E4[YaRN外推<br/>128K→256K]
E4 --> E5[4-bit KV Cache]
E5 --> E6[LLM生成]
性能与成本权衡
| 方案组合 | 最大支持长度 | 准确率 | 推理成本 | 适用场景 |
|---|---|---|---|---|
| 原生+YaRN | 128K | 90% | 1x | 通用场景 |
| YaRN+KV压缩 | 256K | 88% | 0.7x | 资源受限 |
| RAG+YaRN | 1M+ | 85% | 1.5x | 文档检索 |
| 分层摘要+RAG | 10M+ | 82% | 2.0x | 知识库问答 |
参考资料
-
H2O: Heavy-Hitter Oracle for Accurate KV Cache Compression (Zhang et al., 2023)
- KV Cache压缩的开创性工作,Heavy-Hitter发现
-
- 基于困惑度的Prompt压缩
-
Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (Lewis et al., 2020)
- RAG基础架构
-
Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection (Asai et al., 2023)
- 自适应检索机制
-
LongLLMLingua: Accelerating and Enhancing LLMs in Long Context Scenarios (Jiang et al., 2023)
- 面向长上下文的RAG优化
-
SnapKV: Efficient KV Cache Compression for Long-Context Inference (Li et al., 2024)
- 自适应KV Cache压缩