AI编码代理上下文压缩后如何续接?10天430条Codex实验记录

1. 这个实验到底在折腾什么

先把这个标题拆开看。上下文压缩,指的是当 AI 编码代理(比如 Codex 这类 CLI 工具)在一个长会话里连续工作时,对话历史会不断膨胀,最终撞上模型的上下文窗口上限。这时候系统会做一次“压缩”——把前面的对话摘要化、裁剪掉冗余部分,腾出空间继续往下跑。AI 编码代理,就是那种能自己读文件、改代码、跑命令、看报错的自动化编程助手,Codex CLI 是其中比较有代表性的一类。而long_mem和engram这两个词,指向的是“长期记忆”和“记忆痕迹”的机制——说白了,就是压缩之后,怎么让代理还记得之前干过什么、为什么这么干。

这个实验的规模是10 天、430 条公开记录。这不是一个拍脑袋的 demo,而是一个持续观察、逐条记录、事后复盘的过程。我之所以对这个题目感兴趣,是因为我自己用 Codex 做日常开发辅助也有一段时间了,最头疼的场景就是:一个重构任务跑了二十几轮,突然上下文被压缩,代理就像失忆一样,开始重复问已经确认过的信息,或者把之前改好的文件又改回去。这种“接不上”的体验,比模型本身能力不足更让人抓狂。

所以这篇东西适合谁看?如果你只是偶尔用 AI 补全几行代码,那可能感受不深。但如果你在用 Codex CLI 跑多轮任务、做跨文件重构、或者尝试让代理自主完成一个完整 feature,那你一定遇到过压缩后代理“断片”的问题。这个实验的价值就在于,它把“压缩后如何续接”这件事,从模糊的体感变成了可观察、可记录、可复现的工程问题。

我下面会从实验的整体设计思路讲起,然后拆解核心机制,再还原实操过程,最后把踩过的坑和排查方法整理出来。整个过程我会尽量用从业者之间聊天的口吻,把“为什么这么设计”讲清楚,而不是只丢一堆结论。

2. 实验整体设计与思路拆解

2.1 为什么选 Codex 作为观察对象

市面上能跑多轮自主编码的代理不少,但这个实验选了 Codex,我觉得有几个现实原因。第一,Codex CLI 的会话机制相对透明,你能看到它什么时候触发了压缩、压缩后保留了哪些内容,这在排查问题时非常关键。第二,它的工具调用链路清晰——读文件、写文件、执行命令、搜索代码,每一步都有明确的输入输出,方便记录。第三,它的使用门槛适中,不需要自己搭一套复杂的 agent 框架就能复现实验条件。

对比之下,有些代理把压缩逻辑藏在黑盒里,你只能看到结果变差了,但不知道是哪一步丢的信息。Codex 至少给了你观察的窗口。这个实验选择它,本质上是为了让“压缩后接不上”这个问题变得可观测。

2.2 long_mem 和 engram 在方案里的角色

这两个词听起来有点学术,但落到工程上其实很具体。long_mem可以理解为一个跨会话的持久化记忆层——它不依赖当前上下文窗口,而是把关键信息写到外部存储里,需要的时候再捞回来。engram更像是“记忆痕迹”的编码方式,它决定了哪些信息值得被记住、以什么形式记住、怎么在压缩后重新激活。

实验的核心思路是:不指望压缩本身不丢信息,而是假设压缩一定会丢,然后通过 long_mem 和 engram 机制,在压缩发生后主动把关键上下文“补”回来。这就像你开会开到一半,会议纪要被人删了,但你在笔记本上还留着几条关键结论,散会后能凭这几条把讨论续上。

为什么不用“加大上下文窗口”这种简单粗暴的方案?因为窗口再大也有上限,而且长上下文本身会带来注意力稀释和成本上升的问题。压缩是必然要发生的,与其对抗它,不如设计一套压缩后的恢复机制。

2.3 430 条记录是怎么攒出来的

10 天 430 条,平均每天 43 条。这些记录不是随便截个图,而是每条都包含:触发压缩时的会话轮次、压缩前后的关键状态对比、代理在压缩后的第一次响应内容、以及人工判断的“接上了”还是“断片了”。记录维度包括任务类型(重构、修 bug、加功能)、压缩触发原因(轮次上限、token 上限、手动触发)、以及恢复策略(无干预、注入摘要、注入 engram 标记)。

这种记录密度的好处是,你能看到不同任务类型下压缩后的表现差异。比如修 bug 类任务,压缩后代理往往还能靠报错信息续上;但重构类任务,一旦丢了“为什么这么改”的决策链,代理就容易反复横跳。这些规律不是靠一两次体验能总结出来的,必须靠量堆。

3. 核心细节解析与实操要点

3.1 压缩触发时到底发生了什么

Codex 的压缩不是简单地把旧消息删掉。它通常会做几件事:把较早的对话轮次做摘要、保留最近几轮的完整内容、把工具调用的结果做截断或聚合。问题就出在摘要这一步——摘要是有损的,而且摘要的粒度由模型自己决定,你很难控制它保留什么、丢弃什么。

我实测下来,最容易丢的是三类信息:一是“已经排除的方案”,比如你之前试过某个改法不行,摘要里往往不会提;二是“跨文件的依赖关系”,比如 A 文件的改动是为了配合 B 文件的接口;三是“用户的隐含约束”,比如“这个项目不能用某个库”。这三类信息一丢,代理就会走回头路。

3.2 engram 标记的设计要点

engram 的核心是给关键信息打标记,让它在压缩时被优先保留,或者在压缩后被优先恢复。标记的设计有几个讲究。第一,标记要短,不能本身占用太多 token,否则压缩的意义就没了。第二,标记要结构化,比如用固定的键值对格式,方便程序解析。第三,标记要带时间戳或轮次号,这样恢复时能判断信息的时效性。

一个常见的做法是维护一个“决策日志”,每做一次关键决策就追加一条记录,格式类似[决策] 放弃方案X,原因:与现有接口冲突。压缩时这个日志被完整保留,压缩后代理先读这个日志再继续。这样即使对话历史被摘要了,决策链还在。

3.3 long_mem 的存取时机

long_mem 不是每轮都写,那样开销太大。合理的时机是:在压缩触发前,把当前会话的关键状态快照写入 long_mem;在压缩触发后,从 long_mem 读取最近一次快照,注入到新的上下文里。写入的内容包括当前任务目标、已完成步骤、待办事项、以及关键约束。

这里有个坑:如果写入太频繁,long_mem 会变成另一个膨胀的上下文;如果写入太少,快照可能过时。我的经验是,按“任务里程碑”来写,而不是按轮次写。比如完成一个文件的修改、通过一次测试、确认一个接口,这些节点写一次就够了。

注意:long_mem 的读取不要全量注入,否则等于没压缩。只注入与当前任务直接相关的部分,其余留在外部存储里按需检索。

4. 实操过程与核心环节实现

4.1 环境准备与基础配置

先把 Codex CLI 跑起来。安装方式这里不展开,重点说配置。你需要确认几件事:模型选择、上下文窗口大小、以及是否开启了自动压缩。这些在配置文件里都有对应项。我建议先把自动压缩的阈值调低一点,比如在窗口用掉 70% 时就触发,这样你有更多空间做恢复,而不是等到 95% 时手忙脚乱。

配置里还有一个容易忽略的点:工具调用的结果保留策略。默认情况下,较早的命令输出会被截断。如果你在做需要反复看报错的任务,建议把最近几次命令的完整输出保留下来,否则压缩后代理看不到原始报错,只能靠猜。

4.2 记录模板与数据采集

要复现这个实验,你得先有一套记录模板。我用的是这样的结构:

字段说明
轮次当前是第几轮对话
任务类型重构/修bug/加功能/探索
压缩触发原因轮次上限/token上限/手动
压缩前关键状态当前目标、已完成、待办
压缩后首次响应代理说的第一句话或第一个动作
接续判定接上了/部分接上/断片
恢复干预无/注入摘要/注入engram

这套模板的好处是,事后你能按任务类型、触发原因、干预方式做交叉分析。比如你可能会发现,修 bug 类任务在注入 engram 后接续率明显提升,而重构类任务即使注入了也还是容易断,因为重构依赖的决策链太长。

4.3 压缩后恢复的具体操作

当压缩发生后,不要急着让代理继续干活。先做一步“状态对齐”:把 long_mem 里的快照读出来,用一段简短的文字告诉代理当前的任务目标、已完成步骤、以及关键约束。这段话不要长,控制在 200 字以内,否则又占用了宝贵的上下文。

然后让代理复述一遍它理解的任务状态。如果复述错了,说明恢复失败,需要手动纠正。如果复述对了,再让它继续。这一步看起来多余,但实测能拦住不少“表面接上、实际跑偏”的情况。

4.4 参数选择与计算过程

上下文窗口的分配需要算一笔账。假设窗口是 128k token,压缩阈值设在 70%,那就是 89.6k 时触发压缩。压缩后保留最近 20% 的完整内容,约 25.6k,剩下的空间用来放摘要和 engram 标记。摘要控制在 10k 以内,engram 标记控制在 5k 以内,这样还有约 48k 的空间给后续对话。

这个分配不是固定的,要根据任务类型调整。重构类任务需要更多空间放决策链,可以把 engram 标记放宽到 8k;修 bug 类任务需要更多空间放报错信息,可以把最近命令输出的保留比例提高。

5. 常见问题与排查技巧实录

5.1 代理压缩后重复已完成的工作

这是最常见的问题。表现是代理又开始改一个已经改好的文件,或者重新问一个已经确认过的信息。排查思路:先看 engram 标记里有没有记录这个“已完成”状态。如果没有,说明标记没打上;如果有但代理没读到,说明注入环节出了问题。

解决方法:在压缩后的状态对齐阶段,明确列出“已完成”清单,并让代理确认。如果代理仍然重复,检查是不是标记的格式不被解析,或者注入的位置太靠前被后续内容挤掉了。

5.2 压缩后代理丢失跨文件依赖

跨文件依赖是最容易丢的信息,因为它在对话里往往是分散的。A 文件的改动原因在第三轮,B 文件的接口定义在第七轮,压缩后这两条可能都被摘要掉了。排查时,看代理是否在改 A 文件时忽略了 B 文件的约束。

解决方法:在 engram 里专门维护一个“依赖图”,用简单的文本格式记录“A 依赖 B 的某个接口”。压缩后优先注入这个依赖图。实测这个做法能把跨文件任务的接续率提升不少。

5.3 long_mem 写入失败或读取为空

有时候你会发现 long_mem 里没有快照,或者读出来是空的。常见原因是写入时机不对——比如在压缩触发后才写,那时候上下文已经被裁剪了,写进去的就是残缺的。另一个原因是存储路径或权限问题,这个在容器环境里比较常见。

排查时先确认写入时机是否在压缩前,再检查存储是否可写。如果用的是外部存储,还要确认网络或挂载是否正常。

5.4 压缩后代理语气或风格突变

这个问题比较隐蔽。压缩后代理可能从“谨慎确认”变成“直接开干”,或者反过来。这通常是因为摘要改变了对话的“语气基调”。解决方法是在 engram 里保留一条“交互风格”标记,比如“本任务需要每步确认”,压缩后注入这条标记,让代理保持一致的风格。

5.5 常见问题速查表

问题可能原因排查动作解决方向
重复已完成工作engram 未标记或未注入检查标记与注入位置补标记,调整注入顺序
丢失跨文件依赖依赖信息分散被摘要检查依赖图是否存在维护依赖图并优先注入
long_mem 为空写入时机或权限问题确认写入在压缩前调整时机,检查存储
风格突变摘要改变语气基调对比压缩前后语气注入风格标记
接续但跑偏状态对齐不充分让代理复述任务状态增加复述确认步骤

6. 十天记录里的一些规律

把 430 条记录按任务类型分组后,有几个规律挺明显。修 bug 类任务的接续率最高,因为报错信息本身就是强上下文,压缩后只要保留最近一次报错,代理基本能续上。加功能类任务居中,取决于功能边界是否清晰。重构类任务接续率最低,因为重构依赖大量“为什么这么改”的决策,而这些决策在摘要里最容易丢。

另一个规律是,压缩触发越晚,接续越难。因为晚触发意味着压缩前积累的信息更多,摘要的损失也更大。所以把压缩阈值调低,虽然会增加压缩次数,但每次压缩的损失更小,整体接续效果反而更好。

还有一个反直觉的发现:手动触发压缩比自动触发效果好。因为手动触发时你可以先写好 engram 标记和 long_mem 快照,再触发压缩,相当于“有准备地失忆”。自动触发往往是猝不及防的,恢复起来更被动。

7. 我个人的一些实操体会

这套东西跑下来,我最大的体会是:不要指望压缩后代理能自己“想起来”,你得主动帮它“记起来”。long_mem 和 engram 本质上是在给代理做“外部大脑”,把容易丢的信息放在外面,需要的时候再喂回去。

另外,记录这件事本身就有价值。哪怕你不做这么大规模的实验,只是在自己项目里简单记一下每次压缩后的表现,几周下来你就能摸清自己常用任务的接续规律。哪些任务容易断、断了之后怎么补最有效,这些经验是任何文档都给不了的。

最后分享一个小技巧:在会话开始时,就先把任务目标和关键约束写进 engram,不要等到压缩前才补。这样即使第一次压缩来得早,你也有东西可恢复。我试过在会话第一轮就写 engram,后面几次压缩的接续率明显比不写要高。这个习惯养成之后,代理“断片”的概率会低很多。