论文:Affix Cache for Diffusion Large Language Models 代码:github.com/sands-lab/ACache 时间:2026 年 6 月 26 日(arXiv v1) 机构:沙特阿卜杜拉国王科技大学(KAUST)+ 香港中文大学(CUHK)+ 巴基斯坦拉合尔管理科学大学(LUMS)。作者包括 Kaihua Liang、An Zhong、Xin Tan、Zafar Ayyub Qazi、Hong Xu、Jian Weng、Marco Canini。
一、论文背景
大语言模型的推理成本一直是产业落地的核心瓶颈,而 KV 缓存(KV Cache) 是自回归(AR)模型推理加速的基石。它的原理很直白:自回归模型按从左到右的因果注意力逐个生成 token,前面算过的 token 的 Key/Value 状态不会因为后面来了新 token 而改变,所以可以直接存起来复用。在真实服务场景中,大量请求共享同样的系统提示词、few-shot 示例或提示模板,**前缀缓存(Prefix Caching)**技术可以把这些共享前缀的 KV 缓存跨请求复用,省去重复的预填充计算——vLLM、SGLang 等主流推理框架都已内置这一能力。
与此同时,一类新的模型架构正在崛起:扩散语言模型(Diffusion Large Language Model, DLLM)。它借鉴图像扩散模型的思想,把文本生成建模为"从全部 [MASK] 出发、逐步去噪"的迭代过程。每个解码步中,模型对所有仍被遮盖的位置并行预测,然后只提交其中置信度最高的一部分。这种设计带来两大优势:一是天然支持并行解码,延迟更低;二是双向注意力让每个位置都能看到全局上下文,特别适合任意位置填充(infilling)等任务。LLaDA-8B、Dream-7B 等开源模型已经证明这条路线可以扩展到十亿参数规模。
但双向注意力是一把双刃剑。在 DLLM 中,每个 token 的表示都依赖于所有其他 token——包括提示词 token 的 KV 状态,也会随着生成内容的演化而变化。这意味着 KV 缓存不再是"只追加(append-only)“的:随着解码推进,缓存会不断"过期(stale)"。现有 DLLM 推理框架(Fast-dLLM、dLLM-Cache、dKV-Cache 等)不得不周期性地重算全部 KV 状态来维持上下文一致性,跨请求共享缓存更是无从谈起。这篇论文正是要解决这个"新旧架构红利错位"的问题。
二、论文定位和关联工作
论文的自我定位非常明确:第一个面向 DLLM 的跨请求缓存复用机制。围绕这个定位,相关工作可以分为三层。
DLLM 单请求内加速:dLLM-Cache 采用非对称复用策略——提示词特征按长间隔重算、响应特征更频繁更新;dKV-Cache 对已解码 token 的 KV 状态跨步复用、按固定块延迟重算;Fast-dLLM 利用块内时间局部性,在解码块内复用 KV、周期性全量重算,并结合并行解码。这些方法都在解决"单个请求内部"的缓存复用,但都绕不开周期性全量重算,也无法跨请求共享。ACache 与它们是正交关系:ACache 决定哪些共享缓存常驻、哪些锚点必须重算,单请求内的优化可以叠加在剩余计算上。
AR 模型的前缀缓存生态:Prompt Cache 支持模块化注意力复用,SGLang 实现了结构化程序的前缀复用,Preble 做分布式前缀调度,DualMap 兼顾缓存亲和与负载均衡。CacheBlend 则研究 AR 模型 RAG 场景下非前缀块的缓存融合——它与 ACache 的问题最接近,但其选择器基于 KV 偏差(HKVD),论文附录证明直接搬到 DLLM 上效果差 11 个点(详见后文消融)。
注意力信号驱动的 token 选择:H2O、Attention Sink 等 KV 压缩/驱逐工作都用注意力权重识别重要 token。ACache 同样使用注意力,但目的不同——不是剪掉不重要的 token,而是找出对请求上下文敏感的锚点来重算,让其余缓存可以安全共享。
三、问题定义
论文要解决的核心问题可以形式化为:给定 DLLM 推理中一段跨请求共享的连续文本段(论文称为 affix,即"词缀”,可以是前缀、中缀或后缀)F = {l, …, r},长度 L = |F|,现有框架在每个重算点都要对 F 中所有 token 重算 KV,成本为 O(L),即便这些文本在不同请求中完全相同。
问题的难点在于一对矛盾:
- 直接复用不行:双向注意力下,affix 的 KV 状态与该请求特有的生成 token 耦合。换个请求,生成内容不同,直接复用缓存的 KV 就是"过期"的,精度会崩塌(实验中 1-shot GSM8K 直接复用只有 37.28%,全量重算为 59.09%)。
- 全部重算太贵:共享文本段(如 few-shot 示例)往往很长,每个请求都全量重算 O(L) 等于放弃复用红利。
所以问题变成:能否找到一个远小于 L 的临界子集,只重算这个子集的 KV,就能让其余缓存"保鲜",既恢复精度又保留复用收益? 这等价于把重算成本从 O(L) 降到 O(K),K « L。
四、问题解法
ACache 的解法分三步:探针选锚、选择性重算、系统集成。
第一步:一次性锚点选择(Anchor Selection)。 在每个请求开始、解码循环启动之前,ACache 先做一次"探针"前向:把当前请求的非 affix 位置(包括被遮盖的生成区)作为 query,让它们与预先算好的 affix 缓存做一次注意力计算——affix 状态本身不前向更新。然后统计每个 affix token 收到的"被遮盖生成位置到它的注意力权重",对所有层、所有头、所有初始遮盖位求和,得到重要性分数 s_j,取 Top-K 作为该请求的锚点集 A,其余为非锚点集 S。
这个设计的依据是一个关键的实证观察(论文图 2):在 GSM8K 样本上,遮盖位到 affix 的注意力质量高度集中在少数 affix token 上,而且这些高排名位置在整个解码过程中保持稳定。也就是说,锚点可以一次选定、全程复用,不需要动态跟踪(动态变化的锚点集会带来重复探针和内存膨胀)。直观理解:锚点充当模型解读共享文本的"稳定语义参照点",请求特有上下文正是通过这些参照点与共享段建立联系的。
第二步:选择性重算(Selective Recomputation)。 每个共享 affix 的 KV 缓存只预计算一次,跨请求复用。每个请求构建"工作缓存"时:非锚点 affix 位置直接读共享缓存,锚点位置和所有请求特有位置(查询、生成区)在线重算。后续到达重算点时,也只重算同样的锚点位置加当前请求特有 token。这样重算成本从 O(L) 降为 O(K),且注意力看到的仍是完整的逻辑上下文。
第三步:系统原型。 作者在轻量级推理引擎 Nano-vLLM 上实现了共享前缀原型:KV 内存分为共享区(存一份共享前缀缓存)与私有区(每个请求存锚点与请求特有 token),配合两张映射表——写侧重算表(枚举要写入的私有槽位)和每请求读槽映射表(把每个逻辑位置绑定到共享区或私有区的物理槽位)。作者还定制了 Triton 注意力核,支持逻辑-物理槽位的间接寻址。准入时完成锚点选择并落表,在线路径只执行"选择性写 + 映射读";借鉴 ORCA 的调度思想,优先处理需要重算的请求,让解码批次保持饱满。
需要注意一个诚实的技术边界:受 Nano-vLLM 位置旋转后分页存储的限制,原型只实现了共享前缀;中缀/后缀的精度实验用 HuggingFace 后端验证了可行性,但端到端收益留待未来工作。
五、评估指标与实验证据
实验设置:两个开源 DLLM——LLaDA-8B-Instruct(从零训练的扩散模型)与 Dream-7B(AR 初始化的扩散模型);三个基准——GSM8K(数学推理)、MBPP(代码生成)、BABILong-0k/qa1(上下文检索);硬件为 A100-SXM4-40GB;生成长度 256、块长 32、置信度阈值 0.9。affix 分别放在前缀、中缀、后缀三个位置测试。
精度恢复(锚点率扫描实验):
| 设置(GSM8K) | 直接复用(锚点率 0) | ACache(锚点率 0.2) | 全量重算(锚点率 1.0) |
|---|---|---|---|
| LLaDA 1-shot | 37.28% | 52.61% | 59.09% |
| LLaDA 2-shot | — | 58.03% | 58.41% |
只重算约 20% 的 affix token,1-shot 就恢复了大部分精度损失(差距从 21.81 点缩到 6.48 点),2-shot 几乎追平全量重算(差 0.38 点)。中缀最难——因为它打断了"查询→答案"的信息流,尤其对 BABILong 这类检索式任务影响大,但锚点率 0.2-0.3 时同样能恢复。
系统效率(Nano-vLLM 原型,锚点率 0.2):
| 指标 | 最佳结果 | 典型数值 |
|---|---|---|
| 重算延迟降低 | 最高 55.7% | LLaDA GSM8K 4-shot batch16:200.4→88.8 ms |
| 端到端吞吐提升 | 最高 1.68× | LLaDA MBPP 4-shot batch16:206.0→346.9 tok/s |
| 峰值 KV 显存下降 | 最高 43.3% | LLaDA GSM8K 4-shot batch16:11.12→6.31 GB |
规律很清晰:共享段越长、batch 越大,收益越大。batch=4 与 batch=16 的全部设置均有加速;batch=1 时锚点探针的开销(每请求 48.1-74.0 ms,其中注意力探针占 98% 以上)无法摊薄,吞吐可能降为 0.65×-0.90×。
两个关键消融:
| 消融对比(LLaDA 1-shot,锚点率 0.2) | 精度 | 差距 |
|---|---|---|
| KeepNA(保留非锚点缓存,ACache 原设计) | 43.01% | — |
| DropNA(丢弃非锚点缓存) | 25.35% | -17.66 点 |
| ACache 注意力选择器 | 52.61% | — |
| CacheBlend 式 HKVD 选择器 | 41.57% | -11.04 点 |
第一个消融证明 ACache 不是 token 剪枝:非锚点的共享缓存仍然提供必要的上下文信息,丢掉它精度暴跌;锚点的作用是"让共享上下文与请求保持一致的适配器",而非"唯一有用的 token"。第二个消融证明锚点选择器必须用"遮盖生成位→affix"的注意力信号——CacheBlend 的 KV 偏差信号不知道生成位在看哪里,在 MBPP 和 BABILong 上尤其吃亏。
六、效果优势的根源解释
按照"方法差异 → 机制变化 → 指标提升"的因果链来拆解 ACache 为什么有效。
方法差异一:用"遮盖生成位→affix 的注意力"选锚,而不是用 KV 偏差或注意力总量。 机制变化:选出的锚点恰好是生成内容最依赖、也最容易受请求上下文影响的 affix token——它们是共享段与请求之间信息流动的"关口"。而 HKVD 只看"缓存前后 KV 差多少",不知道生成位实际看哪里,选出的锚点与真实依赖错位。指标提升:同样 20% 重算预算下,ACache 比 HKVD 变体高 11.04 点。
方法差异二:只重算锚点+请求特有位置,而非全量重算或干脆丢弃非锚点缓存。 机制变化:共享段 KV 被拆成两部分——少数"关口"(锚点)随请求同步更新,保证上下文一致性;其余 ~80% 保持共享,继续为生成提供背景信息。这同时利用了两个经验事实:注意力质量集中(少数 token 承载大部分信息流)且锚点位置跨解码步稳定(一次选定全程有效)。指标提升:精度上 20% 锚点率恢复大部分损失、2-shot 几乎追平全量重算;速度上重算量降为 O(K),延迟最高降 55.7%;显存上共享段只存一份,峰值 KV 降 43.3%。
方法差异三:把缓存复用从"请求内"提升到"跨请求"这一系统层设计。 机制变化:Fast-dLLM 等框架的重算是每请求独立的全量计算,ACache 则把共享文本段变成跨请求的缓存对象,用读槽映射避免为每个请求物化共享前缀副本。指标提升:batch 越大摊薄越好,吞吐最高 1.68×;且探针是一次性预处理成本,batch≥4 时收益完全覆盖。
反过来看边界也更清楚:batch=1 时探针开销摊不掉会变慢;锚点位置稳定性依赖 few-shot 这类强结构化共享段;原型仅支持前缀。这些边界恰好界定了因果链成立的前提条件。
七、必要知识反推
要真正读懂这篇论文并复现其工作,需要掌握以下知识栈:
- 自回归 KV 缓存与因果注意力:为什么 AR 模型的缓存是 append-only 的——因果掩码保证历史 token 的 K/V 不受未来影响。这是理解 DLLM 缓存为何过期的参照系。
- 离散扩散语言模型的解码循环:从全 [MASK] 序列出发,每步并行预测所有遮盖位、按置信度提交子集的"预测-提交"循环;LLaDA 的置信度调度、Fast-dLLM 的块式调度是典型实现。
- DLLM 缓存的过期机理:双向注意力中每个位置的表示依赖全序列,遮盖位每步都在变,所以提示词 token 的 KV 也会变——这是"stale cache"的根源。
- 注意力重要性分析:如何从注意力矩阵聚合 token 重要性分数(论文对层、头、遮盖位求和),以及注意力热图的解读方法。
- 推理系统工程:vLLM 的 PagedAttention 分页 KV 管理、连续批处理、ORCA 的迭代级调度——这些是理解 Nano-vLLM 原型与读槽映射设计的前提。
- Triton 内核定制:论文为间接寻址(逻辑位置→共享/私有物理槽)定制了注意力核,需要基本的 Triton 编程能力。
- Top-K 选择的复杂度分析:论文给出探针成本 O(NHPL)、聚合 O(NHmL)、top-K 提取 O(L log K) 的分析,用于判断一次性开销能否被摊薄。
八、通用性灵感
超出 DLLM 推理这个具体场景,这篇论文有几个可迁移的思想:
- 架构变革应触发系统假设重审。前缀缓存隐含一个"历史不受未来影响"的因果假设,双向注意力一打破它,整套优化便失效。任何新架构(线性注意力、状态空间模型、扩散模型)出现时,都值得问一句:它默认依赖的哪些系统假设变了?
- “过期"与"保鲜"可以是部分的。面对耦合系统,不必在"全部重算"与"全部复用"之间二选一——找到少数耦合最强的接口点(锚点)保持同步,其余部分即可安全复用。这种"关键接口同步"思想适用于缓存失效、增量计算、分布式一致性等广泛问题。
- 先做实证观察再定机制。论文先发现"注意力集中且锚点跨步稳定”,才敢把锚点固定为一次性选择。机制设计紧贴经验事实,是低成本方案成立的根基。
- 消融要能区分相似假设。“保留非锚点缓存 vs 丢弃"的消融干净地区分了"重要 token 剪枝"与"上下文适配"两种解释,这是论文说服力的关键一环——做系统研究时设计能"证伪替代解释"的实验比堆指标更重要。
- 诚实的边界声明。原型只支持前缀、batch=1 会变慢、共享段需预先声明——论文对适用条件的坦白反而增强了可信度,也直接指出了后续研究空间(在线发现共享段的 DLLM 版"radix cache”、位置感知的中缀注册机制)。
对于关注 AI Infra 的读者,这篇论文值得放进书架的关键理由是:它不只是一个加速技巧,而是为"双向注意力模型如何组织共享上下文与计算"打开了一扇门——正如作者所言,双向建模也许会带来比 AR 前缀缓存更灵活的推理抽象。