Codex 基于模型驱动的上下文管理策略

大模型的上下文窗口再大,也有用完的时候。对 Coding Agent 来说,这个问题更明显:一次任务可能连续读取几十个文件、运行多轮测试、修改代码,再根据结果继续排查。只要任务足够长,前面的消息迟早要退出当前上下文。

常见做法是由客户端监控 token,用到一定比例后调用一次"摘要",再拿摘要替换旧历史。这套方案能工作,但客户端需要决定什么时候压缩、压缩哪些内容、摘要以什么格式组织。更麻烦的是,摘要一旦漏掉某个约束,后面的模型很难知道自己漏了东西。

Codex 的新方案换了一种分工:运行时继续管理 token 预算、持久化和窗口切换;模型自己判断哪些信息值得保留,并把它们写成 checkpoint。旧历史不会硬塞进新窗口,需要细节时再按地址查回原始记录。

本文讨论的是当前源码中按模型配置开启的实验性上下文能力。没有启用这组能力的模型,仍然使用传统 compaction。

这套机制可以概括成三个部分:

  • notes 保存继续工作所需的状态;
  • window_id + item_id 指向旧窗口里的原始记录;
  • history 根据这些地址或关键词取回细节。

它是一次有索引的任务交接,而不是把整段聊天压缩成一篇摘要。

一次上下文切换如何发生

完整流程如下:

1. 运行时计算剩余预算

每次模型响应都会带回 usage。Codex Core 根据这些实际用量维护当前窗口的 token 消耗,并结合模型配置中的窗口大小,计算还剩多少空间。

这里的运行时只做计数,不替模型判断内容价值。接近阈值后,它会给模型加入一条内部提醒,告诉模型当前窗口即将耗尽,需要先保存状态再切换。

2. 模型写 checkpoint

模型收到提醒后,会把仍然影响后续工作的内容写进持久 notes。典型内容包括:

  • 当前任务目标;
  • 用户明确提出的约束;
  • 已经做出的设计决定及原因;
  • 已完成和未完成的工作;
  • 排查中确认的关键事实;
  • 下一步应该从哪里继续;
  • 仍需引用的旧消息地址

这份 notes 不是完整聊天记录,也不需要复述所有工具输出。它更像工程任务的交接单:新窗口读完后,应该能立刻继续工作。

比如:

markdown 复制代码
## 当前目标
修复登录请求偶发失败,不能改变现有对外状态码。

## 已确认
- 问题发生在数据库超时后的重试分支。
- 用户明确要求保留原状态码。
- 已定位实现文件,但尚未修改。

## 下一步
1. 调整重试条件。
2. 增加超时后重试成功和最终失败两类测试。
3. 运行登录模块定向测试。

## 原始依据
- 用户最初需求:window_1 / usr_73c2
- 用户关于状态码的纠正:window_1 / usr_d829
- 定位调用链的工具结果:window_1 / tool_c004

最后几行很重要。notes 保存的是压缩后的工作状态,window_id + item_id 保存的是原始证据位置。两者分开后,模型不必为了保留一条可能有用的长日志,把整份日志复制进 checkpoint。

3. 开启新窗口

保存完成后,模型调用 new_context。运行时创建新的上下文窗口,并记录它与前一个窗口的关系。

新窗口不会自动带上旧窗口的完整消息。这是切窗真正节省 token 的地方。它只获得恢复工作所需的入口,例如当前窗口 ID、前一个窗口 ID、notes 的使用提示,以及 history 查询能力。

4. 按需恢复原始信息

新窗口先读取 notes。如果 checkpoint 已经足够,它可以直接继续修改代码。发现细节不足时,再通过 history 回查旧窗口。

已知准确地址时,直接调用:

scss 复制代码
read_item(window_id, item_id)

不知道 item ID 时,可以先使用:

scss 复制代码
list_items(window_id, role, ...)
search_contents(window_id, query, role, ...)

例如,notes 只写了"用户要求不要改变状态码",模型需要确认原话,就能根据记录的用户消息 ID 精确读取,而不是把整个旧窗口重新装进上下文。

item ID 是怎么用的

Codex 会为会话记录保存结构化 item ID。启用这套上下文机制后,用户消息、developer 消息、工具结果等非 assistant 内容,会在模型可见正文后显示一个短 ID:

bash 复制代码
不要改变对外状态码,只修复重试逻辑。
[id: usr_d829]

模型在旧窗口里就能看见这个地址,并在写 notes 时把它和窗口 ID 一起保存。新窗口用二者可以精确读取原始记录。

assistant 消息也有结构化 ID,只是不在正文后显示这类尾标记。需要找回某段 assistant 输出时,新窗口可以用 search_contents,并将 role 限定为 assistant;拿到匹配结果的 ID 后,再调用 read_item

所以,尾部没有显示 [id: ...] 不代表记录不存在。区别只在于:非 assistant item 方便模型当场抄下地址;assistant item 通常需要通过搜索重新定位。

模型负责什么,客户端还负责什么

这套方案把上下文管理很大的自由度交给了模型,但客户端 harness 仍然做了很多保障工作。

模型负责语义判断:

  • 哪些约束仍然有效;
  • 哪些进度值得带到下一个窗口;
  • 哪些原始记录以后可能需要复查;
  • checkpoint 应该如何组织;
  • 什么时候已经准备好切换窗口。

客户端和服务端负责工程保障:

  • 统计 token 用量和剩余预算;
  • 在合适的阈值提醒模型;
  • 提供 notes、history 和 new_context 工具;
  • 持久化旧窗口、checkpoint 和窗口关系;
  • 创建新窗口并安装新的工作上下文;
  • 模型没有及时交接时执行强制兜底。

模型忘记保存怎么办

自动管理不能只依赖模型自觉。模型可能连续调用工具,也可能在剩余 token 很少时仍试图继续回答。

因此 Codex 还保留了硬兜底。当窗口达到强制阈值后,运行时会要求模型停止当前任务,只允许它完成一次 notes 写入,然后调用 new_context

仍然存在的边界

这套机制没有消除信息丢失,只是让丢失后更容易恢复。

模型仍可能误判某条信息的重要性,没有把它写进 notes。虽然可以通过 history 搜索补找,但前提是新窗口意识到自己缺了信息。如果它把不完整的 checkpoint 当成全部事实,还是可能走偏。

history 查询也有成本。关键词不准确、旧窗口很多,或者需要反复读取长工具结果时,恢复过程会增加模型调用和 token 消耗。因此 checkpoint 不能过度精简。它至少要留下足够的名词、文件、决定和地址,让后续检索有明确入口。

另外,旧窗口的持久化记录仍然是基础设施的一部分。notes 只是索引和工作状态;如果底层历史已经过期、不可访问,item ID 本身没有意义。

总结

整个过程可以压缩成一句话:

notes 保存可继续工作的状态,window_id + item_id 保存原始证据地址,history 负责按需取回;模型决定保留什么,运行时保证这套交接能够完成。

它比一次性摘要多了一层索引,也多了一条恢复路径。对短对话来说,这套机制没有明显价值;对会连续运行几十轮、跨越多个上下文窗口的 Coding Agent 来说,它把"上下文压缩"从一次不可逆的文本改写,变成了带 checkpoint 和原始记录索引的任务续接。

相关推荐
问商十三载1 小时前
从RAG到信源打分:拆解大模型引用品牌信息的底层机制
人工智能
用户721746588261 小时前
7 档模型审同一份带 bug 的代码:一次 PR 的总账从 ¥0.0007 到 ¥0.4048,附单变量 harness 与 5 个真坑
人工智能
liukuang1101 小时前
WorkBuddy、千问办公、TRAE Work、百度搭子:四大AI办公硬碰硬
人工智能
大模型真好玩1 小时前
仅需3轮对话,Seed-Evolving大模型帮我创造出 “知识跳动”——一个智能化时代的知识学习系统!
人工智能·agent·豆包marscode
IvorySQL1 小时前
AI 时代,PostgreSQL 正在发生什么变化?
数据库·人工智能·postgresql
学习日记5251 小时前
AI PPT生成系统实践:从自由生成到可控生成的工程演进复盘
人工智能·ai·prompt
用户3705743608391 小时前
Claude Agent SDK 和 LangGraph 都用过之后,我发现选型先问一个问题
人工智能
资讯综合1 小时前
2026 高精度 AI 3D 模型生成工具实测对比:Hyper3D 、Tripo、Meshy 谁更适合生产级管线?
人工智能