这段时间我一直在拿 Codex Goal 模式跑各种长任务,有一个场景反复出现:对话已经滚了十几屏,突然系统提示上下文被压缩了。大多数人的第一反应是“完了,它要失忆了”。但有意思的是,压缩完之后它只是短暂顿了一下,然后接着读文件、改代码,目标一点没丢。为什么上下文压缩之后,Goal 模式还能继续执行?这篇就来把里面的机制彻底拆开。
如果你也被“压缩后失忆”坑过,或者正在纠结长任务到底能不能稳定跑完,这篇文章会给你一个比较清晰的答案。我会先从 Codex 的上下文结构讲起,再拆解压缩到底删了什么、留了什么,最后用实测案例分享怎么让 Goal 模式在压缩后不跑偏。
1. Goal 模式为什么绕不开上下文压缩
1.1 长任务必然撞上窗口上限
先说一个很基础的事实:任何模型的上下文窗口都是有限容量的,Codex 也一样。不管用的是哪个版本的模型,哪怕支持很长的上下文,它也是一个有限的工作台,不可能无限塞内容。
Goal 模式恰恰是给长任务设计的。你给它一个目标,它自己拆解、读文件、改代码、跑命令、看结果,再循环往复。这种模式最大的特点就是中间产物极其庞大。
我举个实际体会过的例子。假设你让 Codex 去重构一个服务模块,它会先扫描目录结构,然后逐个读关键文件。一个六百行的 Python 文件,按 token 换算大概要吃掉七千多个 token。如果一轮就读五个文件,光这一步就是三万多 token。读完开始改代码,它常常会把新版本的完整代码写回上下文里,这又是几万 token。改完跑测试,如果日志一大片,几千 token 又没了。
这么一算,一个完整的“读一批文件、改两个文件、跑一次测试”的循环,花掉四五万 token 非常正常。只要任务复杂到需要十来个循环,上下文窗口就一定会被顶穿。这不是偶然,是必然。
1.2 压缩是长任务 Agent 的主动设计
正因为必然会被顶穿,上下文压缩对 Goal 模式来说就不是一个“兜底的补丁”,而是核心设计环节。它要解决的问题是:在上下文容量有限这个硬约束下,怎么让任务继续跑下去。
如果没有压缩机制,长任务到中途就会因为“上下文已满”直接卡死。有了压缩,系统可以把前一段对话整理重写,用更少的 token 保住关键信息,腾出空间给后续执行。
所以你在 Codex 里看到的压缩提示,不是“它不行了”,恰恰是“它还打算继续干”。只要目标、进度、关键决策在压缩后幸存下来,这个任务就还是稳的。这是理解整篇文章的底层逻辑。
接下来真正要回答的问题只有一个:压缩到底保留了哪些东西,才让 Goal 模式能继续跑?
2. Codex 的“上下文”不是一层,而是三层
2.1 系统提示层、工作记忆层、对话历史层
要搞明白压缩为什么不会杀死 Goal,先得知道 Codex 的上下文不是一块平面,它是有层次结构的。
第一层是系统提示层。这一层承载角色定义、能力说明和当前任务目标。在 Goal 模式下,你的目标描述会被固化在这一层里,稳定性最高,正常情况不会参与对话历史的压缩。
第二层是工作记忆层。Codex 执行多步骤任务时,会维护一个关于当前进度和计划的结构化状态。比如它现在在做什么子任务、已经完成了哪些、下一步准备做什么。这些内容可以存在于内部状态里,也可以被它主动写进项目目录的文件中。
第三层是对话历史层。这就是你和它之间一来一回的原始记录,包括工具返回的完整输出、完整代码 diff、报错日志。这一层体积最大,也是压缩器优先下手的对象。
对于普通问答模式,第三层崩了,整个对话就崩了。但 Goal 模式里,前两层才是承重墙。压缩掉第三层的部分内容,就像把工地上堆着的建材收走一部分,脚手架还在,楼就不会塌。
2.2 压缩器眼中的“低价值内容”
压缩器是讲性价比的,它优先压掉体积大且信息密度低的内容。那在 Codex 的上下文里,哪些属于“低价值”?
一是已经写入磁盘的代码。Codex 改完一个文件,新版本已经存在项目里了,上下文里那一大段 diff 就从“必要信息”降级成了“临时影像”。压缩时完全可以把这段清掉,反正后面需要时它会把文件重新打开来看。
二是重复的报错和超长日志。调试阶段经常出现连续好几轮都是同一个错误的变体。这些内容非常占地方,但信息量极低。压缩时它们会被归并成一句话,比如“期间反复出现 A 错误,最终通过 B 方案解决”。
三是试探性方案。实际执行中,Codex 经常试了两种方案,最后选择第二种。对后续执行来说,只需要记住“选了 B 方案,原因是 C”,至于试 A 方案的过程细节,压缩时会直接丢掉。
那哪些是“高价值内容”?用户最新指令、目标本身、当前进度列表、关键决策、验收标准。这些是压缩器优先保留的对象。
2.3 自动触发与手动 compact
Codex 的压缩有自动和手动两条路。自动方式就是上下文使用量逼近上限时触发;手动方式是你主动发起 compact 命令,CLI 里对应的就是 /compact。
压缩完成后,上下文的占用会显著下降。我给一个体感参考:压缩前可能已经用了十几万 token,压缩后往往能回到四五万 token。省出来的这部分空间,就是给后续执行步骤用的。
我自己更喜欢手动压缩。因为自动压缩往往发生在最糟的时刻,比如 Codex 正在读一个大文件时被顶满,或者它刚进入一个非常依赖完整上下文的子任务时。手动压缩则可以挑在任务节点处:一个子任务刚完成、代码已经落盘、正好需要规划下一步的时候。这种时机压完,目标、进度都很清晰,信息丢失最少。
3. 核心解密:Goal 模式靠什么扛住压缩
3.1 目标在系统提示层,天生不会被挤掉
Goal 模式启动时,Codex 会把你的目标写进系统提示层。这个目标在会话里是最高指令,它不参与普通对话历史的滚动压缩。
这意味着什么?意味着压缩发生的时候,你的目标描述就像混凝土浇在承重墙里,动不了。
为了验证这一点,我做过一个很简单的实验。开一个 Goal 任务,目标写得很细,包含三个可验收的子目标。跑了一段时间触发压缩后,我在对话里直接问:“用一句话说说你现在要完成的事。”它把三个子目标基本准确复述出来了,和原始描述高度一致。如果没有系统提示层对目标的固化,单靠压缩摘要很难达到这个准确度。
这也解释了为什么很多人压缩后会担心“它忘了初心”,但实际上只要你把目标写清楚了,Codex 对目标的记忆远比想象中稳定。
3.2 外部计划文件是更硬的一张底牌
相比系统提示层的软保护,更硬的是磁盘上的文件。这一点是很多用户没有充分利用的,也是我觉得最值得养成习惯的地方。
Codex 在执行长任务时,如果目标比较明确,它常常会自己创建计划文件,比如 PLAN.md 或者 TASK.md,里面写清目标、步骤、当前状态。遇到复杂的任务,它甚至会拆出多个阶段,每个阶段对应一个清单。
这个文件存在的意义是:哪怕对话历史被压缩得干干净净,只要文件还在磁盘上,Codex 压缩后的第一件事就可以是读取计划文件。它通过文件内容判断自己做到哪一步、还剩哪些步骤,然后无缝继续。
反过来,如果任务全程只依赖对话上下文里的模糊共识,没有生成计划文件,那么压缩之后出现偏差的概率会大很多。上下文压缩能保住“目标”这个顶层信息,但保不住所有随口的临时决策。
所以我现在的建议很明确:启动复杂 Goal 之前,明确要求 Codex 先输出一份计划文件并保存到项目目录,之后每完成一个阶段都让它在文件里更新状态。这个习惯成本极低,但对长任务稳定性的提升非常明显。
3.3 会话存档与 resume:压缩不是抹除,是重编码
Codex 的会话可以保存到本地,CLI 里有 /resume 命令可以恢复之前的会话。这意味着,压缩发生时生成的新摘要上下文,会被完整写入会话存档。之后你随时可以 resume 这个会话,重新加载压缩后的上下文。
这个机制强的地方在于:存档文件不受模型上下文窗口限制。它是磁盘上的持久化状态。Codex 在 resume 之后,如果需要查看更早的信息,理论上可以分段读取存档内容,而不是一次性把所有历史塞回窗口。
说人话就是:压缩只是把“在线可用的短期记忆”重编码得更紧凑了,而完整的会话存档是躺在磁盘上的长期记录。短期记忆会翻新,长期记录不会凭空消失。这给 Goal 模式又上了一道保险。
3.4 目标驱动循环:控制变量从来不是对话
如果从系统设计角度再看一遍,Goal 模式本质上是一个循环:初始化目标、规划、执行、检查、再规划。每一轮循环开始时,它依据的核心信息是“目标”和“进度状态”,而不是“上一轮对话的逐字记录”。
对话历史在这个循环里扮演的角色,更接近过程日志,而不是控制指令。真正的控制指令是目标本身、是你中途给的明确约束、是计划文件里的清单。只要这些还在,压缩之后它完全可以重新构建对任务的认知。
这也是 Goal 模式与普通问答模式最根本的区别。普通问答里,上下文就是记忆本身,一压缩就失忆。Goal 模式里,上下文只是燃料,目标是引擎。燃料烧掉一部分,引擎不会熄火。
4. 实战验证与踩坑记录
4.1 用“目标复述测试”做压缩后的体检
压缩之后,别急着继续堆需求,先花一分钟做一次目标复述测试。问它三个问题:你现在要达成的目标是什么?你目前完成了哪些步骤?下一步准备做什么?
如果三个答案都和你的预期一致,说明压缩保住了核心状态,可以放心继续。如果第二个问题对不上,说明进度摘要丢了,需要修正。如果第一个问题都讲不清,说明目标本身写得太虚,或者会话结构已经坏了,这时候最稳的做法是调出存档、整理信息后重新来一轮。
我实测下来,这个测试真的只要一分钟,但能避免在错误方向上多跑十分钟。
4.2 目标漂移的四个典型信号
压缩后最让人头疼的其实不是彻底失忆,而是半失忆。目标没丢,但局部细节出了问题,行为开始漂移。我总结了四个典型信号。
第一,自作主张做无关优化。比如目标是重构登录模块,它突然跑去改了一处跟登录逻辑完全无关的公共组件样式。
第二,重复已完成的工作。它忘了某段代码已经重写完了,又开始动手重写一遍,甚至把你已经调好的部分覆盖掉。
第三,实现风格前后不一致。压缩前它用的是方案 A 的接口设计,压缩后它按方案 B 的风格继续写,结果代码一半 A 一半 B,非常难维护。
第四,关键约束记忆淡化。你之前明确说过“不要动数据库表结构”,压缩几轮之后它开始尝试改表结构。
这些漂移的根源,大多不是目标丢失,而是目标级别以下的细节在摘要过程中被压缩掉了。
4.3 三个防漂移的实操习惯
针对漂移问题,我现在有固定的三个动作。
第一,开机写计划。任务开始前,强制让 Codex 把目标、步骤、约束、验收标准全部写进项目里的一个文件。这相当于给目标以下的细节上保险。
第二,阶段落盘。每完成一个子任务,就让它在计划文件里更新状态,并简短写一句“这里用了 X 方案,原因是 Y”。这一步防的是决策丢失。
第三,主动压节点。在里程碑处手动压缩,不要总等系统自动压。压缩前确认工作区已经保存、代码能编译通过,这样即使压缩后有小偏差,也不至于带着一个坏掉的现场继续跑。
这三个习惯配合起来,长任务跑两三个小时都很稳,我已经用这套打法跑过不少重构和功能开发任务。
4.4 一个正例和一个反例
正面例子:我用 Goal 模式给一个小服务做模块重构。最初目标写得很细,包括改造范围、兼容要求、验收方式。启动后我让 Codex 把计划写到 PLAN.md。跑了大概四十分钟,中途上下文见顶自动压缩了一次。压缩结束后,它做的第一件事就是去读 PLAN.md 和当前代码目录,然后准确报出了当前进度和下一步动作,后面几乎没有偏差,顺利收尾。
反面例子:另一个任务里我图省事,只给了口头目标,没让它写计划文件。前面一两轮很顺,但第二次自动压缩之后,它开始出现风格漂移。重构到一半,突然用一种新的风格定义接口,跟前面的代码完全不搭。回看存档才发现,当初没有把“接口风格”这个约束写进任何持久化位置,压缩摘要里也没保留这个细节,于是它就放飞了。
两个例子对比下来,结论其实很简单:上下文压缩保护的是目标这个顶层信息,而目标以下的工程细节,必须靠外部文件来保护。
5. 常见问题速查与自查清单
5.1 问题速查表
这里整理了一份我在实际使用中遇到过的现象、排查方向和对应处理方式,可以直接对照着用。
| 现象 | 排查方向 | 处理方式 |
|---|---|---|
| 压缩后无法复述目标 | 目标描述太模糊 | 启动时写清楚目标与验收标准 |
| 压缩后反复重做已完成工作 | 进度记录没持久化 | 用计划文件记录每阶段完成状态 |
| 压缩后实现风格前后不一致 | 关键决策未写盘 | 把重要决策和理由写进计划文件备注 |
| 压缩后开始改动违反约束的代码 | 约束只在对话里出现过 | 把约束写入项目目录的清单文件 |
| 手动 compact 后没效果 | 命令用法或版本问题 | 确认 CLI 版本,运行后观察 token 占用变化 |
| 压缩后工具调用频繁异常 | 局部会话状态损坏 | 用 /resume 重载会话存档 |
第一行的本质是源头问题。Codex 的压缩摘要是忠实执行者,如果你目标本身就含糊,保留下来的摘要也会是含糊版本。第二、三、四行属于同一类问题:关键信息没有落盘,等于把底牌押在“当前上下文”这一张牌上,压缩一来就露馅。
5.2 长任务自查清单
跑任何一个可能超过半小时的 Goal 任务前,花两分钟过一遍这个清单:
- 目标是否包含可验收的标准
- 是否已生成计划文件并保存到项目目录
- 关键约束是否写进文件,而不是只存在于对话里
- 是否清楚当前会话的上下文占用情况
- 是否规划好在里程碑节点手动 compact
- 压缩后是否先做目标复述测试再继续
这套清单不复杂,但每次都能筛掉不少隐患。以我的经验,只要这六项都满足,Goal 模式跑长任务的可靠性会有质的提升。
5.3 关于 /compact 的一个细节
在 CLI 里,/compact 不是简单地把聊天记录清空,而是触发一次摘要生成,并把摘要加载为新的上下文基础。运行后会看到新的上下文占用数字,通常明显下降。
我建议把“观察 compact 之后的 token 占用变化”当成常规动作。如果压完还几乎没降,说明会话里可能有超大单块内容,比如某个大文件被完整塞进了历史。这时候要从源头削减:避免让它反复读同一个大文件,或者在合适时机引导它用定向搜索代替整文件读入。
另外还有个小经验:如果上下文里已经积累了超大日志输出,可以主动让它把日志写到文件里,再在需要时用搜索读取关键片段,而不是让日志全文占着上下文。
6. 写在最后
我现在跑超过一小时的长任务,基本固定一套姿势:先写好目标、让它出计划文件、阶段落盘、掐着节点手动压缩。这套姿势最初就是从一次“压缩后任务还能继续”的惊讶里摸索出来的,后来想明白了,不是 Codex 有什么魔法,而是 Goal 模式在设计上就把目标放进了不容易被压缩掉的位置。
最后分享一个实操心得:上下文压缩之后,如果发现它还在继续推进,别急着打断,先给它一点时间让它自己读文件、重新对齐进度。很多时候它需要的只是一次重新锚定的机会。我见过太多次用户刚压完就问“你还记得目标吗”,然后收到一条回复就慌着接管,结果反而打断了它正在进行的恢复流程。给它一点信任,观察它的复述和下一步动作,再决定要不要介入,这是压缩场景里最实用的一条经验。