智能体的计划,活不过一步:上下文管理为什么是"承重墙"

上周调一个长程 Agent 的时候,我碰到一件挺邪门的事。

任务一开始,模型规划得头头是道——先去哪、拿什么、放哪里,步骤列得清清楚楚。结果跑了五六步,它就像突然失忆一样,开始在原地打转,把一个早就规划好要做的动作彻底忘了。我当时第一反应是上下文被截断了,plan 那段被 evict 掉了。检查了一下,没有,plan 还好好待在 history 里。

那它为什么不照着做?

这篇来自 Snowflake AI Research 的论文,恰好把我这个困惑捅破了。它的结论简单到有点扎心:标准 LLM Agent 根本没有把计划"记在心里",它只是把计划"放在眼前"。 一旦计划离开上下文窗口,哪怕只是被往后挤了一步,模型对它的"内部记忆"就会断崖式衰减——一个动作-观察的周期内,衰减 4 到 12 倍。


一段话讲清楚这篇论文在干嘛

长程 Agent 离不开上下文管理:压缩、摘要、驱逐旧 token,这样任务才能在有限窗口外继续跑。这套逻辑成立有个前提——被丢掉的信息要么不再需要,要么已经被模型"内化"了。计划恰恰是最危险的反例:它写在最早,要用很多步,却最先被驱逐。

作者搞了个叫 replay pairing(重放配对)的诊断方法:同一条轨迹跑两遍,一遍保留 plan,一遍删掉 plan,然后测两者隐藏状态的余弦距离。在 Llama-3.1-70B 上,plan 注入后下一步信号飙到 0.453,再走一个动作-观察周期就掉到 0.110,衰减 4.1 倍;换到 HotpotQA 任务甚至衰减 12.4 倍。更狠的是压力测试:天真地把 plan 驱逐掉,ALFWorld 成功率直接从 56.7% 砸到 22.0%,掉了 34.7 个百分点;而事后想用探针把 plan 再"捞回来",根本救不回。

我的判断:这不是一篇提新方法刷 SOTA 的论文,而是一篇做"测量"和"诊断"的论文。它的价值不在于解决了问题,而在于用相当严谨的实验把一个被很多人模糊感知、却没人量化过的现象钉死了——Agent 赖以工作的关键信息,可能是"上下文驻留"的,而不是"持久化"的。 这个洞察对做 Agent 工程的人来说,分量很重。

  • 论文标题:Plans Don't Persist: Why Context Management Is Load Bearing for LLM Agents
  • 作者:Aman Mehta, Anupam Datta(Snowflake AI Research)
  • 链接:https://arxiv.org/abs/2606.22953 (提交于 2026 年 6 月 22 日,17 页 8 图)

🤔 先说清楚问题:什么叫"计划没被持久化"

你可能会觉得,这有什么好研究的?plan 在上下文里,模型自然就能用啊。

问题在于"用"这个动作背后的机制。我们默认 Transformer 在读到 plan 之后,会把 plan 的语义"吸收"进它的内部状态(hidden state),后面每一步都带着这份理解往前走。就像人看完一份行程单,脑子里有了个大致框架,单子收起来也照样能执行。

但如果模型其实没有"吸收",只是每一步都重新去上下文里"看一眼" plan 呢?

那后果就严重了。因为所有上下文管理策略——压缩、摘要、滑动窗口、驱逐——都建立在"模型已经内化了旧信息"这个假设上。如果这个假设不成立,那你每丢掉一段 plan,丢掉的不是冗余,而是模型当前唯一的"记忆载体"。

这就是论文要回答的核心问题:计划到底是模型的持久状态,还是只是上下文里的一段文本?

直觉上你可能倾向于前者。这篇论文用数据告诉你:是后者。而且衰减得比你想象的快得多。


🔬 方法核心:怎么测"模型有没有把计划记在心里"

这部分是全篇我最欣赏的地方。测量"内部状态里还剩多少 plan",听起来玄学,作者却给了一个干净利落的操作化定义。

Replay Pairing:同一条路走两遍

核心idea一句话:让模型在"有 plan"和"没 plan"两种条件下,走完全相同的轨迹,看它的内部状态差多少。

具体怎么做:

  • 条件 A(plan 保留):Agent 正常跑,在第 2 步注入一个 guard 消息,逼它把完整计划说出来,plan 进入 history。记录每一步每一层的隐藏状态 \(\mathbf{h}_A\)
  • 条件 B(plan 删除重放):把 A 走过的轨迹原封不动重放一遍——喂给模型 A 当时的 observation 和 action,但是把 plan 那段对话删掉。模型在这个条件下产生隐藏状态 \(\mathbf{h}_B\)。B 自己输出什么不重要,整个对话由 A 的轨迹驱动。

两个条件唯一的差别,就是 plan 在不在 history 里。所以两者隐藏状态的差异,就纯粹反映"plan 这段信息对模型当前内部状态的影响有多大"。

图1:Replay Pairing 诊断的示意图。上半部分 A 条件保留 plan,下半部分 B 条件删除 plan 但重放完全相同的动作与观察。两者隐藏状态的余弦距离就是 plan signal,它在 plan 注入后一步飙升,一步之内衰减到接近零。

图1:同一轨迹跑两遍——A 保留计划、B 删除计划。红色曲线标出的 plan signal 在 step +1 尖峰(0.45),到 step +2、+3 迅速塌缩到 0.11、0.04。这张图基本就是整篇论文的灵魂。

Plan Signal:用余弦距离量化

信号定义就一个公式:

\[\text{PlanSignal}^{(s,\ell)}=1-\cos\left(\mathbf{h}_A^{(s,\ell)},\;\mathbf{h}_B^{(s,\ell)}\right)\]

step 索引相对 guard 注入点对齐:step 0 是 guard 那一步,step +1 是下一个 Agent 回合。

这里有个特别漂亮的验证设计:plan 注入之前的那些步(s<0),A 和 B 还没有任何差别,信号理论上应该是零。 实测低于 \(10^{-3}\)(基本是浮点噪声)。这个零基线就是方法的"对照组",证明信号不是噪声造出来的。说实话,做诊断方法的论文很多,但能把零基线钉这么死的不多。

探针:把信号衰减变成可检测的诊断器

光测出衰减还不够,作者想要一个能实时报警的工具。于是在峰值层 \(\ell^*\)(Llama-70B 上是 L32)训练一个 Ridge 回归探针,去拟合 plan signal 的标量大小,再设个阈值 \(\tau\) 转成"开火/不开火"决策。

为什么用回归不用二分类?这是个细节但很关键——因为 step index(当前是第几步)可以从 residual stream 里平凡地解码出来,二分类探针很容易偷偷学到"第几步"这个捷径,而不是真的在读 plan 内容。作者对这点很警觉,专门做了泄漏控制(后面会讲)。

⚠️ 这里作者很克制地强调了一句:L32 探针检测的是衰减这个现象,不是证明它在直接读取 plan 的内容本身。这种不越界的表述,反而让我更信任这篇论文。


📉 主结果:4.1 倍的断崖

先看核心那张图。

图3:Llama-3.1-70B 在 ALFWorld 上,plan signal 随相对步数的变化(80 个任务,均值±标准误)。红色虚线左侧是注入前的近零基线,step 0 注入后 step +1 跳到 0.453,下一步直接掉到 0.110,衰减 4.1 倍。

图3:注入前信号贴着零(灰色 Pre-plan),注入后蓝色柱子从 0.453 一路塌到 0.11、0.06、0.04……一个动作-观察周期,4.1 倍。后面拖着一条长长的低位尾巴,但已经接近噪声水平。

数字摆出来:

相对步 plan signal 说明
step −2, −1 < \(10^{-8}\) 注入前基线,浮点噪声
step +1 0.453 ± 0.039 峰值
step +2 0.110 ± 0.032 一个周期内衰减 4.1×
step +3 ~0.060 继续下滑
step +5 ~0.027 基本归零

这个衰减曲线最让我意外的,是它在不同任务类型上几乎完全重合。

图2:六种 ALFWorld 任务类型的衰减曲线。clean+place、pick two、heat+place、pick+place、examine、cool+place 六条线几乎完美叠在一起,step 0 都在 0.45 附近,到 step 2 都收敛到 0.1 以下。

图2:六种任务类型,从拿了就放到加热再放,衰减形状几乎一模一样。尖峰范围 0.445–0.474,衰减率 4.0–4.4 倍。这种跨任务的高度一致,说明衰减不是某类任务的偶然,而是模型的结构性行为。

层级上看,step +1 的峰值出现在 L32(80 层模型的 40% 深度),信号高达 0.686 ± 0.024,L28/L36 形成一个宽的中网络峰。换到 Llama-3.1-8B,形状完全一样——峰值 0.382,衰减 10.9 倍,峰值层在 L12(32 层的约 37.5% 深度)。相对深度对齐这件事挺有意思,暗示这是 Transformer 处理 plan 的某种通用机制,而不是某个特定 checkpoint 的怪癖。

探针这边,Ridge 回归在 ALFWorld 上 \(R^2\) 达到 0.875,AUROC 0.999。更实用的是 lag 分析:在 80 个任务里有 31 个出现了"计划偏离"(用 Claude Opus 4 当 judge,判定第一个 plan-alignment < 0.3 的动作),探针平均提前 4.45 步就开火,在 74.2% 的情况下领先于实际偏离发生。换句话说,它真能当个早期预警器用。


🧩 一个容易被忽视的坑:推理模型的"测量混淆"

这部分是论文的第二个贡献,也是我觉得作者真正下了功夫的地方。

你可能会想:那推理模型(带 <think> 的那种)是不是把 plan 记得更牢?毕竟它每步都在思考。

作者一开始测 DeepSeek-R1-Distill-Llama-70B,结果 step +1 信号只有 0.022,同任务下 Llama 是 0.099——R1 看起来弱了 4.5 倍,好像推理模型反而更不在乎 plan。

但作者没急着下结论,而是停下来追问了一句:这个低信号,是真的 plan 衰减更快,还是我的测量方法出了问题?

问题出在 <think> 上。推理模型在每个动作前都会发一段 <think>…</think> 轨迹,而这段轨迹里会把 plan 的内容重新推导一遍。标准的 replay pairing 只删掉 plan 那段对话,却把这些 <think> 块原样保留了。结果就是:B 条件里虽然删了 plan,但 <think> 里又把 plan 重新陈述了,两个条件都还编码着 plan,余弦距离自然被严重低估。

作者给这个现象起了个名字——reasoning-trace confound(推理轨迹混淆),并提出 strict stripping(严格剥离) 来修:在删 plan 对话的基础上,还要把 B 历史里每个 assistant turn 中完整的 <think>…</think> 块也删掉(</think> 之后的 Thought/Action 行保留)。

修完之后,R1 的 step +1 信号从 0.022 涨到 0.058,变化 +163%;5 个 held-out 任务上恢复 +153%。而对照组——本来就没有 <think> 的 Llama——strict stripping 只带来 +4.8% 的变化,基本是 no-op。

条件 R1 step +1 信号
标准 replay 0.022
strict-strip 0.058(涨 163%
held-out 5 任务 恢复 153%
Llama 对照(no-op) 仅 4.8%

这个一升一平的对比,干净地证明了:R1 的低信号不是因为它真的不在乎 plan,而是测量方法把信号"洗"掉了。R1-Llama 的差距也从 4.5 倍缩到 1.7 倍。

我特别喜欢这段的处理方式——发现一个反常结果,不是顺势编个故事("推理模型不依赖 plan"),而是怀疑自己的尺子。这种科研直觉,比结论本身更值钱。


🔀 探针迁移:R1 把计划"存"在了不同的地方

修好测量之后,作者做了个跨机制的探针迁移实验,结论很有味道。

探针 评估目标 AUROC n
Llama L32 Llama ALFWorld 0.999 80
Llama L32 Llama HotpotQA 1.000 25
Llama L32 R1 raw(迁移) 0.600 5
Llama L32 R1 strict(迁移) 0.748 [0.62, 0.87] 19
R1 L32(自训) R1 strict 1.000 85

用 Llama 训的探针去测 R1,strict 条件下 AUROC 只有 0.748(p=6×10⁻⁴,统计显著但远不完美);可 R1 自己训的探针轻松到 1.000。两者方向夹角高达 89.3°(余弦相似度 0.012),几乎正交。

这说明什么?R1 确实编码了 plan 信号,但用的是和 Llama 完全不同的隐藏状态方向。 plan 信息在那里,只是"藏"在了不一样的子空间里。这个发现挺反直觉的——同样从 Llama 蒸馏来的模型,经过推理训练后,居然重新组织了表征 plan 的几何结构。

不过这块的样本量偏小(迁移只有 19 个),p 值也只是勉强显著,作者自己也没把话说满。我倾向于把它当成一个"有意思的线索"而不是"铁证"。


🧪 压力测试:把计划救回来,根本不够

前面都是在测内部状态,最后这个实验才真正回答了工程师最关心的问题:这事儿到底对任务成功率有多大影响?

设置:四种上下文策略,30 个 ALFWorld 任务 × 5 次运行 = 每个策略 150 次,Llama-3.1-70B,20 步上限,保留最近 4 步。

策略 成功率 标准误 Δ p 重浮现次数
none(不压缩) 56.7% 4.0% 0.0
naive(天真驱逐) 22.0% 3.4% −34.7(vs none) <0.001 0.0
plan_protected(保护 plan) 20.7% 3.3% −1.3(vs naive) 0.89 0.0
probe_gated(探针触发重浮现) 24.7% 3.5% +2.7(vs naive) 0.67 6.1

图4:压缩压力测试。none 不压缩成功率最高,naive 天真驱逐砸掉 34.7 个百分点,而 plan_protected 和 probe_gated 两个 plan-aware 策略都没能把成功率救回来。误差棒为标准误。

图4:四根柱子,none 一骑绝尘,naive 直接腰斩,剩下两个"想救 plan"的策略和 naive 在统计上没区别。这张图基本宣告了"光保护计划文本"这条路走不通。

两个关键结论:

第一,天真地驱逐 plan,成功率从 56.7% 掉到 22.0%,−34.7 个百分点,p<0.001。这个幅度是灾难性的,等于把一个能用的 Agent 直接打废一半。

第二,也是更扎心的——两种"plan-aware"策略都救不回来。 不管是简单地永久保护 plan 不被驱逐(plan_protected),还是用探针检测到信号衰减就把 plan 重新插回上下文(probe_gated,平均每次运行重浮现 6.1 次),相比 naive 都没有统计显著的改善(p=0.89 和 0.67)。

这个结果才是论文标题那句"plan protection alone is not enough"的实证支撑。问题不只是"plan 被删了",而是"plan 即使在上下文里,模型也只能短暂地用一下"。 把文本捞回来,治标不治本,因为模型本来就不会把它持久化成内部状态。

说实话,看到 probe_gated 也救不回来的时候,我愣了一下。我原本以为既然探针能精准检测衰减、还能提前预警,那"检测到就重新插回去"应该是个顺理成章的解法。结果不行。这恰恰说明,单纯在上下文层面打补丁解决不了根本问题——这是个表征层面的事。


💡 我的判断:一篇诚实得有点难得的论文

先说我觉得它好在哪。

测量方法干净。 replay pairing 的设计——同一轨迹两条件、零基线对照——非常优雅,把一个玄学问题变成了可量化、可证伪的实验。这种把模糊直觉操作化的能力,是好的实证研究的标志。

对自己的方法足够警惕。 发现 R1 信号低,不是顺势讲故事,而是怀疑尺子,找出 reasoning-trace confound 并修掉。step-index 泄漏那块也专门做了 shuffle 控制(真 AUROC 1.000,打乱标签后掉到 0.297,证明探针学的不是"第几步"这个捷径)。这种自我审查在如今追求 SOTA 的论文里太少见了。

结论诚实。 它没有给你一个"我们提出 XX 方法完美解决了问题"的爽文结局。相反,它的压力测试明确告诉你:现有的 plan-aware 策略都不管用。一篇敢于报告"我试过的解法都失败了"的论文,可信度反而更高。

再说我的保留。

没有解药。 论文是纯诊断性质的,指出了问题、量化了问题、证明了简单补丁无效,但没给出真正的解决方向。附录里那些干预实验(residual-stream steering、head-level 干预)效果基本都在噪声范围内(Δ 大多 ±1 到 ±3pp,置信区间跨零)。所以你读完会有点"那然后呢"的悬空感。

部分结论样本量偏小。 跨模型、跨机制的迁移实验,n 经常只有十几二十个,p 值勉强显著。这些更像是"值得后续深挖的线索",而不是确凿结论。作者表述上也比较克制,没过度声张。

ALFWorld 和 HotpotQA 衰减差 3 倍这件事,作者的解释是 ALFWorld 的 observation 和 plan 相关(动作反馈会不断"刷新" plan 相关特征),而 HotpotQA 的维基段落和 plan 信息正交,所以覆写更快。这个解释合理,但也提醒我们:衰减速度其实高度依赖任务的 observation 结构,不能一概而论。


🔧 对做 Agent 工程的启发

如果你也在做长程 Agent,这篇论文至少给三个实际提醒:

别太信任"压缩+摘要"。 你以为模型已经内化的旧信息,可能根本没内化。尤其是计划、约束、目标这类"写在早期、用在全程"的信息,驱逐它们的代价可能远超预期。

关键信息要持续"在场",而不是"曾经出现过"。 既然模型不会持久化 plan,那与其指望它记住,不如在架构层面让关键约束每一步都重新出现在它眼前——比如固定的 system reminder、每步重注入的目标摘要。论文里 probe_gated 的失败说明"偶尔捞回来"不够,可能需要"一直在"。

推理模型有点不一样,但别想当然。 R1 这类模型的 <think> 会反复重述 plan,某种程度上起到了"持续在场"的作用,这或许是它们在某些长程任务上更稳的原因之一。但论文也显示,它编码 plan 的方式和基座模型完全不同,迁移现成的诊断工具未必管用。

归根结底,这篇论文把一句很多人隐约感觉到、却没人敢明说的话钉死了:当前的 LLM Agent,并不真正"记得"自己的计划,它只是在不停地"重读"计划。 上下文管理之所以是承重墙,正是因为我们把太多本该持久化的东西,悄悄寄存在了那个随时会被清空的窗口里。

arXiv ID 2606.22953,17 页,值得做 Agent 的人认真读一遍——尤其是那个 replay pairing 的设计,迁移到你自己的诊断里可能会很有用。


觉得有启发的话,欢迎点赞、在看、转发。跟进最新AI前沿,关注我