一个反直觉的发现
2023 年底,MIT 和 Meta 的研究团队发现了一个奇怪的现象:在所有主流 Transformer 模型中,第一个 token 总是会接收到远超正常水平的注意力权重——即使它只是一个毫无语义意义的 <BOS>(Begin of Sentence)标记。
这就是 Attention Sink 现象。
更奇怪的是:如果你在推理时把第一个 token 的 KV Cache 删掉,模型的输出质量会急剧下降,即使那个 token 距离当前生成位置已经有几千步之遥。
这篇论文(Efficient Streaming Language Models with Attention Sinks, ICLR 2024)不仅解释了这个现象的成因,还基于它构建了一个极其实用的系统——StreamingLLM,让预训练好的 LLM 无需微调就能处理理论上无限长的文本流。
Attention Sink 的成因
Softmax 的”垃圾桶”效应
自注意力的核心公式是:
Attention(Q, K, V) = softmax(QK^T / √d_k) · V
Softmax 函数有一个重要特性:它的输出必须归一化为概率分布(总和为 1)。当一个 query token 对所有 key token 都没有强烈的语义相关性时,注意力权重仍然必须分配到某个地方。
初始 token 因为两个原因成为了这个”垃圾桶”:
- 位置编码的边界效应:RoPE 等旋转位置编码在位置 0 处有特殊的数值特性,使得初始 token 的 key 向量天然具有较大的内积
- 训练数据的统计偏差:在预训练语料中,初始 token 出现在每个样本中,模型学会了把”不确定放哪里”的注意力分配给它
量化验证
论文对 Llama-2、Falcon、Pythia 等多个模型族进行了分析,发现:
- 超过 96% 的注意力头在至少部分层中呈现 Attention Sink 现象
- 前 1-4 个 token 平均吸收了约 30-65% 的注意力权重
- 这一现象在不同模型规模(160M 到 70B)和架构中普遍存在
传统长上下文方案的问题
在理解 Attention Sink 之后,我们可以重新审视现有的长上下文处理方案:
方案 1: 完整 KV Cache
保留所有 token 的 KV Cache。精度最高,但内存占用是 O(n) 的:
| 模型 | 上下文长度 | KV Cache 大小 |
|---|---|---|
| Llama-3 70B | 8K | 2.5 GB |
| Llama-3 70B | 128K | 40 GB |
| Llama-3 70B | 1M | 312 GB |
1M 上下文的 KV Cache 比模型权重本身还大。不可接受。
方案 2: 滑动窗口(Sliding Window)
只保留最近 N 个 token 的 KV Cache,丢弃更早的。内存固定,但有一个致命问题:
当滑动窗口移过初始 token 时,模型输出会崩溃。
这正是 Attention Sink 解释的现象——模型失去了注意力的”锚点”,Softmax 的数值稳定性被破坏,导致注意力分布变得混乱。
方案 3: RoPE 外推
通过修改位置编码的频率基数(如 YaRN)或使用分段线性外推(LongRoPE),让模型在训练窗口之外仍能工作。这需要额外的微调,而且外推倍数越大精度损失越明显。
StreamingLLM:优雅的工程方案
StreamingLLM 的核心 idea 极其简单:
保留前 K 个 Sink Token 的 KV Cache + 最近 W 个 token 的滑动窗口,丢弃中间的所有缓存。
[sink_1, sink_2, sink_3, sink_4, ...(丢弃)..., recent_W-3, recent_W-2, recent_W-1, recent_W]
典型配置是 K=4, W=252,总共只保留 256 个 token 的 KV Cache。
为什么有效
- Sink Token 提供了注意力的”锚点”,维持 Softmax 的数值稳定性
- 滑动窗口保留了最近的上下文,足以支撑生成质量
- 中间被丢弃的 token 对当前生成的实际贡献极小(注意力权重衰减)
实现伪代码
class StreamingLLM:
def __init__(self, model, sink_size=4, window_size=252):
self.model = model
self.sink_size = sink_size
self.window_size = window_size
self.kv_cache = None
def process_token(self, token):
# 正常前向传播,更新 KV Cache
output, new_kv = self.model.forward(token, self.kv_cache)
# 如果 KV Cache 超过上限,执行驱逐
cache_len = self.kv_cache.shape[1] if self.kv_cache else 0
if cache_len > self.sink_size + self.window_size:
# 保留前 sink_size 个 + 后 window_size 个
sink = self.kv_cache[:, :self.sink_size, :]
window = self.kv_cache[:, -self.window_size:, :]
self.kv_cache = torch.cat([sink, window], dim=1)
return output
性能数据
论文在 Llama-2 7B 上的实验数据:
| 方案 | Perplexity (20K tokens) | 内存 | 延迟 |
|---|---|---|---|
| 完整 KV Cache | 5.04 | 40 GB | 1x |
| 滑动窗口 (无 Sink) | 崩溃 (>100) | 0.5 GB | 0.8x |
| StreamingLLM | 5.18 | 0.5 GB | 0.045x |
| RoPE 外推 (YaRN) | 5.12 | 20 GB | 0.5x |
StreamingLLM 的 Perplexity 仅比完整缓存高 2.8%,但延迟降低了 22 倍。
2026 年的进展:从 StreamingLLM 到 Sink Token 训练
原始的 StreamingLLM 有一个限制:它依赖模型预训练时自然形成的 Sink Token,而这些 token 通常是 BOS 等特殊标记。
2025-2026 年的后续研究引入了 显式 Sink Token 训练:
Dedicated Sink Token
在预训练时在序列开头添加专门的 <SINK> token,并在训练目标中强制让注意力集中到这些 token 上。好处是:
- Sink Token 的功能更稳定、更可控
- 不再占用有语义意义的位置
- 可以调整 Sink Token 的数量以适配不同的任务
Multi-Scale Attention Sink
将 Sink Token 扩展为多尺度:
- Local Sink: 每 1024 个 token 插入一个局部 sink
- Global Sink: 序列开头的全局 sink
这样中间被丢弃的 token 的信息可以部分压缩到局部 sink 中,减少信息丢失。
工程落地场景
场景 1: 实时对话系统
用户和 AI 的对话可能持续数小时,传统方案需要不断截断对话历史。StreamingLLM 让模型保持最近 N 轮对话的完整上下文,同时内存占用恒定。
场景 2: 日志流分析
服务器日志是无限流。StreamingLLM 配合 vLLM 的 PagedAttention,可以持续分析日志流中的异常模式,不需要批处理。
场景 3: 实时翻译/字幕
视频会议的同传场景需要低延迟 + 长时间运行。StreamingLLM 的固定内存和低延迟特性完美匹配。
与其他技术的组合
StreamingLLM 不是银弹,但它可以和其他技术组合:
| 组合 | 适用场景 |
|---|---|
| StreamingLLM + RAG | 流式处理中遇到需要深度回溯的问题时,触发 RAG 检索补充上下文 |
| StreamingLLM + Speculative Decoding | 在流式推理中进一步降低延迟 |
| StreamingLLM + 量化 | INT4 量化 + StreamingLLM 可以在消费级 GPU 上运行 70B 模型的流式推理 |
| Sink Token + Flash Attention 3 | Flash Attention 的 IO 优化与 Sink 的缓存驱逐策略互补 |
我的判断
Attention Sink 论文的核心贡献不是 StreamingLLM 本身——那只是一个工程应用——而是揭示了 Transformer 注意力机制中一个基本的结构性特征。
这个发现对整个 LLM 领域的影响包括:
- 位置编码设计:未来的位置编码方案需要显式处理 Sink 效应
- KV Cache 优化:所有的 KV Cache 压缩方案(GQA、MQA、量化)都需要考虑 Sink Token 的特殊性
- 模型架构:Mamba 等 SSM 模型不存在 Attention Sink(因为没有 Softmax),这可能是它们在极长序列上表现更稳定的原因之一
2026 年的趋势是:原生长上下文(1M+)模型处理大多数场景,StreamingLLM 类方案处理”真正无限”的流式场景。两者不是竞争关系,而是互补。