当编码Agent运行一个长会话时,上下文窗口压力会逐渐累积。在某个时刻,Agent会压缩早期的对话以释放空间。用户不会注意到这个过程正在发生。但Agent现在操作的,是它早期做出决策的有损摘要。
实际后果
Agent开始做出局部合理的决策,但这些决策与它已不再完整记忆的早期架构选择相矛盾。它在原本设计明确避免缓存的地方引入了缓存层。它在新文件中选择了不同的错误处理模式,因为原始模式已经被总结为”标准错误处理”。
我在重构会话中实时观察过这个过程。会话前半段产生干净、一致的代码,遵循一个连贯的架构。然后上下文压缩发生,后半段开始缓慢偏离。Agent不会宣告这一点。它不会说”我不再记得我们关于X的早期决策了”。它只是开始做出不同的选择。
三种模式
模式一:命名漂移。 Agent在开始时一致地命名变量和函数。压缩后,它引入了略有不同的命名约定,与原有的约定不协调地共存。代码库最终出现 getUserById、fetchUser 和 retrieveUser 做着类似的事情。
模式二:约束失忆。 在会话早期,用户指定了一个约束:”不使用外部依赖”或”必须离线工作”或”保持在100行以内”。Agent忠实地遵循这个约束,直到压缩将该约束从活跃记忆中删除。新代码违反了约束,而Agent甚至不知道这个约束的存在。
模式三:抽象层混淆。 Agent早期构建了一个干净的抽象,压缩后开始绕过自己的抽象,因为它记得接口但忘记了设计理由。它直接调用原始API,而不是通过它专门为封装这些调用而构建的层。
有效的缓解策略
将架构决策写入文件,而不仅仅是对话。如果Agent可以重新阅读 DECISIONS.md 或架构文档,它就能恢复被对话压缩破坏的上下文。文件系统成为Agent的长期记忆,对话成为可以被安全压缩的短期工作记忆。
如果你运行的编码Agent会话超过约20轮交互,你很可能已经在经历这个问题。偏离是渐进的,足以让你将其归因于Agent不一致,但根本原因是压缩导致的记忆丢失,而不是推理的不一致。