阅读,与值得关注的内容Readance

Codex 的“记忆”大改?上下文管理架构拆解


架构师(JiaGouX)
我们都是架构师!
架构未来,你来不来?



8 月 30 日,Nico Ritschel 发了一条关于 Codex 上下文管理的帖子。他提到,Codex CLI 正在试验一套不只依赖上下文压缩(compaction)的方案:需要时切换到新的上下文窗口,再配合任务笔记(notes)和历史记录(history)回查旧内容。

随后,他在评论中补充了 new_context、notes 和 history 的相关 PR,以及一张 Harness 提示截图。Nous Research 的 Teknium 也拿 Hermes 的 compaction system 做了对照,提到 Hermes 最近加入了回看压缩前内容的能力。

我顺着这些线索,把官方配置、版本记录和源码放在一起看,想弄清楚一件事:上下文用完以后,一个长任务怎么继续?

截至今天,这套上下文管理(context management)在 Codex CLI 0.153.0 里仍是默认关闭的实验功能。它只对使用 Codex 后端的部分 ChatGPT Plus、Pro 和 Pro Lite 会话开放,API Key、自定义模型提供方、临时结构化线程暂时都不支持。

官方配置里还保留着 compaction 相关选项,0.150.1 的更新说明里也还有远程压缩(remote compaction)的修复。

目前能确认的是,Codex 正在试验另一套长任务续跑机制;至于它会不会取代 compaction,公开材料还不足以得出结论。

在我看来,这组改动表面上在处理“记忆”,底下动的却是状态管理。

从实现看,眼前要用的信息、跨窗口交接、旧记录回查,以及任务已经产生的外部事实,分别落在不同载体里。

从 Agent 架构的角度看,这比单纯讨论“上下文还能变长多少”更有意思。

一份摘要,承担了太多责任

先看一个常见任务:让 Coding Agent 迁移一套跨模块的认证中间件。

它先梳理调用链,确认旧接口暂时不能删除;排除统一升级 SDK 的路线后,主链路改完了;集成测试又卡在偶现的鉴权失败上。任务还没结束,上下文窗口却快满了。

传统 compaction 会把前面的对话、工具调用和结果压成一份更短的摘要,再带着摘要继续工作。这个办法很实用,也让不少长任务能够继续往下跑。

麻烦在于,摘要得提前猜:后面究竟还会用到什么?

“旧接口要保留”可能写进去了,背后的兼容原因未必还在;“集成测试失败”可能留下了,第一次失败时的完整日志可能没留下;某条路线已经试过,如果放弃原因被压掉,Agent 换个窗口后还可能重新走一遍。

摘要质量当然重要,但它还得同时承担三件事:

  • 缩短当前输入;
  • 保存任务进度;
  • 代替过去的原始记录。

三件事放在一起,很难都做到。压得越狠,恢复越快,细节损失也越多;保留得越细,窗口又很快被旧内容占满。

把这些改动连起来看,Codex 正在把这几件事拆开。

“记忆”里面,混着四类状态

讨论 Agent 时,对话、notes、history,甚至工作区里的文件,经常都被叫作“记忆”。这个叫法很方便,不过到了系统设计里,差别就出来了:谁写入、保存多久、能不能覆盖、出现冲突时以谁为准,各不相同。

拆开来看,大致能分出四类状态。

Coding Agent 的状态、动作与证据
Coding Agent 的状态、动作与证据

图 1:状态、动作和证据要分别对齐;这是帮助理解本文的架构示意,不是 Codex 官方架构图。

1. 当前工作集:这一刻需要看什么

当前 context window 是模型眼前的工作台:系统指令、用户要求、最近的对话、工具结果,以及当前步骤马上要用的信息。

Token 预算只回答资源问题:这是第几个窗口,还剩多少可用空间。它不保存任务进度,却能让模型知道什么时候该收束当前阶段,什么时候该为交接留出余量。

认证迁移进入测试修复后,当前步骤围绕失败用例、相关代码和兼容约束展开。此前看过的每一份文件如果都留在窗口里,会继续占用推理空间。

2. 交接状态:下一窗口从哪里接手

notes 保存的是跨窗口仍要使用的信息,例如:旧接口为什么不能删、哪些文件已经改完、哪条路线验证过但不可行、当前故障假设是什么、下一步从哪个入口继续。

源码里的提醒模板写得很具体:目标、关键决策、当前进展、已经确认的情况、下一步,都要尽量留下;仍在处理的用户请求和重要工具调用,还会带上对应的 window ID、item ID,方便新窗口回到原始记录。它不像一篇“前情提要”,更接近任务运行到某个位置时留下的检查点(checkpoint)。

换成线上值班的场景,接班人会先看交接本,不会把上一班所有群聊重听一遍;遇到某次告警的来龙去脉,再去翻原始记录;服务到底恢复没有,最后还是看监控和业务指标。

这个检查点由模型筛选、整理,仍然会损失信息。模型忘记写入一项约束,新窗口不会自动知道;任务状态变化后没有及时更新,旧笔记还可能反过来误导后续判断。

3. 会话历史:需要核对时回到原始记录

history 保存旧窗口里的原始条目。新窗口可以列出历史窗口及其条目、读取具体内容,也可以搜索过去的对话和工具结果。

比如 notes 只写了“统一升级 SDK 不可行”,后续需要确认原因,就能回到 history 找当时的用户要求、命令和报错,而不是对一份二手概括继续猜。

不过,“原始内容还在”和“需要时一定找得到”是两回事。当前源码里的搜索是区分大小写的字面子串匹配,不是语义检索。关键词没选对、同一件事换了种说法,都可能搜不到。

4. 外部权威事实:任务实际上做成了什么

另外还有一类状态不在模型上下文里:代码、Git、测试报告、CI、工单和业务系统中的真实状态。

new_context 换掉的是模型上下文,不会清空工作目录、回滚文件,也不会撤销已经发出的外部请求。notes 里写着“测试通过”,只能说明模型记录了这件事;测试是否真的通过,仍要看退出码和报告。模型记得“退款已提交”,也不能替代支付系统里的交易状态。

四类状态各自回答一个问题:

  • 当前工作集
    :眼前推理需要的材料;
  • notes
    :下一窗口快速接手所需的交接信息;
  • history
    :需要核对时可以回看的原始记录;
  • 外部系统
    :确认任务到底做成了什么。

这组实现没有给 Agent 凭空增加一段“永久记忆”,它做的是把不同生命周期、不同可信度的状态分开放置。

Codex 是怎么完成一次切窗的

把状态分开后,切窗时的几个动作也更容易看清:窗口快满时谁来决定,切换前写什么,切换后又怎样恢复?

把几组连续的 PR 串起来,能看到一套由模型和 Harness 共同完成的协议。

先让模型看见预算,再给它主动切窗的入口。

运行时把当前窗口身份和 Token 余量暴露给模型。它不必等到系统突然压缩,可以先判断手头这一步是否适合收尾,再决定什么时候整理交接。

模型可以调用 new_context,主动开启一个新的模型上下文。若它一直没有行动,运行时会在余量跨过阈值后提醒一次;基础预算耗尽时,再注入兜底提示,并留出一段缓冲,让模型最后写 notes、发起切窗。模型已经主动调用 new_context,这段兜底就会跳过;缓冲也用完了,运行时才自动切换。

两层判断各自处理不同问题。模型判断手头这一步是否适合收尾、哪些信息值得交接;Harness 盯住余量、提醒状态和最晚换窗时间。

切换完成后,新窗口先找回任务位置。

这里的“新”指的是换一套模型上下文,任务本身不会回到白纸状态。源码会丢掉旧窗口的对话历史,再根据当前运行时状态(world state)重建 Harness 仍需提供的上下文;工作目录里的代码、Git 状态和已经发生的外部动作不会跟着回滚。

每次构建完整的窗口上下文时,history-notes 扩展还会尝试从后端取回一段 thread_hint。只有请求成功、内容非空且不超过 4000 字节时,这段提示才会进入模型上下文;旧窗口原文不会因此整体回灌。需要更多细节时,模型再用 notes 和 history 工具查找。

4000 字节上限还透露出一个取舍。Codex 仓库自己的评审规则要求,模型上下文尽量增量构建,避免频繁变化带来缓存失效;所有注入项都要有硬上限,单项也不能超过 1 万 Token。从这组约束看,系统没有把旧内容换个地方重新塞满窗口,而是在预算内恢复:交接保持简短,历史按需读取,模型眼前的上下文始终有边界。

找到位置以后,再按需恢复细节。

回到前面的认证迁移任务,新窗口先从 notes 读取交接;遇到缺口或需要核对的细节,再去 history 搜索、读取原始条目。其余旧内容不会重新塞回当前窗口。

整条链路可以简化成:

看见预算余量 → 收束当前阶段 → 写交接 → 切到新窗口 → 重建运行时上下文 → 读取 notes → 必要时回查 history → 对照外部事实继续执行

上下文工程的运行时链路
上下文工程的运行时链路

图 2:从当前工作集到交接、回查和验收的运行链路;图中“压缩后仍可续接”对应旧机制,Codex 的实验开关提供了另一条切窗路径。

模型判断“这一阶段是否做完”“哪些决策值得交接”;Harness 守住资源上限,记录窗口编号,处理切换条件,并提供历史存储和恢复入口。

模型可以主动收尾,运行时仍保留硬边界和兜底。长时间运行的 Agent 因此不必把可靠性完全寄托在模型“记得主动整理”上。

架构师熟悉的问题:状态归谁

我们做架构设计时,经常会讨论服务边界、数据归属和故障恢复。Agent 的上下文管理其实是同一道题,只是状态的一部分落进了模型窗口。

如果把上面的认证迁移任务放进生产级 Harness,我会先看每类状态的所有权,而不是模型最多能记多少。一张很朴素的状态表,就能把模型和运行时各写什么、谁可以覆盖、旧值何时失效、发生冲突时以谁为准摊开。

比如,模型可以记录“当前失败假设”,真实测试结果却不会因此改变;notes 可以写“主链路已修改”,实际改动范围仍在 Git diff 里;history 能证明之前运行过某条命令,外部服务此刻是什么状态,还要回到服务本身确认。

如果状态所有权说不清,问题通常不会直接表现成“失忆”。更常见的情况是任务慢慢跑偏:旧约束继续生效、失败路线又试了一遍、外部动作重复执行,而系统仍以为自己在正常续跑。

平滑切换之外,还有异常恢复

主动收尾、写好 notes,再从新窗口继续,这是最顺利的路径。真实任务里还会遇到没有完成交接的时刻。

例如窗口突然超限、进程被取消、模型调用失败,或者外部请求已经发出但响应没有回来。几类故障的恢复方式并不相同。

模型上下文丢失,可以从 notes 和 history 重建;本地改动做到哪里,可以用 Git diff 和测试结果确认。外部动作结果未知时,更稳妥的顺序是先查询权威系统,再依据幂等键决定是否重试。交接笔记里没有结果,并不能证明上一次动作没有发生。

如果只覆盖“正常路径”,遇到这些情况就没有明确的恢复入口。主动切窗、自动超限、异常中断和外部结果未知,各自需要找到最后一个可信状态,再决定怎样继续,尽量少漏做、少重做。

工具结果未知时的恢复分支
工具结果未知时的恢复分支

图 3:上下文可以重建,外部副作用不能靠笔记猜测;结果未知时先查权威系统,再决定是否继续。

这和数据库故障恢复、工作流续跑的思路很接近:模型上下文可以重建,外部副作用仍要回到业务记录里确认。

短任务里,差别未必明显

单凭目前的公开材料,还不能判断新机制是否优于 compaction。

notes 加 history 的好处是,当前窗口可以更干净,关键细节也保留了回查入口;代价是系统多了一组新问题:交接会不会漏、搜索能不能命中、恢复会不会变慢、历史保存成本是否可控。

如果在团队里验证,我会选一批确实会经历多次切窗的任务,先小流量开启实验,同时保留原有 compaction 回退路径。除了 Token 消耗,我还会记录:

  • 多次切窗后,用户约束、当前进度和失败路线还剩多少;
  • Agent 发现信息不足时,是否会主动回查,字面搜索能否找到目标;
  • 从新窗口恢复到有效工作的时间有多长;
  • 新窗口重建输入后,缓存复用和首次响应延迟怎样变化;
  • 是否出现重复提交、重复调用或漏执行;
  • 为写 notes、搜索和读取 history,多付出了多少 Token 与延迟。

这些数据放在一起,才能看清取舍。只看上下文省了多少,恢复质量和副作用风险容易被漏掉;只看任务最终完成,中间反复试错的成本又看不见。

我会把验证重点放在多次切换以后:任务还能不能正确继续,恢复花了多少成本,出了问题能不能查清。

摘要、notes 和 history,各自做什么

compaction 和硬切窗口经常被看作两条互斥路线。放进实际链路里,它们承担的工作和读取成本并不相同。

放回同一条运行链路里,它们更像不同成本的读取层级。

摘要适合快速恢复全局,notes 适合保存明确的交接状态,原始 history 适合核对关键细节。只有摘要,遗漏的信息很难找回;只有原始记录,新窗口又可能花很多次检索才能拼出任务全貌。

Codex 当前实验采用了“短交接 + 原始历史”的组合,compaction 也仍然留在官方产品里。以后哪条路会成为主线,最终还得看真实任务数据;眼下仅凭一条帖子和几组 PR 还看不出来。

Teknium 提到 Hermes 也在加入 compaction recall。两个项目的具体实现不同,却都给压缩或交接后的内容留了回查原始记录的入口。

目前怎么开启

Codex CLI 0.153.0 的公开配置是:

在 ~/.codex/config.toml 中加入两行:

[features.context_management]experimental_mode = true

它默认关闭,并受前面提到的账号、后端和线程类型限制。开发阶段曾出现 [features] token_budget = true 和更早的细分开关,当前公开配置已经换成了上面的入口。

最近也能看到一种写法:“使用 GPT-6 Astra 就一定要开启”。这里容易把两个层次放在一起:GPT-6 Astra 是模型选择,experimental_mode 是 Codex CLI 的上下文管理开关。官方配置说明的是后者的实验范围,并没有把 Astra 列为前置条件,也没有承诺开启后一定更省 Token 或表现更好。

放在实际使用里,我会把它当作长任务的实验开关:在 ~/.codex/config.toml 写入配置,退出并重新启动 Codex 让配置重新加载,再拿几类会经历多次切窗的任务做对照。它会让 notes 和可搜索的 history 参与跨窗口恢复,减少把完整历史反复压进一份摘要的依赖;这不等于彻底取消 compaction,实际收益也要看任务是否真的需要多次切窗。

配置名、工具行为和数据格式都还有变化的可能。按目前的成熟度,我会先把它留在实验和验证环境,不会接进关键流程。

最后

最初看到“Codex 要摆脱 compaction”时,我以为重点是换一种压缩办法。把实现展开后,我更在意的是状态怎样被分开:临时工作集留在当前窗口,notes 保存交接,history 留着原始记录,代码和外部系统继续保存任务事实。

这套分工能不能比现有 compaction 少丢状态,又不把成本转移到检索、延迟和副作用风险上,还要等真实长任务的数据。至少到 0.153.0,公开材料还没有给出答案。


参考资料

  • OpenAI:Codex Configuration Reference
  • OpenAI:Codex Changelog(CLI 0.150.0、0.150.1、0.153.0)
  • OpenAI:Compaction(API Guide)
  • openai/codex PR #27438:Add token budget context feature
  • openai/codex PR #27488:Add new context window tool
  • openai/codex PR #33255:Add a fallback phase before automatic context rollover
  • openai/codex PR #39827:Add history and notes tools for token-budget sessions
  • openai/codex PR #40539:Inject history notes hints into context windows
  • openai/codex PR #41803:Allow models to enable token budgeting by default
  • openai/codex PR #42385:Add experimental context management activation
  • Nico Ritschel:Codex CLI context cutover 讨论
  • Teknium:Hermes compaction recall 讨论
  • Anthropic:Effective context engineering for AI agents
  • Anthropic:Effective harnesses for long-running agents

如喜欢本文,请点击右上角,把文章分享到朋友圈
如有想了解学习的技术点,请留言给若飞安排分享

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

·END·

相关阅读:


      版权申明:内容来源网络,仅供学习研究,版权归原创者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

      架构师

      我们都是架构师!


      图片

      关注架构师(JiaGouX),添加“星标”

      获取每天技术干货,一起成为牛逼架构师

      技术群请加若飞:1321113940 进架构师群

      投稿、合作、版权等邮箱:[email protected]

      前往微信阅读全文

      内容来自公众号,可前往微信查看原文。

      查看作者的更多文章 →