190 lines
12 KiB
Markdown
190 lines
12 KiB
Markdown
# 压缩讲义:Agent 怎样从历史中学习
|
||
|
||
## 1. Memory 不是仓库,而是受限状态
|
||
|
||
最朴素的 Agent memory 是保存聊天记录,然后按相似度找回来。这个模型隐含了两个假设:过去可以被完整保存;只要找到相关文本,模型就能做出更好的动作。最近一年的工作反复证明,这两个假设都不够。
|
||
|
||
更有用的形式化来自 POMDP:Agent 看不到完整世界状态,只能用历史构造一个内部状态。设历史为 `h`、当前问题为 `q`、memory 编码器为 `g`,实际决策只能依赖:
|
||
|
||
```text
|
||
m = g(h, q)
|
||
a = policy(m, q)
|
||
```
|
||
|
||
因此 memory 的目标不是重建全部过去,而是让 `m` 成为当前决策的充分状态。这个视角立刻解释了三个现象:
|
||
|
||
- 两段语义相似的历史,可能要求完全不同的行动,因此不能合并。
|
||
- 两段描述完全不同的历史,如果对当前问题导向同一个最优行动,可以安全压缩。
|
||
- memory 质量最终要用决策损失衡量,不能只用召回率或摘要相似度衡量。
|
||
|
||
[DeMem](https://arxiv.org/abs/2605.10870) 把这个直觉写成 decision rate-distortion。对历史 `h` 采取动作 `a` 的损失是:
|
||
|
||
```text
|
||
Delta_q(h, a) = best_value(h, q) - value(h, q, a)
|
||
```
|
||
|
||
如果一组历史存在一个共同动作,使每段历史的损失都不超过容忍值 `epsilon`,它们才可以共享一个 memory state。这给出了一个非常实用的遗忘原则:
|
||
|
||
> 可以忘记描述差异,但不能忘记会改变决策的差异。
|
||
|
||
## 2. 为什么长上下文不是答案,但必须作为 baseline
|
||
|
||
长上下文保留原始信息,避免了过早摘要和 schema 丢失,所以它经常比复杂 memory 系统更强。[EvoMemBench](https://arxiv.org/abs/2605.18421) 在统一协议下比较 15 种方法,得到三个重要结果:
|
||
|
||
1. 长上下文 baseline 仍然很有竞争力。
|
||
2. memory 在当前上下文不足、任务更难时才更稳定地产生价值。
|
||
3. 没有一种 memory 形态能同时支配所有任务。
|
||
|
||
这不意味着只要扩大窗口即可。上下文越长,推理成本和延迟越高,干扰也越严重;而跨 session 的持久状态、可删除性、来源治理和经验学习也不是上下文窗口本身能解决的。
|
||
|
||
正确结论是:长上下文是 memory 实验必须击败的控制组,而不是必须淘汰的旧方案。
|
||
|
||
## 3. 相似度为什么经常失效
|
||
|
||
向量检索回答的是“什么文本看起来像当前问题”,Agent 真正需要的却可能是:
|
||
|
||
- 哪个动作导致了当前状态?
|
||
- 哪条约束仍然有效?
|
||
- 上次失败发生在哪个分支?
|
||
- 哪段经验对未来成功有长期贡献?
|
||
|
||
这些关系分别是因果、时间、控制流和价值关系,不能被单一语义距离稳定表达。
|
||
|
||
[AutoMEM 的诊断研究](https://arxiv.org/abs/2606.04315) 给出了两个具体失效层:
|
||
|
||
- 表示失败:索引 schema 根本没有保存 step id、动作或未来问题需要的谓词,之后再强的检索器也找不回来。
|
||
- 检索失败:原始存储里仍有答案,但一次被动路由没有把细节交给回答模型,也没有第二次补证据的机会。
|
||
|
||
它还给出了“什么时候索引值得做”的两个条件:schema 必须能表达问题所需关系;大量问题必须确实需要跨记录聚合。否则,保留原始文本并让 Agent 用 `grep/read` 主动查找,可能更通用。
|
||
|
||
所以结构化不是越多越好。结构化是在写入时对未来问题下注,而主动检索是在查询时再决定需要什么结构。
|
||
|
||
## 4. 四类 memory,解决四类失败
|
||
|
||
### 4.1 事实与主题文档
|
||
|
||
适合用户偏好、人物关系、项目事实和跨 session 知识更新。关键不是把每句话切成孤立向量,而是把相关证据维护成可以修订的主题单元。
|
||
|
||
[Infini Memory](https://arxiv.org/abs/2606.10677) 使用 topic documents:新观察先进入缓冲区,再周期性巩固到主题文档;读取时由 Agent 迭代搜索、查看局部行和补充证据。在 MemoryAgentBench 上,其 agentic variant 报告 64.7% overall;维护结构固定时,agentic retrieval 相比 summary+BM25 增加 3.3 点,而移除 split/merge 使 LongMemEval 减少 6.7 点。
|
||
|
||
这里的启发不是“文件一定胜过数据库”,而是 memory 需要可维护的语义单元、原始证据链接和多步检查能力。
|
||
|
||
### 4.2 当前执行状态
|
||
|
||
长程工具任务的主要问题常常不是忘记一个事实,而是丢失当前控制状态:已经完成哪些子目标、哪些路径失败、哪些动作改变了后续约束。
|
||
|
||
[MAGE](https://arxiv.org/abs/2606.06090) 用两层树表示执行状态:底层保存 action-observation,顶层在子目标边界压缩;当前状态来自 root-to-current path。四个操作形成闭环:
|
||
|
||
- `Grow`:追加新的动作与观察。
|
||
- `Compress`:在边界把完成片段压缩为子目标状态。
|
||
- `Maintain`:在摘要成为可信状态前检查遗漏和执行错误。
|
||
- `Revise`:回到错误边界,从新分支继续,隔离错误轨迹。
|
||
|
||
这个结构解决的是控制流连续性,而不是文本相似性。论文在 MemoryArena 报告相对 baseline 平均提高 7.8 到 20.4 个百分点,同时比长上下文减少 55.1% token。
|
||
|
||
### 4.3 稳定规则与技能
|
||
|
||
如果同一种错误反复发生,把旧案例再次塞进上下文可能不如直接改变 Agent 的行为规则。
|
||
|
||
[Compiled Memory](https://arxiv.org/abs/2603.15666) 的 Atlas 把经过验证的经验写成 system prompt 中的子规则:memory 是 distillation,读取是 instruction rewriting。其 CUAD 实验报告 token F1 增加 8.7 个百分点,HotpotQA joint F1 增加 3.16 个百分点;同一份从 GPT-4o 错误编译的 prompt 在 Claude Sonnet 4.5 上仍增加 2.31 个百分点。
|
||
|
||
但这个结果有重要限制:演化 prompt 从约 960 增至 1570 token,论文没有完成等长度通用内容控制;而训练信号没有覆盖的目标不会自然改善。这说明程序记忆适合稳定、重复、可验证的任务规则,不适合不断变化的事实。
|
||
|
||
### 4.4 有价值的经验链
|
||
|
||
一次成功可能依赖更早的记忆,而那条记忆又帮助生成了后续记忆。只奖励最后一次被直接检索的记录,会错误分配信用。
|
||
|
||
[MemQ](https://arxiv.org/abs/2605.08374) 记录 memory provenance DAG,并把 TD error 沿祖先链反向传播:
|
||
|
||
```text
|
||
delta(m) = reward + gamma * Q(new_memory) - Q(m)
|
||
credit(ancestor) += alpha * (gamma * lambda)^depth * delta(m)
|
||
```
|
||
|
||
它在多步任务上的提升大于单步任务,说明“结构距离”可以比单纯时间距离更适合经验归因。不过它假设 memory 单调增长,尚未解决巩固和删除,维护 DAG 也会持续增加成本。
|
||
|
||
## 5. 写入比读取更危险
|
||
|
||
检索错了一次通常影响一个回答;持久 memory 写错一次,可能在未来反复被召回,成为系统状态污染。
|
||
|
||
[TrustMem](https://arxiv.org/abs/2606.25161) 把 memory update 视为可审计 transition,动作空间是 `WRITE / REVISE / PRUNE`。verifier 从三个维度检查每次更新:
|
||
|
||
- coverage:新输入中的重要信息是否保留。
|
||
- preservation:原有有效信息是否被无依据删除或扭曲。
|
||
- faithfulness:新写内容是否有当前输入或旧状态支持。
|
||
|
||
这比只看最终问答正确率更合理,因为正确答案也可能掩盖中间产生的危险状态。论文报告,相比各错误类型的最强 baseline,遗漏、破坏和幻觉分别减少 40.1%、79.1% 和 50.0%。
|
||
|
||
但“内容真实”仍不等于“有权支持行动”。外部网页中的恶意指令即使被准确保存,也不应在未来授权转账。[MemLineage](https://arxiv.org/abs/2605.14421) 因此把来源签名、派生 DAG 和敏感动作 gate 结合起来:一条行动理由如果沿派生链来自不可信源,就不能直接执行。
|
||
|
||
它的确定性机制隔离实验中,三类攻击的 ASR 均降为零,但这个结果来自自定义 cross-session harness;headline 评估没有覆盖完整自适应攻击,且作者明确假设模型权重和推理路径可信。它支持“来源链必须进入执行策略”这个方向,但不能被读成 memory 安全已解决。
|
||
|
||
## 6. Memory controller 才是核心能力
|
||
|
||
写入什么、怎样组织、什么时候读取、如何补证据和何时遗忘,本质上都是控制策略。当前出现了三种控制方式:
|
||
|
||
| 控制方式 | 优点 | 代价 |
|
||
| --- | --- | --- |
|
||
| 固定规则 | 可预测、可调试、成本低 | 难适应任务与状态变化 |
|
||
| LLM 工具调用 | 灵活,可按问题主动查找 | 多轮调用昂贵,受模型能力影响 |
|
||
| 训练控制器 | 能从结果优化策略 | 训练和 credit assignment 复杂,容易过拟合 benchmark |
|
||
|
||
[HORMA](https://arxiv.org/abs/2606.11680) 提供了一个值得保留的分工:高能力模型负责异步 memory organization,轻量模型学习低延迟 retrieval。论文中,Qwen 3.5 4B retriever 仅在 LoCoMo 训练,却能迁移到 ALFWorld 和 LongMemEval;但弱模型如果一开始就把 memory 组织坏了,更强的 retriever 也补不回来。
|
||
|
||
这正好说明我们自己的模型分工原则:小模型适合局部、可验证、低风险操作;跨论文压缩、结构设计和关键判断需要强模型或人工研究编辑承担。
|
||
|
||
## 7. 怎样证明 memory 值得存在
|
||
|
||
Memory 论文最容易犯的错误,是只比较成功率,不计算 memory 模块自己消耗的 token、延迟和额外调用。
|
||
|
||
[在线 memory/skill 的预算研究](https://arxiv.org/abs/2606.15017) 把相同预算交给 vanilla actor 增加观察和行动步数。在 WebArena 的三个域、三个模型上,budget-matched vanilla baseline 的平均成功率都高于三个在线 augmentation 方法,并且通常 token 更少;在 WorkArena-L1 上也保持竞争力。
|
||
|
||
这项结果不能推广到所有 memory:它研究的是在线模块,离线编译后被大量复用的技能需要另一种摊销方式。但它给出了必须遵守的评测卫生:
|
||
|
||
1. 报告所有模块的 token 和延迟,不只报告主 Agent。
|
||
2. 与长上下文和 budget-matched vanilla actor 比较。
|
||
3. 多次运行并报告方差。
|
||
4. 分开评估写入、组织、读取、回答和动作执行的错误。
|
||
5. 测试更新、冲突、遗忘、污染和跨任务泛化,不只测静态 recall。
|
||
|
||
## 8. 综合结论:一个可工作的参考架构
|
||
|
||
对需要长期运行、可学习、可审计的 Agent,可以从下面的最小架构开始:
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
E["Immutable event log"] --> V["Transition verifier"]
|
||
V --> B["Current buffer"]
|
||
B --> T["Topic documents"]
|
||
B --> X["Execution-state tree"]
|
||
T --> K["Compiled rules / skills"]
|
||
X --> K
|
||
Q["Current task"] --> C["Memory controller"]
|
||
T --> C
|
||
X --> C
|
||
K --> C
|
||
C --> D["Minimal sufficient context"]
|
||
D --> A["Agent action"]
|
||
A --> O["Outcome and feedback"]
|
||
O --> L["Credit and consolidation"]
|
||
L --> V
|
||
P["Provenance / time / principal / policy"] --> V
|
||
P --> C
|
||
P --> A
|
||
```
|
||
|
||
这不是要求第一天实现全部层。它给出的是责任边界:
|
||
|
||
- 原始日志负责可恢复和审计。
|
||
- topic documents 负责可维护事实。
|
||
- execution tree 负责长任务状态。
|
||
- compiled rules 负责稳定行为改变。
|
||
- controller 负责按任务选择最小充分上下文。
|
||
- verifier 与 provenance 负责阻止错误和不可信状态永久化。
|
||
- outcome loop 负责让 memory 从使用结果中学习。
|
||
|
||
最终设计原则可以压成一句话:
|
||
|
||
> 先判断未来决策需要保留什么区别,再选择存储结构;先用公平 baseline 证明价值,再让 memory 获得长期权限。
|
||
|