过去我一直以为,大模型想支持更长的上下文,只有一条路:
把更多历史 Token 留下来。
上下文从 8K 增长到 128K,再增长到百万 Token,无非就是继续优化 Attention Kernel、压缩 KV Cache、使用 GQA、MLA、量化缓存,或者干脆堆更多显存。
这套思路当然没有错。
但真正看懂 Kimi Delta Attention,也就是 KDA 之后,我才意识到:长上下文还有另一条完全不同的路线。
它不再执着于保存每一段历史。
它更关心的是:
读完这些历史之后,模型当前应该形成怎样的理解。
传统 Attention 像一间不断扩建的档案室。
KDA 更像一块不断擦除、修正和重写的工作白板。
这两个画面一旦建立起来,后面的 Delta Rule、细粒度门控、循环状态、Chunkwise 和 WY 表示法,就不再是一堆难以理解的数学名词了。
KDA的数学公式可以参考我的上一篇
这一篇主要是以具体的例子讲解KDA
KDA 最反直觉的一点:它不是保存更多历史,而是边读边重写记忆-CSDN博客
一、先别看公式,想象一个项目群聊
假设你让一名助理持续阅读一个项目群。
群里陆续出现四条消息:
09:00 项目正在开发 10:00 项目延期了 11:00 项目已经审批通过 12:00 项目最终完成现在你问助理:
项目目前是什么状态?助理至少可以使用两种记忆方式。
第一种方式,是把四条消息全部保存下来。
当你提问时,他重新翻阅聊天记录,判断哪条消息更新、哪些状态已经被覆盖,最后得出“项目已经完成”。
第二种方式,是维护一张项目状态表。
读到第一条消息时:
项目状态:开发中读到第二条消息后,直接改成:
项目状态:已延期继续阅读,状态依次变成:
项目状态:审批通过最终变成:
项目状态:已完成这时候再问项目状态,他不需要重新检查全部聊天记录,直接读取当前值就行。
这就是理解传统 Attention 与 KDA 最简单的入口。
二、传统 Attention 保存的是“历史现场”
传统 Attention 的核心优势,是它尽可能保留历史 Token 对应的信息。
模型生成一个新 Token 时,会使用当前 Query 去匹配历史 Key,再从相应的 Value 中提取信息。
翻译成人话,就是:
过去发生过什么,我先尽量保存下来。 等真正需要时,再重新查询。这套机制非常强。
因为历史信息还在,所以模型不仅可以回答:
项目现在是什么状态?它还有机会回答:
项目最初是什么状态? 项目几点发生延期? 审批之前经历了什么? 延期通知的原话是什么?只要相关 Token 仍然保留,模型就可以重新定位细节。
这也是传统 Attention 难以替代的能力:精确回查历史。
但代价同样明显。
在标准自注意力中,序列变长后,训练阶段的注意力计算通常会呈平方级增长。
自回归推理阶段虽然不必每次重算全部历史,但历史 Token 的 Key 和 Value 仍然需要保存在 KV Cache 中。
上下文只有几千 Token 时,问题还不明显。
当上下文增长到几十万甚至上百万 Token,事情就变成了:
档案越来越多。 仓库必须越来越大。 每次检索都要访问更多历史数据。所以,传统长上下文技术的大量优化,本质上都在解决同一个问题:
怎样以更低的成本,保存和查询更多历史?
三、KDA 保存的不是完整历史,而是“当前理解”
KDA 选择了另一条路。
它不会主要依赖一个随序列长度不断增长的 KV Cache,而是把读到的信息持续写入一个大小相对固定的循环状态。
为了方便理解,可以暂时把这个循环状态想象成一块白板。
新信息到来后,模型不只是往白板上继续增加文字。
它还会:
- 检查白板上原来写了什么;
- 判断旧内容是否已经过期;
- 擦掉一部分不再重要的信息;
- 使用新信息修正当前状态。
于是,传统 Attention 更像在问:
过去具体发生过哪些事情?KDA 更像在问:
读完这些事情之后,我现在应该形成什么状态?这是两种完全不同的记忆观。
传统 Attention 强调保留历史现场。
KDA 强调维护最新理解。
所以,KDA 最反直觉的地方并不是“压缩率很高”,而是:
它保存的重点不再是历史本身,而是模型对历史形成的当前状态。
四、别把“白板”理解成一张真正的业务表
这里必须踩一下刹车。
KDA 内部并没有真的维护这样一份 JSON:
{ "project_status": "completed", "owner": "Zhang San", "risk": "low" }“白板”只是为了帮助我们理解状态可以被覆盖和修改。
真实模型维护的是一个数值矩阵。
这个矩阵可以被理解成一种关联记忆:
某种 Key → 某种 ValueKey 可以粗略理解为:
这条信息属于什么问题?Value 可以粗略理解为:
这个问题对应什么内容?例如:
Key:项目当前状态 Value:已完成当然,真实模型中的 Key 和 Value 都是高维向量,不是人类可以直接阅读的文字。
更准确地说:
KDA 维护的是一套能够被 Key 查询、被新信息修改的连续数值状态。
这和数据库表格不是一回事。
但“可查询、可覆盖、可修正”这几个特征,确实与状态表很相似。
五、为什么最简单的线性记忆会越写越乱
在理解 Delta Rule 之前,需要先看一个最朴素的记忆方案:直接累加。
假设每来一组 Key 和 Value,模型就把它写进记忆矩阵:
Memory = Memory + Key × Value不必纠结矩阵方向,先理解它表达的意思:
每来一条信息,就往记忆里增加一笔关联。模型先读到:
项目状态:开发中于是它写入:
项目状态 → 开发中后来又读到:
项目状态:已延期如果仍然只是累加,记忆中就会同时存在:
项目状态 → 开发中 项目状态 → 已延期再继续阅读,还会出现:
项目状态 → 审批通过 项目状态 → 已完成问题来了。
同一个 Key 对应了多个互相冲突的 Value。
下一次查询“项目状态”时,模型读出来的可能不是干净的“已完成”,而是多个历史状态混合后的结果。
这就是单纯累加的根本缺陷:
它擅长增加信息,却不擅长修改过期信息。
而现实世界中,大量信息都存在覆盖关系:
变量的新值覆盖旧值 项目的新状态覆盖旧状态 用户的新要求覆盖旧要求 工具的新结果覆盖旧结果 文档后文修正前文结论如果记忆只能不断 append,却不能 update,那么上下文越长,冲突只会越多。
六、Delta Rule:不要盲目写入,先看看自己记错了什么
Delta Rule 最关键的动作,其实不是“写”。
而是“先读”。
一条新信息到来时,模型先使用当前 Key 查询旧记忆:
按照我现在的记忆,这个 Key 对应的 Value 是什么?假设新信息是:
项目状态:已延期但旧记忆读出来的是:
项目状态:开发中模型就可以计算两者之间的差异:
修正量 = 新答案 - 旧答案随后,它不再盲目追加一份完整的新答案,而是只把差异写回记忆。
用极度简化的伪代码表示:
old_value = read(memory, key) error = new_value - old_value memory = memory + learning_rate * write(key, error)这并不是 KDA 的完整实现,但已经抓住了 Delta Rule 的灵魂:
先读取旧答案 再计算旧答案错了多少 最后只修正错误的部分如果旧记忆已经比较准确:
error ≈ 0那么几乎不需要修改。
如果旧记忆已经严重过期,误差很大,模型就会进行更明显的更新。
所以,Delta Rule 不是简单的“记住新内容”。
它做的是:
根据新答案与旧答案之间的误差,编辑原有记忆。
这也是 Delta 这个名字的来源。
Delta 表示的正是变化量、差值或者修正量。
七、KDA 为什么看起来像在推理过程中学习
看到这里,很多人会有一个疑问:
模型不是已经训练完成了吗?
为什么在阅读上下文时,还会不断“学习”?
关键在于,需要区分两种东西:
模型参数 当前序列的循环状态模型参数可以理解成一个人的长期能力:
- 是否理解语言;
- 是否会编程;
- 是否掌握推理方法;
- 是否知道如何使用工具;
- 是否具备某个领域的知识。
这些能力主要来自预训练、监督微调和强化学习。
而 KDA 的循环状态,更像这个人处理当前任务时使用的草稿纸:
- 当前目标是什么;
- 任务进行到哪一步;
- 哪些信息刚刚更新;
- 哪些结论已经失效;
- 当前应该采取什么行动。
执行任务时,人的长期能力并没有被重新训练。
但草稿纸上的内容一直在变化。
因此,所谓“推理阶段在线学习”,不是说模型每读一个 Token,就重新训练一遍全部参数。
而是:
模型在当前序列内部,快速更新一组临时状态。
这类状态也可以从 fast weights,也就是“快速权重”的角度理解。
长期参数决定模型应该怎样读写记忆。
循环状态则负责适应当前任务。
任务结束后,这些临时状态通常不会自动变成模型的永久知识。
所以,KDA 更接近工作记忆更新,而不是偷偷微调模型。
八、会修改还不够,模型还必须学会遗忘
假设一块白板已经写满了内容。
即使模型会使用 Delta Rule 进行修正,如果所有旧信息都永久保留,白板仍然会越来越拥挤。
因此,在写入新信息之前,KDA 还需要对旧状态进行衰减。
整个过程可以简化为:
旧状态 ↓ 根据门控衰减旧信息 ↓ 使用当前 Key 读取旧答案 ↓ 计算新答案与旧答案的误差 ↓ 写入修正量 ↓ 得到新状态这里的门控决定了旧信息应该保留多少。
门控值较大,意味着保留得更多。
门控值较小,意味着衰减得更快。
可以把它想象成在白板上使用不同的笔:
- 有些信息用永久记号笔;
- 有些信息用普通白板笔;
- 有些信息很快就会自动消失。
真正困难的地方在于:不同信息的有效期并不相同。
九、细粒度门控解决的,不是“忘不忘”,而是“忘哪一部分”
假设 Agent 当前状态中包含这些信息:
用户姓名:张三 当前目标:生成月度销售报告 当前步骤:读取 Excel 当前代码位置:第 328 行 上一次工具返回:文件读取成功它们的生命周期完全不同。
“用户姓名”可能整场会话都有效。
“当前目标”可能持续几十分钟。
“当前步骤”可能几十秒后就会变化。
“第 328 行”可能在下一次修改代码后立刻失效。
“上一次工具返回”甚至可能只对当前一次推理有效。
如果所有记忆共用同一个遗忘速度,就会出现两个极端。
遗忘太快:
任务目标、用户约束和关键结论一起被丢掉。遗忘太慢:
临时变量、旧工具结果和过期步骤长期残留。早期一些门控线性注意力机制,遗忘控制相对粗粒度。
可以把它理解成:
整个 Attention Head 的状态统一保留 90%。但 KDA 进一步细化了这件事。
它不再只是决定:
这一整块状态应该保留多少?而是可以更细致地控制:
状态中的不同通道,分别应该保留多少?这就是细粒度门控的重要价值。
它让不同类型的信息拥有不同的衰减速度,从而更充分地利用容量有限的循环状态。
十、为什么 KDA 天然更偏向近期信息
假设某条信息很早就被写入状态。
在后续处理过程中,它会经历很多轮:
- 门控衰减;
- 新信息写入;
- 相似 Key 的修正;
- 状态重新组合;
- 其他信息的干扰。
因此,它对当前状态的影响往往会逐渐减弱。
最近的信息刚刚进入状态,经历的衰减次数更少,通常保留得更明显。
于是系统会自然形成一种时间倾向:
较近的信息通常影响更大 较远的信息通常影响更弱这种近期偏好不完全等于模型显式读取 Token 的位置编号。
它更像是信息在循环状态中传播时,真实经历了多轮衰减和修改。
一句话刚刚说完,细节还很清晰。
经过许多轮转述和新信息干扰后,留下来的往往只剩下大意。
十一、固定状态真正难的,是给信息分配“地址”
KDA 的循环状态大小相对固定。
这意味着它不可能无限增加新的独立存储位置。
模型必须学会判断:
哪些信息属于同一个问题? 哪些信息应该分开保存?假设模型先读到:
项目 A 的负责人是张三。随后又读到:
项目 B 的负责人是李四。理想情况下,模型生成的 Key 应该足够不同:
项目 A 负责人 → 张三 项目 B 负责人 → 李四但如果两个 Key 太相似,模型可能把它们都映射成:
项目负责人于是第一次写入:
项目负责人 → 张三第二次更新后变成:
项目负责人 → 李四项目 A 的信息就可能被项目 B 覆盖。
这并不代表模型完全不会记忆。
而是模型没有为两条信息找到足够独立的地址。
在线性关联记忆中,Key 的可分性非常重要。
不同信息生成的 Key 越容易区分,它们越有机会占据相对独立的状态方向。
Key 越相似,越容易发生:
- 覆盖;
- 串扰;
- 混合;
- 错误联想;
- 不相关信息相互破坏。
所以,KDA 并没有消灭记忆容量问题。
它只是把问题从:
怎样保存无限增长的历史 Token?转变成了:
怎样在有限状态中分配、修改和保护信息?十二、百万 Token 不等于百万 Token 无损背诵
这是理解 KDA 和其他线性注意力架构时最容易踩的坑。
假设模型读完一百万 Token,最终形成了这些状态:
项目已经完成 主要风险已经解除 负责人是张三 最终方案采用 B这并不代表它还完整保存着:
第 18372 个 Token 的原话 第一次提出方案 A 时的具体措辞 某次会议的完整争论过程 审批人当时使用了什么标点符号固定大小的循环状态,本质上是一种有损压缩。
它更擅长保留:
- 当前状态;
- 核心关系;
- 重要结论;
- 持续有效的任务信息;
- 对后续预测有价值的模式。
它不一定擅长保留:
- 任意遥远位置的逐字原文;
- 大量互相独立的随机事实;
- 所有历史状态的完整时间线;
- 模型认为不重要的细节。
因此:
能够处理百万 Token,不等于能够逐字恢复百万 Token。
更准确的说法是:
模型可以在处理超长序列时,持续维护和更新一个大小相对固定的内部状态。
这和人类读一本书很像。
真正看懂一本书,不代表能够背出每一页的每一句话。
十三、传统 Attention 与 KDA,不是谁淘汰谁
把两种机制放在一起看,会发现它们擅长解决的是不同问题。
| 能力 | 传统 Attention | KDA 式循环记忆 |
|---|---|---|
| 保存历史细节 | 较强 | 容易被压缩 |
| 精确回查原文 | 较强 | 相对困难 |
| 状态空间 | KV Cache 随历史增长 | 循环状态大小相对固定 |
| 处理过期信息 | 查询时重新判断 | 可以直接修改状态 |
| 长序列成本 | 历史越长成本越高 | 对序列长度更友好 |
| 记忆容量 | 可随缓存扩张 | 受固定状态限制 |
| 信息干扰 | 可重新访问原始 Token | Key 相似时可能串扰 |
传统 Attention 像完整档案室。
里面保存着:
- 完整邮件;
- 原始合同;
- 历史日志;
- 所有会议记录;
- 每一次状态变更。
KDA 更像管理驾驶舱。
它重点展示:
- 当前状态;
- 当前风险;
- 当前负责人;
- 当前结论;
- 下一步行动。
日常决策时,驾驶舱效率更高。
需要审计、追责和恢复原话时,档案室更可靠。
这两种能力并不冲突。
相反,一个成熟系统往往同时需要两者。
十四、为什么 Kimi Linear 仍然保留全局 Attention
既然 KDA 能显著降低长上下文成本,为什么不让所有层都使用 KDA?
因为固定状态记忆存在明确边界。
KDA 擅长:
- 持续更新当前理解;
- 处理流式输入;
- 使用固定状态承载长历史;
- 降低长上下文推理中的缓存压力。
传统全局 Attention 擅长:
- 精确访问历史 Token;
- 在大量位置之间重新建立联系;
- 找回压缩状态遗漏的细节;
- 处理需要精确匹配的远距离依赖。
因此,Kimi Linear 采用的是混合架构,而不是纯 KDA 架构。
公开架构按照大约 3:1 的比例交替使用 KDA 与全局 MLA。
可以粗略理解为:
大部分层负责高效维护压缩状态。 少部分层保留精确访问完整历史的能力。官方报告显示,在其特定模型、硬件和测试设置中,这种设计最多可以减少约 75% 的 KV Cache,并在百万 Token 上下文测试中取得最高约 6 倍的解码吞吐提升。
需要强调的是,这些数字来自特定测试条件,不应该理解成所有模型、所有 GPU 和所有部署环境都固定提升 6 倍。
但这套混合设计背后的工程判断非常成熟:
不要强迫一种机制解决所有问题,而是让不同机制承担各自擅长的工作。
十五、理论复杂度更低,为什么 GPU 上未必更快
从算法复杂度看,循环状态非常诱人。
生成下一个 Token 时,模型不需要访问全部历史 KV,只需要:
读取当前状态 计算当前输出 更新当前状态问题在于,状态更新存在前后依赖。
必须先计算:
State₁ = Update(State₀, Token₁)才能继续计算:
State₂ = Update(State₁, Token₂)然后才是:
State₃ = Update(State₂, Token₃)后一个状态依赖前一个状态。
这是一种串行递归。
而 GPU 最擅长的并不是一环扣一环的小任务,而是同时执行大量结构相同的矩阵运算。
可以把 GPU 想象成一座拥有几千名工人的工厂。
它最喜欢的是:
让几千名工人同时加工一大批相似零件。它最不喜欢的是:
一个人加工完第一件, 第二个人才能开始, 其他人全部等待。因此:
理论运算量更少,不代表硬件实际运行一定更快。
算法复杂度只是第一关。
能不能把算法改造成 GPU 喜欢的大矩阵计算,才决定真实吞吐。
十六、Chunkwise:块间递归,块内并行
解决办法之一,是把 Token 分块处理。
假设序列中有 1024 个 Token。
原始方式可能是逐个更新:
Token 1 → 更新状态 Token 2 → 更新状态 Token 3 → 更新状态Chunkwise 会把序列切成多个块:
Chunk 1:Token 1~64 Chunk 2:Token 65~128 Chunk 3:Token 129~192Chunk 与 Chunk 之间仍然需要按照顺序传递状态。
因为第二块的初始状态,依赖第一块结束时的状态。
但在每一个 Chunk 内部,可以通过数学变换,并行计算多个 Token 对状态的影响。
核心思路可以浓缩成八个字:
块间递归,块内并行。它没有彻底消除状态依赖。
但它把大量细碎的逐 Token 更新,组织成了更大规模的计算任务,减少了小 Kernel 的频繁启动,让 GPU 更容易发挥吞吐能力。
十七、WY 与 DPLR:把几十次小修改整理成一次批量计算
Delta Rule 中,每个 Token 都可能对状态进行一次低秩修改。
最直接的执行方式类似:
修改一次状态 再修改一次状态 继续修改一次状态WY 一类紧凑表示法所做的事情,可以理解为:
先把一个 Chunk 内的多次状态修改进行代数整理,再转换成更适合矩阵乘法的形式。
这像一家工厂收到了几十张小订单。
低效方式是:
来一张订单,启动一次机器。 再来一张订单,再启动一次机器。更高效的方式是:
先把几十张订单汇总成一张批量生产单, 再一次性交给机器处理。KDA 的 Chunkwise 算法进一步利用了特殊的“对角加低秩”状态转移结构,也就是 DPLR 结构,将递归更新整理成硬件效率更高的分块矩阵运算。
所以,这几个概念实际上分别解决了不同问题:
Delta Rule 解决记忆怎样纠错和更新 细粒度门控 解决不同记忆应该保留多久 Chunkwise 解决怎样减少逐 Token 串行执行 WY / DPLR 解决怎样把块内更新变成高效矩阵运算它们不是四套彼此竞争的技术。
而是同一条技术链上的四个环节。
十八、FlashKDA 说明了一个残酷事实:好公式不等于好性能
即使理论推导已经完成,如果底层 Kernel 没有针对 GPU 进行优化,算法优势依然可能无法转化成真实速度。
Moonshot AI 后续开源的 FlashKDA,使用 CUTLASS 构建高性能 KDA Kernel,并接入 Flash Linear Attention 的chunk_kda后端。
这说明 KDA 的高性能并不只来自公式。
它还依赖:
- 数据怎样排列;
- Tensor Core 能否被充分利用;
- 中间结果是否频繁读写显存;
- 多个算子能否融合;
- Chunk 大小是否适合目标 GPU;
- 训练和解码是否使用不同执行路径;
- Kernel 是否针对具体架构优化。
所以,判断一个线性注意力架构是否真的更快,不能只看:
复杂度是不是 O(N)还要看:
它最终能不能变成 GPU 喜欢的计算。论文中的 FLOPs 不是服务器上的最终速度。
算子能不能喂饱 GPU,才决定真实表现。
十九、KDA 对 Agent 工程最有价值的启发
理解 KDA 后,我发现它对 Agent 工程的启发,甚至比对模型结构本身更直接。
现在很多 Agent 系统的记忆方式,本质上仍然是不断追加 Prompt。
例如:
任务状态:未开始 任务状态:处理中 任务状态:等待审批 任务状态:审批通过 任务状态:已完成每次状态变化,都往上下文里再添加一条消息。
然后要求大模型自己判断,究竟哪一个状态才有效。
工具调用一多,Prompt 很快就会变成一条混乱的事件流水账:
第一次查询失败 第二次查询超时 第三次查询成功 用户后来修改了目标 模型仍然保留旧目标 工具返回了旧缓存 新工具又返回了更新后的数据这相当于一家公司没有业务数据库。
每个员工每天都要重新阅读完整聊天记录,推断订单现在处于什么状态。
系统当然容易不稳定。
KDA 给出的工程启发非常清晰:
会变化的信息,应该被更新;需要审计的信息,才应该被追加保存。
二十、Agent 记忆应该分成四层
一个更加可靠的 Agent 记忆系统,可以分成四层。
1. 当前状态白板
只保存当前仍然有效的信息:
{ "task_id": "TASK-2026-0731", "goal": "生成月度销售分析报告", "status": "completed", "current_step": null, "approved": true, "latest_file": "sales_report_v3.xlsx" }状态变化后直接更新:
state["status"] = "completed"而不是继续追加:
messages.append("任务状态:已完成")2. 事件历史
完整保存每一次变化:
10:00 创建任务 10:08 开始读取数据 10:12 文件读取失败 10:14 第二次读取成功 10:35 报告生成完成 10:50 审批通过事件历史主要用于:
- 审计;
- 故障排查;
- 责任追溯;
- 过程复盘;
- 任务重放。
3. 原始档案
保存真正需要精确回查的内容:
- 原始文件;
- 完整邮件;
- 合同;
- 会议纪要;
- 工具返回原文;
- 代码和运行日志。
4. 检索索引
通过 RAG、全文搜索或者结构化查询,在必要时恢复历史细节。
最终形成这样的调用逻辑:
平时做决策 → 读取当前状态 需要理解背景 → 检索相关历史 需要审计原话 → 打开原始档案这与 KDA 和全局 Attention 的混合思路非常相似:
大部分时间使用压缩状态。 关键时候访问完整历史。二十一、Agent 的状态更新,本质上是一个 Reducer
在工程实现中,可以使用一个确定性的 Reducer 管理当前状态。
def reduce_state(state: dict, event: dict) -> dict: event_type = event["type"] if event_type == "TASK_STARTED": state["status"] = "running" elif event_type == "WAITING_APPROVAL": state["status"] = "waiting_approval" elif event_type == "APPROVED": state["approved"] = True state["status"] = "approved" elif event_type == "TASK_COMPLETED": state["status"] = "completed" state["current_step"] = None return state历史事件继续保留:
event_log.append(event)但 Agent 平时读取的,不是完整事件日志,而是归约后的当前状态:
current_state = reduce_all(event_log)这种设计有几个明显优势:
- 当前状态不存在多个冲突版本;
- 每个字段都有明确的更新规则;
- Prompt 更短;
- 模型决策更加稳定;
- 历史过程仍然可以审计;
- 业务规则可以由代码验证;
- 状态错误更容易定位和修复。
从这个角度看,KDA 最值得 Agent 工程借鉴的一句话是:
记忆不能只有 append,还必须具备 update、replace、decay 和 retrieve。
二十二、不同记忆还应该拥有不同的保质期
细粒度门控对 Agent 的第二层启发是:
不同信息不应该拥有相同的保留周期。
可以按照生命周期划分状态。
长期有效
用户所属公司 用户习惯的语言 项目固定目标 业务规则 权限范围当前任务有效
当前输入文件 本次任务约束 当前审批人 本次执行计划当前步骤有效
当前循环索引 临时文件地址 工具调用参数 重试次数单次调用有效
某次 API 返回 某段中间计算结果 临时解析文本工程上可以通过这些机制控制生命周期:
- TTL;
- 状态作用域;
- 命名空间;
- 版本号;
- 事件类型;
- 显式失效条件。
例如:
{ "value": "第328行", "scope": "current_debug_step", "expires_when": "code_updated" }代码一旦更新,这条信息立即失效。
这比把所有信息永久塞进对话历史可靠得多。
二十三、KDA 真正的限制不是速度,而是容量
固定状态带来了效率,也带来了不可避免的容量约束。
当需要同时保存的信息超过状态能够稳定表达的范围时,模型必须进行取舍:
- 哪些信息继续保留;
- 哪些信息应该衰减;
- 哪些信息可以覆盖;
- 哪些信息可能被混合;
- 哪些关系值得占据独立状态方向。
因此,线性注意力中的“无限上下文”,不能理解成无限记忆。
它通常表示:
模型可以持续处理更长的输入, 而不需要让 KV Cache 按照 Token 数量无限增长。但固定状态本身并不会因此拥有无限的信息容量。
一个人可以持续参加一整年的会议。
这不代表他能逐字背诵每一场会议。
他真正留下来的,往往是:
- 当前决策;
- 关键人物;
- 核心关系;
- 未完成事项;
- 对未来有用的结论。
大量低价值、互相相似或者已经过期的细节,会逐渐模糊。
这就是固定状态必须付出的代价。
二十四、真正看懂 KDA 后,应该建立四个判断
判断一:长上下文不只有扩大 KV Cache 一条路
传统路线研究的是:
怎样保存和查询更多历史?KDA 路线研究的是:
怎样把历史持续压缩成可修改的状态?两条路线解决的是不同问题。
判断二:记忆更新比记忆增加更难
增加一条信息非常容易。
真正困难的是:
- 判断新信息是否与旧信息冲突;
- 判断应该覆盖旧记忆的哪一部分;
- 判断哪些内容仍然有效;
- 避免破坏其他相关记忆。
Delta Rule 的价值,就在于把记忆从“不断增加”推进到了“根据误差进行编辑”。
判断三:线性复杂度不等于天然高性能
递归状态可以减少理论计算量,却也会引入串行依赖。
没有 Chunkwise、矩阵变换和高性能 Kernel,GPU 未必能够充分发挥性能。
判断四:压缩记忆与精确记忆必须分工
压缩状态适合:
维护当前理解。完整 Attention 或外部检索适合:
恢复历史细节。真正优秀的系统,往往不会只选择其中一个。
结语:模型到底应该保存过去,还是保存对过去的理解
理解 KDA,不需要一开始就钻进复杂公式。
先记住两个画面就够了。
传统 Attention 像一间完整档案室。
它尽量保存过去具体发生过什么,等需要时再重新查阅。
KDA 像一块工作白板。
它一边阅读,一边擦除过期内容,并根据新信息修正当前状态。
在这块“白板”背后,真正发生的是:
- 使用 Key 查询数值状态;
- 使用 Delta Rule 修正旧记忆;
- 使用细粒度门控控制遗忘;
- 使用 Chunkwise 扩大块内并行;
- 使用 WY、DPLR 和高性能 Kernel 提高 GPU 执行效率。
所以,KDA 最终回答的是一个非常现实的问题:
当历史长到无法全部摆在桌面上时, 模型应该保存过去本身, 还是保存自己对过去形成的最新理解?KDA 选择了后者。
但未来成熟的长上下文系统,大概率不会彻底放弃任何一边。
它们更可能同时拥有:
一块能够快速决策的工作白板 加上 一间能够精确追溯的完整档案室或许,这才是机器记忆真正成熟的形态。
参考资料
- Kimi Team:《Kimi Linear: An Expressive, Efficient Attention Architecture》
- Moonshot AI:Kimi Linear 官方开源仓库
- Moonshot AI:Kimi Linear 模型卡及架构说明
- Moonshot AI:FlashKDA 高性能 Kernel 实现
文章标签
Kimi KDA Kimi Delta Attention 线性注意力 Transformer 长上下文 KV Cache 大模型原理 Agent 人工智能