Titans - Learning to Memorize at Test Time · essay
15. Titans:测试时学习,模型在推理过程中学会记什么
论文:Titans: Learning to Memorize at Test Time
本地原文:
![[papers/15-Titans-2501.00663.pdf]]
论文定位与阅读路径
核心定位
Titans 研究的是 test-time memory:模型不是只在训练阶段学,推理时也能把历史上下文写入一个神经长期记忆模块,并用“惊讶度”之类信号决定什么值得记。
概念解释:
模型一边读长文本,一边把意外、有信息量的内容写进记忆,以后再用。
原文结构导读
| 章节 | 内容 | 重点 |
|---|---|---|
| Abstract | 注意力能看当前窗口,但长上下文成本高 | neural long-term memory module |
| 1 Introduction | RNN 压缩太狠,Attention 太贵 | 为什么需要新记忆模块 |
| 2 Preliminaries | 注意力、线性 RNN、记忆背景 | 概念铺垫,先粗读 |
| 3 Learning to Memorize at Test Time | 核心方法 | surprise、write、forget、retrieve |
| 4 How to Incorporate Memory | 记忆和模型主干怎么结合 | 三种结构组合方式 |
| 5 Experiments | 语言、常识、基因、时间序列 | 看长上下文能力 |
| 6 Conclusion | 总结 | 测试时记忆是长上下文路线 |
证据链阅读
| 证据点 | 读什么 | 工程判断 |
|---|---|---|
| Surprise / write 机制 | 什么信号触发写入 | 记忆系统不能无差别写入所有 token |
| Memory 组合方式 | 记忆模块和 attention/RNN 如何接 | 不同接法对应不同延迟和表达能力 |
| 长上下文实验 | 在语言、时间序列等任务是否稳 | 证明 test-time memory 是否泛化 |
| 消融与成本 | 去掉记忆或改写入策略后变化 | 判断提升来自记忆机制还是模型规模 |
研究背景与问题定义
先理解:为什么 Attention 不够
标准 Transformer 的 self-attention 会让每个 token 看前面很多 token。
问题是:
代码块收起展开
上下文越长,attention 成本越高。
KV cache 也越大。如果无限扩大上下文窗口,成本会爆炸。
Titans 的思路是:
代码块收起展开
近期信息:用 attention 精确看。
遥远历史:压缩进神经记忆模块。
需要时:从记忆模块读回来。方法框架与核心机制
核心结构
关键概念:surprise
surprise 可以理解为“模型没想到这件事”。
如果当前输入和模型已有知识很一致,没必要强记。
如果当前输入让模型预测误差大,说明它包含新信息,值得写入记忆。
工程类比:
代码块收起展开
老师讲你已经会的内容,你不会记很多笔记。
老师突然讲一个你完全不知道但考试会考的点,你会立刻记下来。Titans 把这种“该不该记”的判断做成可学习机制。
三种记忆需求
| 需求 | 含义 | 例子 |
|---|---|---|
| 存储 | 哪些信息写入长期记忆 | 新事实、罕见模式 |
| 遗忘 | 哪些旧信息应降低影响 | 过时、重复、噪声 |
| 检索 | 当前需要哪些旧信息 | 长文前面的人名关系 |
这三件事是 Agent Memory 的通用三件套。
Method 逐层拆解
1. 神经长期记忆模块
Titans 的 memory 不是文本库,也不是普通向量数据库,而是一个神经网络模块。它可以被更新,用来压缩历史信息。
对比:
| 记忆类型 | 写入方式 | 可解释性 | 与模型耦合 |
|---|---|---|---|
| 文本记忆 | 保存文本 | 高 | 低 |
| 向量库 | 保存 embedding | 中 | 低 |
| Titans memory | 更新神经模块 | 低 | 高 |
2. 测试时学习
传统训练/推理分得很清楚:
代码块收起展开
训练阶段:更新参数。
推理阶段:参数冻结。Titans 模糊了这条线:
代码块收起展开
推理阶段:主模型可以稳定,但记忆模块能继续更新。这就是 test-time learning。
3. 怎么接入主模型
论文讨论了记忆和注意力的不同组合方式。你不用死背结构名,先理解三种位置:
| 接入方式 | 直觉 |
|---|---|
| 记忆在 attention 前 | 先从历史提炼,再参与当前注意力 |
| 记忆和 attention 并行 | 一边看当前窗口,一边读长期记忆 |
| 记忆在 attention 后 | 当前理解完,再用长期记忆补充 |
工程上类似:检索可以发生在 prompt 构造前、中间工具调用时、或回答后反思阶段。
相关工作与方法对比
和长上下文模型的关系
| 路线 | 思路 | 问题 |
|---|---|---|
| 直接扩窗口 | 把上下文做很长 | 成本高 |
| 稀疏注意力 | 只看部分 token | 可能漏信息 |
| RAG | 外部检索文本 | 依赖检索质量 |
| Titans | 学一个长期记忆模块 | 复杂、可解释性低 |
Titans 的价值是提出:
长上下文不一定等于把所有 token 都留在窗口里,模型可以学习如何压缩和回忆。
实验论证与评价方式
实验阅读方法
论文在多类任务上评估,包括语言建模、常识推理、基因组、时间序列等。你读实验时重点看:
- 长序列越长时,Titans 是否更稳定。
- 和 Transformer、线性 attention、RNN 类方法相比优势在哪。
- ablation 里去掉 memory 或 surprise 后效果是否下降。
- needle-in-haystack 类任务是否能找回远处信息。
不要只看“赢没赢”,要看它验证的机制:
代码块收起展开
记忆模块真的在保存长距离信息吗?
写入策略真的比盲目压缩好吗?概念校准
你复习一本 500 页教材,不会把每页逐字背下来。你会:
- 课堂上听到重要/意外内容就记笔记。
- 相似内容合并。
- 过时或不考的内容淡化。
- 做题时翻相关笔记。
Titans 就是把这套“会记笔记”的能力放进模型。
工程映射与实践启发
工程落地启发
你的 Agent 系统可以借鉴 surprise 写入策略:
| Titans 概念 | 工程实现 |
|---|---|
| surprise | 当前信息和已有记忆差异大 |
| write gate | 达到阈值才写记忆 |
| forget | 低价值记忆降权/过期 |
| retrieve | 按任务找相关记忆 |
示例规则:
代码块收起展开
如果新事实与旧事实相同:不写。
如果新事实补充旧事实:合并。
如果新事实冲突但来源更新:写新版本并失效旧版本。
如果用户明确纠正:提高权重。局限、对比与阅读检查
局限与边界
- 神经记忆难解释。
- 测试时更新可能带来安全和稳定性风险。
- 工程部署比普通 RAG 复杂得多。
- 记忆写错后不容易人工修复。
- 论文能力不等于现成产品能力。
阅读检查清单
- test-time learning 是什么。
- surprise 为什么能作为记忆写入信号。
- 长上下文不只有“扩大窗口”一条路。
- Titans 和 RAG、MemoryLLM、Memorizing Transformer 的区别。
- 如何把“惊讶驱动写入”迁移到应用层 Agent。
深度精读:Titans 的关键词是 surprise、test-time、neural memory
1. 它为什么不是普通长上下文
普通长上下文路线是:
代码块收起展开
把窗口做得更长,让模型能看到更多 token。Titans 的路线是:
代码块收起展开
窗口仍然有限;
模型额外维护一个长期神经记忆;
推理过程中把值得记的信息写入;
之后再读出来。这更像“边读边做笔记”,而不是“把整本书摊在桌上”。
2. surprise 为什么适合作为写入信号
如果一个信息模型已经很熟悉,强行写入会浪费容量。真正值得记的往往是:
- 新的。
- 罕见的。
- 和已有模式冲突的。
- 对后续预测有帮助的。
这些都可以用 surprise 直觉表示:
代码块收起展开
模型越没预料到,越可能值得记。在应用层,你可以把 surprise 换成:
代码块收起展开
新信息和旧记忆差异大;
用户明确纠正;
任务失败暴露新问题;
出现高价值实体或规则。3. test-time learning 的风险
推理时更新记忆很强,但也危险:
| 风险 | 解释 |
|---|---|
| 写入噪声 | 临时信息被当长期规律 |
| 被攻击 | 用户诱导写入恶意记忆 |
| 不可解释 | 神经记忆里到底存了什么难查看 |
| 回滚困难 | 写错后不如文本记忆好改 |
所以产品系统更常先做文本/结构化记忆,而不是直接神经记忆。
4. Titans 和 RNN/Attention 的折中
| 模型 | 怎么处理历史 |
|---|---|
| RNN | 压进固定 hidden state |
| Transformer | attention 看上下文窗口 |
| Titans | 当前窗口 + 可学习长期记忆 |
RNN 压缩太狠,Transformer 太贵,Titans 想要两者折中。
5. 三种记忆接入方式怎么理解
论文讨论记忆如何接入主模型。你不用背名字,理解位置即可:
- 记忆先处理历史,再给 attention 用。
- 记忆和 attention 并行提供信息。
- attention 处理当前窗口后,再用长期记忆补充。
这和工程系统类似:
代码块收起展开
前置检索、并行工具调用、后置反思/补证据6. 应用层 surprise 写入策略
代码块收起展开
boolean shouldWriteMemory(Event e, List<Memory> similar) {
if (e.userExplicitCorrection()) return true;
if (e.taskFailedWithNewCause()) return true;
if (similar.isEmpty() && e.importance() > 0.7) return true;
if (conflictsWithExisting(e, similar)) return true;
return false;
}这不是 Titans 原算法,但继承了它的思想:不要平均地记所有东西。
7. 消融实验要看什么
读 Titans 时重点看:
- 去掉 memory module 后下降多少。
- 去掉 surprise/写入机制后下降多少。
- 序列越长,优势是否越明显。
- 在不同任务上是否都有效,还是只对某类长序列有效。
如果只在某些任务有效,也不丢人,说明记忆机制有适用边界。
8. 对你当前阶段的结论
你不需要实现神经记忆,但要学会一个原则:
代码块收起展开
写记忆要有触发信号。触发信号可以是:
- 用户显式要求。
- 与旧事实冲突。
- 多次重复出现。
- 任务失败后总结出新教训。
- 对未来任务明显有用。
这比“每轮都写”成熟得多。
精读补强:Titans 的证据链与工程判断
Titans 的关键词是 test-time memory。读这篇时要判断:模型在推理时写入的记忆,是否真的比更长上下文或普通检索更有效。
| 判断点 | 原文证据 | 工程含义 |
|---|---|---|
| surprise 如何定义 | 新颖度/预测误差触发写入 | 记忆写入不能全量发生,必须有选择信号 |
| 长期记忆如何更新 | neural memory 在推理时调整 | 在线更新要有稳定性保护 |
| 和 attention 的关系 | 短期窗口 + 长期记忆协作 | 不同时间尺度的记忆要分层管理 |
| 实验比较对象 | 长上下文、RNN/Transformer 变体 | 看收益是否来自记忆机制,而非参数规模 |
工程启发是:写入记忆前要有“值得记吗”的门控。Personal Knowledge Agent 可以用 surprise 的工程近似:新事实、用户纠正、高失败代价、反复出现的任务,才进入长期记忆。
论文精读主线:问题-方法-验证-局限-启发
1. 核心结论
Titans 用 surprise 信号驱动测试时长期神经记忆更新,让模型在不无限扩大 attention 窗口的情况下选择性记住长序列历史。
本篇的阅读重心是:用 surprise 信号在测试时选择性写入神经长期记忆。读完后要能说清它改变的是 runtime、存储、检索、更新还是评测层;否则只是记住了论文名。
2. 问题背景
Transformer 长上下文成本高,RNN/线性模型压缩历史会丢细节,普通 RAG 又依赖外部文本检索。Titans 的矛盾是:模型能否在推理过程中自己判断什么信息值得写入长期记忆。
把问题具体化为失败样例:长序列中大部分 token 不值得记,但真正意外和关键的信息如果错过,后续推理无法恢复。用这个样例反推论文动机,比泛泛说“上下文不够”或“记忆不准”更有判断力。
3. 核心方法
模型保留短期 attention,同时引入 neural long-term memory。输入到来时计算 surprise,越出乎模型预期的信息越可能触发写入;后续推理再读取长期记忆与当前 attention 融合。
方法部分按数据流读:模型在推理时计算 surprise,决定是否写入 neural memory,后续通过 attention/检索重新利用。每一步都要能标出输入、输出、控制点和失败后该记录的日志。
4. 技术细节
surprise 可以理解为预测误差或新颖度信号。它不是说所有异常都值得记,而是提供一种写入门控。神经记忆难审计,所以论文适合研究模型能力,工程上要谨慎迁移。
代码块收起展开
final class SurpriseMemoryPolicy {
private final SurpriseScorer surpriseScorer; // 估计当前信息是否新颖、冲突或高价值
private final WriteGate writeGate; // 决定是否写入长期记忆,避免每轮都记
private final NeuralMemoryAdapter memoryAdapter; // 抽象神经记忆读写接口,便于替换成显式记忆
private final DriftMonitor driftMonitor; // 监控测试时更新是否导致行为漂移
MemoryResult handle(MemoryInput input) {
// 1. 估计当前信息是否新颖、冲突或高价值
// 2. 决定是否写入长期记忆,避免每轮都记
// 3. 抽象神经记忆读写接口,便于替换成显式记忆
// 4. 监控测试时更新是否导致行为漂移
// 输出中保留 traceId、sourceIds、decisionReason,方便复盘和回滚。
return MemoryResult.withTrace(input.traceId());
}
}字段检查重点是 surprise、writeStrength、neuralMemory、decay、retrievalState 是判断机制是否成立的字段。这些字段不是装饰,它们决定后续能否检索、审计、回滚、限权和做离线评测。
5. 实验验证
实验覆盖语言建模、长序列、needle 类任务等。要看序列变长后是否稳定,去掉 memory 或 surprise 后是否下降。还要注意跨领域实验不等于生产可控。
实验阅读重点:看长序列任务、写入门控消融、记忆容量和噪声写入;尤其关注 surprise 是否真能代表重要性。如果论文没有直接给出这层证据,复现时就要自己补机制级指标。
6. 局限与启发
闭源模型和普通应用层 Agent 很难直接复现神经测试时学习。启发是应用层也应有 surprise 写入策略:用户纠错、任务失败、新旧冲突、高价值实体出现时才写入。
迁移到你的项目时,结论是:工程上可借鉴“意外度触发写入”:用户纠正、测试失败、知识冲突比普通聊天更值得记。先把边界做对,再追求更复杂的模型或更大的记忆规模。
7. 关键术语表
| 术语 | 在论文里的意思 | 工程落地时要看什么 |
|---|---|---|
| Test-time learning | 推理时更新状态或模块 | 生产上要控制漂移和回滚 |
| Surprise | 意外程度/预测误差 | 写入门控信号 |
| Neural long-term memory | 模型内部长期记忆模块 | 难审计,适合研究 |
| Write gate | 写入门控 | 决定是否保存信息 |
8. 复现难点
高 surprise 不一定是好记忆,攻击输入、噪声和异常也会高。测试时更新如果没有回滚,会把模型带偏。评测必须覆盖安全、漂移和旧能力保持。
复现入口应从失败集开始:用长序列 toy task 比较全写、永不写、surprise 写入三种策略,看容量和噪声的权衡。只有先证明旧方案会坏,才知道新机制是否真的解决了问题。
9. 代码框架建议
应用层先实现 SurpriseMemoryPolicy.shouldWrite(event),规则包括 userCorrection、taskFailure、stablePreferenceChange、conflictWithOldMemory。输出必须带 reason 和 riskLevel。
代码验收门槛:写入触发器必须可解释;如果 surprise 只是一串内部数值,产品层仍要外加规则和审计。这条门槛应写进测试或 trace 字段里,避免实现只停留在 demo。
10. 相关论文对比
Titans 和 Memorizing Transformer 都是模型内部记忆方向;前者强调测试时学习,后者强调 KNN hidden state 检索。Mem0 的写入门控是显式外部版本,更适合当前工程落地。
横向比较时抓这个角度:Titans 是内部动态记忆,Mem0 是外部动态记忆;两者都在解决“何时写入”。比较对象不是谁“更先进”,而是谁负责哪一层失败。
11. 批判性思考
Titans 很前沿,但不要把 surprise 神化。真正产品需要的是可解释写入、可撤销状态和安全边界;神经记忆的黑箱特性使它暂时更像研究方向。
批判边界:测试时学习很强,但对用户系统而言也最危险;错误输入会立即改变后续行为。这不是否定论文,而是把论文结论放回真实系统的成本、权限和恢复约束里。