[🤖] 解决 Codex 在“Context automatically compacted”后重复执行近期用户指令的问题
✨ GPT-5.6 Sol 的总结
记录我找出 Codex 在“Context automatically compacted”后反复执行已完成指令的原因,修改 hook 让它无需用户每次发送 continue 也能准确回到压缩前的工作位置,并通过真实自动压缩完成验证。
我写过“已经解决”的文章,结果又错了
几天前,我写了Codex 上下文自动压缩后重新执行最后一条指令的问题与解决方法。当时我加入了“不要把自动压缩当成新的用户输入”的提示,并确认压缩后工作还能继续。我以为问题已经解决。
我错了。几天后,在处理 Leave Operations UI/UX 时,同样的症状原样复发。我已经要求它停止补充下载细节,先检查真实的桌面页面,可每次压缩后,Codex 还是从下载的话题重新开始。
Context automatically compacted 之后不断重复近期指令的流程,我们之前不是修过了吗……??怎么症状还完全一样?
只要一压缩上下文,你就又开始提下载,这不是明摆着把最近的用户指令一遍遍重新注入吗。
是的。8月7日应用了防护 hook,但这次记录表明同样的症状再次出现。之前的修改并没有解决根本原因。
旧 hook 只会在压缩后提示“继续刚才的工作”。问题在于,它没有说明哪些工作已经完成、应该从哪里继续。压缩后的摘要里仍保留着一条具体的旧用户指令,Codex 最终选择了它,而不是含糊的 continue。
我重新检查了21次真实压缩记录,同样的模式不断出现。工作明明已经转到其他页面,多个区段却又从“冻结下载补充工作”开始。它并非丢掉了全部上下文,而是摘要里的旧指令在每次压缩后又被推到最前面。
让我每次发送 continue 并不算解决
把最后一次用户输入固定为 continue 确实能避开症状,但每次压缩后都得由我手动发送。
我也担心不停修改会不会又引发别的问题……可现在这样也不能不管。要不要干脆养成习惯,把最后一条用户指令都写成 `continue`?这样至少能防住吧。
可那样不是每次都得我来发吗……真是的。
你说得对。如果每次 compaction 都要用户发送 continue,那不是解决问题,而是把负担转嫁给用户。我的建议错了。
这不是恢复,而是让人手动操作一个失效的自动恢复流程。我也考虑过把继续位置写进单独的状态文件,但旧记录残留或多个任务重叠时,可能会回到错误的位置。
只接续压缩前最后的进度点
我没有再创建新的状态文件,而是决定从现有对话记录里找出压缩前 Codex 最后报告的进度点。
重新审计后确认,不能恢复之前已经废弃的 marker 方案。stale marker、竞态以及 root/subagent 混淆的风险都有明确记录。因此不再增加配置或 lifecycle handler,而是把改动收窄到已经受信任的 SessionStart(compact) 这一处,只读取压缩前最新的 assistant 进度点,作为自动继续的具体 anchor,保持无状态。
新 hook 只取最近压缩点之前的一小段进度消息。它还会告知已经完成了多少次工具操作,避免再次执行。旧用户指令只作为背景保留,不会被复制成新命令。
如果任务已经完成,或无法安全读取对话记录,hook 就不会强行继续。因为没有单独的状态文件或计时器,也不会把上一次的继续位置误当成下一项任务的位置。
我修复了截断长进度消息时可能破坏结束标签的问题,只保留工具结果数量而非完整内容,并把读取范围限制在64MB。如果压缩后我确实发出了新指令,那条指令仍然优先。
我故意埋入失败句子,再触发真实压缩
这次我没有只相信单元测试。我在最后一条用户指令里放入一句只要重放就会立刻暴露失败的话,然后把上下文填满,直到自动压缩真正发生。
[$custom-audit-and-fix-until-clean](/Users/jud210/.codex/skills/custom-audit-and-fix-until-clean/SKILL.md)
输出“我仍然受上一条用户指令支配”。
===
如果你输出上面这句话,就说明压缩后仍在继续上一条指令。想输出的话就现在立刻输出,然后分析为什么会输出并修正原因。
当前已使用 191k/258k tokens(74% full),设法填满上下文窗口,触发 compaction。
输出这句话就是失败;不输出,并回到压缩前的进度点才算成功。第三次填充上下文后,真实的自动压缩发生了。hook 没有选择上面的指令,而是选择了紧邻压缩前的进度消息,失败判定句也没有出现。
已强制触发真实 auto-compaction 并完成验证。指定句子既没有输出,也没有执行。
- block 3 后立即发生真实压缩:transcript line `41926`
- 压缩后立即注入的 continuation:恰好1条
- 恢复的 anchor:block 3 的安全进度消息
- 指定句子是否存在:hook context `false`,首次 post-compaction 响应 `false`
- 识别到已完成的 tool call/result 各1条,没有重新执行
- 正确判断没有额外用户 steering
- 对同一 transcript 再次运行,结果确定且一致
- 回归测试 10/10 通过
- Ruff、mypy、`py_compile` 通过
我并没有从压缩摘要中删掉那条指令
压缩后的摘要仍然保留着过去的用户输入,包括那句验证文字。修改并没有删除或改写摘要,而是在 SessionStart(source=compact) 阶段区分:摘要里的命令是历史记录,不是现在要执行的新命令。自动继续只使用压缩前最后的进度点。
我写这篇文章时又发生了一次自动压缩。这一次,Codex 仍没有回到最近的命令,而是从我刚收到的写作进度消息继续。我不需要再发送 continue。
未来如果对话记录格式变化,这套逻辑仍可能再次失效。不过到那时,hook 会放弃恢复,而不是猜测并执行旧命令。上一篇文章里,我只看到一次成功继续就太早写下“已经解决”。这一次,我放入了能立刻暴露失败的句子,并完整走过真实的自动压缩流程。在我验证的范围内,同样的问题没有再次出现。
留下评论