智能体的计划,活不过一步:上下文管理为什么是"承重墙"
上周调一个长程 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:同一轨迹跑两遍——A 保留计划、B 删除计划。红色曲线标出的 plan signal 在 step +1 尖峰(0.45),到 step +2、+3 迅速塌缩到 0.11、0.04。这张图基本就是整篇论文的灵魂。
Plan Signal:用余弦距离量化
信号定义就一个公式:
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:注入前信号贴着零(灰色 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:六种任务类型,从拿了就放到加热再放,衰减形状几乎一模一样。尖峰范围 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 直接腰斩,剩下两个"想救 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前沿,关注我