一个长期运行的 Agent 最终会碰到一个很直接的资源问题:每生成一个新 Token,都需要把对应的 Key 和 Value 追加到 KV Cache。只要历史一直保留,缓存占用就会随运行时间持续增长。无论模型本身支持多大的位置范围,GPU 显存都不可能无限扩张。
最直觉的办法是只保留最近一段历史。例如缓存窗口固定为 4096 个 Token,每产生一个新 Token,就淘汰最旧的一个。这样缓存容量从随时间增长变成固定大小,看起来非常适合日志监控、实时语音、机器人控制和长期 Agent。但实际使用普通滑动窗口时,一个反直觉现象会出现:如果最开头的少量 Token 也被一起删除,模型的流式语言建模质量可能明显恶化。Attention Sink 研究关注的正是这个现象。
KV Cache 固定窗口为什么仍然可能失效
标准自回归推理会为历史 Token 保存各层的 K/V。新 Token 到来时,当前 Query 可以直接读取这些缓存,而不必重新计算全部历史。缓存因此同时承担两个角色:一是避免重复计算,二是定义当前 Token 能直接访问的历史范围。
假设服务只允许保留最近四个位置,序列已经从 A B C D 继续生成到 E F G H。最简单的滑动策略会逐步把 A B C D 全部淘汰,最终缓存只剩 E F G H。从“最近信息最有价值”的直觉看,这没有问题。但 Attention 并不是纯粹按语义重要程度访问历史。StreamingLLM 的实验观察到,在其分析的模型中,一些 Attention Head 会持续把明显的注意力权重分配给序列开头位置,即使这些位置上的 Token 本身并没有特殊语义。
这意味着缓存淘汰不是单纯的信息摘要问题。删除一个早期 Token,不仅意味着“模型以后看不到这个词”,还可能改变某些 Attention Head 已经适应的归一化结构。若这些 Head 长期依赖初始位置作为稳定的注意力承载点,那么把所有早期位置一刀切掉,执行分布就可能偏离训练时常见的模式。
因此,普通 Sliding Window 的基线失败可以概括为:它正确控制了缓存容量,却假设“最旧位置一定可以安全删除”。Attention Sink 现象说明,这个假设对部分预训练 Transformer 并不成立。
Attention Sink 是什么,以及它不是什么
Attention Sink 可以理解为:某些初始位置会稳定吸收一部分 Attention 权重。这里的“Sink”描述的是观察到的注意力分配现象,不意味着这些 Token 在语义上承担了特殊知识,也不意味着模型把所有无用信息都真正存进了第一个 Token。
一种常见直觉解释来自 softmax Attention。每个 Query 对可见 Key 计算分数后,需要经过 softmax 得到归一化权重。即使当前没有特别值得关注的历史位置,权重仍然需要形成一个归一化分布。因果 Attention 中,最早位置对后续大量 Token 都长期可见,因此它可能成为一种稳定的权重承载位置。模型训练久了之后,一些 Head 可能逐渐利用这种结构。
这是一种有助于理解现象的机制性解释,但不应把它写成 Attention Sink 的唯一已证实成因。后续研究正在从巨大激活、表示压缩、中间层特征变化等角度解释 Sink 为什么形成。也就是说,“注意力垃圾桶”可以帮助建立直觉,却不能替代对模型内部动力学的完整解释。
更重要的是,Attention 权重高也不能直接等价为“这个 Token 的语义最重要”。Attention 既参与信息聚合,也受归一化、位置、Head 分工和训练动态影响。工程上使用 Sink 的依据,是保留这些位置能稳定流式推理,而不是把第一个 Token 解读成模型的长期记忆中心。
StreamingLLM 的核心:固定 Sink,加上最近窗口
StreamingLLM 对普通滑动窗口做的关键调整非常小:不再只保留最近 Token,而是固定保留最前面的少量 Token,再把剩余缓存预算给最近窗口。
例如缓存预算是 4096 个 Token,可以形成类似结构:
[Sink 1][Sink 2][Sink 3][Sink 4] [最近 4092 个 Token]
固定保留 持续滑动
随着新 Token 不断产生,中间旧历史仍然会被淘汰,但开头的 Sink 位置不进入普通淘汰队列。这样,缓存总量仍然保持固定,同时某些 Attention Head 依赖的稳定初始位置继续存在。
flowchart TD
A[新 Token 到达] --> B[读取当前 KV Cache]
B --> C[固定保留 Sink]
C --> D[保留最近窗口]
D --> E{缓存是否超预算}
E -->|否| F[追加新 KV]
E -->|是| G[淘汰最旧普通 KV]
G --> F
F --> H[执行下一步 Decode]
这条数据流里有两个不同的保留规则。Sink Token 按“特殊位置”长期保留,最近 Token 按时间窗口保留;两者之间的旧历史则可以被回收。实现时还必须保证位置编码、缓存索引和 Attention backend 对这种非连续缓存布局具有一致语义,不能只在数组层面删除元素就假定模型行为保持不变。
用户材料引用的 StreamingLLM 实验显示,对其测试的多种模型,保留很少的初始 Token 就足以显著改善流式稳定性。这个数字应理解为论文模型和实验设置中的观察,不代表所有模型都固定需要四个 Sink,也不代表任意架构都存在完全相同的 Sink 行为。
持续处理 400 万 Token,不等于拥有 400 万上下文
StreamingLLM 最容易被误解的地方,是“能持续处理很长的数据流”和“能直接访问全部历史”经常被混为一谈。
假设模型始终只保留 4 个 Sink Token 和 4092 个最近 Token。它可以连续处理 10 万、100 万甚至更长的数据流,因为缓存不会随着累计 Token 数无限增加。但在某个时刻,当前 Query 能通过 KV Cache 直接访问的仍然只是保留下来的有限位置。被滑动窗口淘汰的中间历史并没有隐藏在某个地方等待恢复。
因此,论文展示的数百万 Token 流式处理能力说明的是运行长度可以远大于缓存窗口,而不是模型已经获得同等长度的有效 Context Window。若用户在很早以前给出一个密码、项目约束或关键事实,随后该信息对应的 KV 被淘汰,那么单靠 StreamingLLM 不能在一百万 Token 之后重新召回它。
可以用下面的表区分几类容易混淆的能力:
| 技术/能力 | 保留什么 | 主要目标 | 旧信息被淘汰后能否直接恢复 | 更适合的场景 |
|---|---|---|---|---|
| 普通全量 KV Cache | 全部历史 KV | 完整保留上下文 | 可以,直到显存耗尽 | 有限长度高保真对话 |
| Sliding Window | 最近窗口 | 固定缓存容量 | 不可以 | 只依赖近期状态的数据流 |
| StreamingLLM | 少量 Sink + 最近窗口 | 固定缓存下保持流式稳定 | 不可以 | 长时间持续生成/监控 |
| 长上下文模型 | 更大的有效窗口 | 直接处理更远历史 | 窗口内可以 | 长文档、代码库、远距离推理 |
| 外部 Memory | 摘要、向量或结构化状态 | 跨窗口保存长期信息 | 通过检索重新注入 | 长期 Agent、用户记忆 |
这一区分直接影响系统设计。如果业务要求“持续运行但只关心最近状态”,StreamingLLM 类方案很匹配;如果业务要求几小时前的某项事实必须可精确召回,就需要额外的长期记忆机制,而不是继续缩小滑动窗口。
为什么它可能比窗口重算更快
控制 KV Cache 大小还有另一种实现:每当窗口向前移动,就取最新一段文本重新执行 Prefill,重建一个位置连续的新缓存。这样做可以保持固定窗口,但会反复计算大量最近 Token。
StreamingLLM 路线希望避免这种重复 Prefill。只要 Runtime 能正确维护 Sink 与滑动区的 KV,新 Token 到来时仍然只计算新位置,再淘汰过期缓存,而不必每移动一步就把整个窗口重新跑一遍。用户提供的论文材料报告,相比其 Sliding Window Recomputation 基线,在特定实验配置下最高观察到约 22.2 倍加速。这个数字比较的是论文中的具体基线与工作负载,不能直接换算成任意在线服务的端到端收益。
真实服务是否受益,需要看基线究竟做了多少重算。如果现有引擎本来就能高效维护滑动 KV,StreamingLLM 的性能优势更多来自稳定性而不是避免一整段重复计算;如果基线频繁重新 Prefill 长窗口,则减少重算会更明显地影响 GPU 时间和延迟。
工程验证时至少应同时观察 KV Cache 使用量、每 Token 延迟、窗口移动时是否出现延迟尖峰、Attention kernel 实际执行路径以及长时间生成后的质量变化。只看“显存保持不变”无法证明模型仍然稳定,只看短序列吞吐也无法暴露几万 Token 之后的退化。
Attention Sink 与真正的长期 Agent Memory 是两层问题
长期 Agent 通常同时面对短期状态和长期知识。最近几步工具调用、最新日志和当前任务状态需要低延迟访问,适合留在 Attention 可见窗口内;数小时前的业务事实、历史决策和用户偏好则不一定值得永久占用 KV Cache,但又不能彻底丢失。
因此,更实际的架构往往是分层记忆:
固定规则与工具定义
→ System Prompt / Prefix Cache
最近交互状态
→ Sink + Sliding KV Window
阶段性历史
→ Conversation Summary
长期事实
→ Memory Store / Database / Retrieval
Attention Sink 解决的是“滑动 KV 时不要破坏模型已经形成的注意力结构”,而外部 Memory 解决的是“已经离开 Attention 窗口的信息如何再次进入模型”。两者并不替代。
这也解释了为什么把 StreamingLLM 描述成“无限记忆”会导致错误架构。一个日志 Agent 可以连续看几个月的数据流,同时只保留最近几分钟的 KV;一旦需要回溯上周某次异常,它仍必须查询日志存储或检索系统。持续在线和长期记忆是两个不同能力。
专用 Sink Token 给模型设计带来了什么启发
StreamingLLM 的用户材料还提到一种更主动的思路:既然一些模型会自然把最初位置用作 Sink,那么训练时可以显式提供一个可学习的 Sink Token,让这种结构不必偶然落在普通文本 Token 上。
从架构角度看,这把“保留哪些起始 Token”从 Serving 侧经验规则推进到了训练设计。普通模型可能依赖几个自然出现的初始位置;显式 Sink Token 则让模型拥有一个专门、稳定的位置用于这种注意力行为。论文实验表明,这条路线在其设置中可以减少对多个普通初始 Token 的依赖。
但这里仍要区分研究结论与通用接口。现有任意预训练模型不能仅靠推理时凭空插入一个特殊 Token,就自动获得论文中“训练了 Sink Token”的效果。新增 Token 会改变输入分布和位置关系,是否有效取决于模型训练过程。对于已有模型,更稳妥的做法是使用经过验证的缓存策略,而不是在 Serving 层擅自修改词表或模型输入协议。
生产系统最容易踩的四个边界
第一类问题是把流式稳定等同于历史记忆完整。服务跑了百万 Token 没有崩溃,只能说明缓存管理和模型输出仍可持续;它不能证明模型还能回答百万 Token 之前的细节。测试必须包含“近期信息”和“已被淘汰信息”两类问题,确认业务真正需要哪一种能力。
第二类问题是Sink 数量写死。论文中少量初始 Token 有效,是特定模型族和实验设置下的观察。模型结构、训练方式、Attention 实现改变后,Sink 的数量和位置都可能不同。生产部署应通过长时间困惑度、生成质量或任务指标验证,而不是把某个数字当成协议常量。
第三类问题是缓存语义与位置语义不一致。滑动 KV 不是普通数组截断。RoPE、绝对位置、mask、缓存索引以及 kernel 可能依赖位置关系。若 Runtime 在移动缓存后错误重编号或错误处理位置,模型质量问题可能被误判成 Attention Sink 本身。启用流式缓存前,需要用固定输入与可靠基线做一致性测试。
第四类问题是只看平均延迟。长期流式请求更容易暴露周期性回收、显存碎片、缓存搬运或 fallback。除了平均 TPOT,还应该记录高分位 Token 延迟、缓存占用曲线、淘汰次数、重算 Token 数和长时间任务成功率。如果窗口每次移动都会产生明显停顿,说明实现仍可能在做昂贵的缓存重构。
Attention Sink 研究为什么从 Serving 走向模型机制
最早最实用的问题是:“为什么保留几个开头 Token,就能让滑动窗口稳定很多?”随着现象被更多工作分析,研究重点开始延伸到 Transformer 内部表示本身。用户提供的后续研究材料讨论了 Attention Sink、Massive Activations 与中间层表示压缩之间可能存在的联系,并提出类似 Mix–Compress–Refine 的解释框架。
这些工作值得关注,但目前不适合把某一种解释写成 Attention Sink 的最终理论。不同架构、规模和训练方案中的 Sink 是否由完全相同机制产生,仍然需要更广泛验证。2026 年相关综述把研究路线概括为利用、解释、缓解或消除 Sink,也说明这个问题已经不只是一个缓存技巧,而是一个仍在发展的 Transformer 机制研究方向。
对推理工程而言,最有价值的结论仍然很具体:在采用滑动 KV Cache 前,不要假设所有被淘汰的旧位置都等价;对于已知存在 Attention Sink 行为的模型,保留少量稳定初始位置可能是维持长期流式输出质量的关键条件。
如何判断自己的服务是否需要 Attention Sink 策略
可以从业务记忆需求开始,而不是先从算法名字开始。若请求总长度很短,KV Cache 根本没有增长到资源瓶颈,那么引入流式淘汰策略只会增加复杂度。若请求持续数小时,但任务只依赖近期状态,则固定窗口具有明确价值,此时应进一步比较纯 Sliding Window 与 Sink + Window 的质量和延迟。
测试至少应覆盖三个时间尺度:窗口以内、刚刚越过窗口、远超窗口。窗口以内用于确认新实现没有破坏普通短上下文行为;刚越过窗口用于观察删除最早普通 Token 时是否出现质量突变;远超窗口用于确认缓存确实保持有界,同时任务指标没有随着累计 Token 数持续崩坏。
如果业务还要求召回很久以前的信息,就应把外部 Memory 一起纳入测试。此时较合理的成功标准不是“模型永远不忘”,而是近期状态由固定 KV 窗口低延迟处理,长期事实在需要时由检索或结构化状态重新注入。Attention Sink 让这个短期窗口更稳定,但不会替系统完成长期知识管理。
从这个角度看,Attention Sink 最重要的工程意义并不是证明第一个 Token 有多神秘,而是提醒推理系统:KV Cache 中不同位置的作用并不完全同质。删除历史时,既要考虑语义信息是否还需要,也要考虑模型训练过程中形成的 Attention 结构是否依赖某些稳定位置。只有这两个条件同时满足,固定窗口才能从“显存不会增长”进一步变成“模型长期运行仍然可靠”。
资料来源
- Efficient Streaming Language Models with Attention Sinks
- StreamingLLM 官方实现
- StreamingLLM:一种能够接受近乎无限长度文本的大模型框架
- LLM 中的注意力匯聚(Attention Sinks)實現無限流暢度
- Attention Sinks and Compression Valleys in LLMs are Two Sides of the Same Coin
- Attention Sink in Transformers: A Survey on Utilization, Interpretation, and Mitigation
- 關於 Transformer 架構中的 Attention 機制