先给结论:

Codex 不是把整个 session 永远原样塞回模型。
它先控制单个工具输出体积,再在上下文接近阈值时压缩 active history。

本地压缩有明文 handoff prompt。
远端压缩没有 Codex 本地可见的明文压缩 prompt。

更完整地说,长任务能继续跑,靠的是这条链路:

工具输出限流
-> token 使用量达到阈值
-> 触发本地或远端 compaction
-> 压缩结果替换 active history
-> 下一次请求重新注入当前权限、环境、AGENTS.md、skills、plugins 等运行上下文

压缩解决的是当前会话的 active context 过大问题,不是长期记忆。长期记忆、AGENTS.md、skills、rollout 和 compaction 是不同层。

场景一:工具输出很长时,Codex 先做单条输出限流

用户说:

把失败测试修到通过。

模型可能运行测试,终端输出几万行。Codex 不会把这几万行完整放进模型下一轮上下文,而是先对工具输出做体积控制。

模型后续看到的通常是这种形态:

Total output lines: 999

EXEC-LINE-0001 ...
EXEC-LINE-0002 ...
…8941 tokens truncated…
EXEC-LINE-0998 ...
EXEC-LINE-0999 ...

这里有三个关键信息:

1. 开头保留:模型能看到命令最早输出了什么。
2. 结尾保留:模型能看到最终失败、错误尾部、最后状态。
3. 中间标记:模型知道这里发生了截断,不会误以为日志本来就这么短。

这一步不是 compaction。它发生在 compaction 之前,目标是防止单个工具结果先把上下文撑爆。

相关 Implementation Note / 工具输出截断策略

英文原文:

tool_output_token_limit
truncation_policy

中文对照:

工具输出 token 限制
截断策略

这两个配置/模型字段共同决定工具输出预算。tool_output_token_limit 可以覆盖模型 metadata 里的默认截断预算;truncation_policy 决定按 bytes 还是 approximate tokens 截断。

这段不是模型可见 prompt,而是运行时策略。模型并不会“决定要不要截断工具输出”;工具返回进入 active history 前,Codex 已经做了截断。

需要注意:这里的 token 是工程近似值,不是精确 tokenizer。Codex 用近似预算换取稳定、快速、足够保守的输出控制。

场景二:输出已经限流后,为什么还需要压缩

用户继续说:

继续。

即使每个工具输出都被截断,整个会话还是会增长:

用户输入
模型解释
工具调用
工具输出
代码 diff
测试结果
用户纠正
下一轮工具调用
...

所以 Codex 还需要第二层机制:当 active history 接近模型上下文窗口时,把旧历史替换成更短的压缩表示。

相关 Implementation Note / 自动压缩阈值

英文原文:

model_auto_compact_token_limit

中文对照:

模型自动压缩 token 阈值

这个值控制什么时候触发自动压缩。没有显式配置时,Codex 会根据模型 context window 推导默认阈值,通常按窗口的 90% 左右触发。

例如:

模型 context window: 400k
默认自动压缩阈值: 约 360k

压缩触发位置有三类:

pre-turn:
  新一轮采样前发现上下文已经太大,先压缩再发请求。

mid-turn:
  模型刚调用完工具,还需要继续 follow-up,但上下文已到阈值,于是同一轮中途压缩。

model-downshift:
  用户切到更小上下文窗口的模型,Codex 先按旧模型能力压缩,再交给新模型继续。

mid-turn 很重要。它解释了为什么长任务中工具循环还没结束时,Codex 也能先“收拢上下文”再继续做下一步。

场景三:本地压缩有明确 prompt,它要模型写交接摘要

当 provider 不支持远端 compaction 时,Codex 使用本地压缩。

本地压缩的行为是:

把当前 active history 加上一条合成用户消息
-> 让模型生成明文 summary
-> 给 summary 加固定前缀
-> 用“最近用户消息 + summary”替换 active history

这里最关键的是这段运行时提示词。

相关 Runtime Prompt / 本地压缩提示词

英文原文:

You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.

Include:
- Current progress and key decisions made
- Important context, constraints, or user preferences
- What remains to be done (clear next steps)
- Any critical data, examples, or references needed to continue

Be concise, structured, and focused on helping the next LLM seamlessly continue the work.

中文对照:

你正在执行一次 CONTEXT CHECKPOINT COMPACTION。为另一个将接手继续任务的 LLM 创建交接摘要。

需要包含:
- 当前进展和已经做出的关键决策
- 重要上下文、约束或用户偏好
- 还需要完成什么,给出清晰下一步
- 继续任务所需的关键数据、示例或引用

保持简洁、结构化,并聚焦于帮助下一个 LLM 无缝继续工作。

这段 prompt 的重点不是“总结聊天记录”,而是“写给接手模型的 handoff summary”。

它要求保留的不是全部细节,而是继续任务最关键的信息:

当前进展
已经做出的技术决策
用户约束和偏好
剩余任务
关键文件、错误、命令、测试结果、例子

所以本地压缩效果好的原因之一确实是 prompt 写得很明确。它把模型的目标从“压缩历史”改成了“帮助下一位执行者继续工作”。

场景四:本地 summary 为什么看起来像“另一个模型留下的交接”

本地 summary 生成后,Codex 会在前面加一段固定前缀。

相关 Runtime Prompt / 本地压缩摘要前缀

英文原文:

Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:

中文对照:

另一个语言模型已经开始解决这个问题,并生成了其思考过程摘要。你也可以访问该模型使用过的工具状态。使用这份摘要接续已有工作,避免重复劳动。下面是另一个模型生成的摘要,请用其中信息辅助你的分析:

这段前缀的作用是给后续模型一个解释框架:

这不是普通用户闲聊。
这不是新任务。
这是接手任务时必须使用的交接状态。

本地压缩后,active history 大致变成:

最近一段真实用户消息
带 SUMMARY_PREFIX 的压缩摘要

最近用户消息会保留一段预算,当前常量约是:

20,000 tokens

这解释了为什么 Codex 通常不会忘掉最近用户刚刚纠正过什么:最近用户消息不完全依赖 summary,而是会尽量原样保留一段。

场景五:远端压缩没有 Codex 本地可见的压缩提示词

这是最容易误解的一点。

用户问:

远端压缩是不是也用了那段 handoff prompt?

答案是:

不是。

更精确地说:

远端压缩没有使用 Codex 本地的 SUMMARIZATION_PROMPT。
Codex 仓库里也没有一段对应远端 compaction 的明文自然语言压缩 prompt。

本地压缩和远端压缩的差异是:

本地压缩:
  Codex 显式追加 handoff prompt。
  模型返回明文 summary。
  Codex 把 summary 加前缀后写回 active history。

远端压缩:
  Codex 不追加本地 handoff prompt。
  Codex 调用 provider 的原生 compaction 能力。
  provider 返回 compacted transcript 或 encrypted compaction item。

远端 v1:调用 /responses/compact

远端 v1 使用专门的 compact endpoint:

/responses/compact

请求里带的是:

模型
当前输入历史
当前 instructions
当前 tools
reasoning / service tier 等请求设置

它没有把下面这段本地 prompt 追加进去:

You are performing a CONTEXT CHECKPOINT COMPACTION...

所以远端 v1 的压缩语义来自 provider 对 /responses/compact 的服务端实现,而不是 Codex 本地明文 prompt。

相关 Implementation Note / 远端 v1

英文原文:

/responses/compact is unary and returns compacted ResponseItems.

中文对照:

/responses/compact 是一次性请求,返回压缩后的 ResponseItem 列表。

这段是实现语义,不是模型可见提示词。

远端 v2:追加 CompactionTrigger

远端 v2 不调用 /responses/compact。它在普通 Responses 输入末尾追加一个协议项:

ResponseItem::CompactionTrigger

这也不是自然语言 prompt,而是协议级触发信号。

服务端返回的不是普通明文 summary,而是 compaction 输出项,当前形态可以是:

ResponseItem::Compaction { encrypted_content }

因此远端 v2 的模型请求形态更像:

历史消息
工具 schema
当前 instructions
CompactionTrigger

而不是:

历史消息
工具 schema
当前 instructions
"Please summarize the conversation..."

这也是为什么在远端 compaction 的历史里经常看到:

compaction:encrypted=true

而不是一段可读的 handoff summary。

场景六:OpenAI 模型是否支持远端压缩

Codex 的判断粒度是 provider,不是逐个模型在本地探测。

当前逻辑可以理解为:

OpenAI provider:
  支持远端 compaction。

Azure Responses provider:
  支持远端 compaction。

其他 provider:
  默认不支持远端 compaction,走本地压缩。

所以更准确的说法是:

当 Codex 使用 OpenAI / Azure Responses provider 时,会优先使用远端 compaction 路径。
远端路径是否具体怎么压缩、是否用隐藏服务端指令,不在 Codex 本地源码中暴露。

这也意味着:

你能在 Codex 仓库里完整看到本地压缩 prompt。
你看不到远端压缩的完整 prompt,因为本地并没有这段 prompt。

如果服务端内部有额外指令,那是 provider 内部实现,不是 Codex 本地可审计的 prompt。

场景七:压缩后为什么权限、AGENTS.md、skills 不会靠 summary 记忆

用户继续说:

继续改,不要忘了 AGENTS.md 的要求。

这里要区分两类信息:

任务状态:
  当前修到哪里、哪些测试失败、下一步做什么。

运行规则:
  system/developer 指令、权限、AGENTS.md、skills、plugins、apps、MCP tools、环境上下文。

压缩 summary 主要承载任务状态。运行规则不是靠 summary 背下来,而是下一次请求前由 Codex 重新注入。

也就是说,压缩后模型看到的不是:

summary 里记住了所有权限和 AGENTS.md

而是:

当前运行规则被重新构造并放回 prompt
summary / compaction item 只负责接续任务状态

这就是为什么压缩不会天然破坏权限系统、skills 选择、AGENTS.md 约束。它们不应该依赖压缩摘要保存。

场景八:压缩前的旧消息是不是没了

用户问:

压缩后之前的 session 是不是没了?是不是 message 列表被替换?

答案要分两层:

active history:
  会被 replacement history 替换。
  下一次模型请求看的是压缩后的上下文,不是压缩前完整 message list。

rollout:
  仍然保存线程事件、工具调用、响应项、compaction checkpoint。
  resume / fork / debug 时会用这些记录重建可继续的 active history。

所以:

对模型上下文来说:旧 message list 不再完整进入请求。
对本地会话记录来说:rollout 仍保留历史事件和 checkpoint。

压缩 checkpoint 的核心是:

message:
  本地压缩时通常是明文 handoff summary。
  远端压缩时可以为空,因为关键信息在 compacted response items / encrypted item 里。

replacement_history:
  压缩后真正用于恢复 active history 的消息列表。

resume 时 Codex 不需要从最早一条消息开始重放给模型。它可以从最近 checkpoint 的 replacement history 起步,再接上 checkpoint 之后的新事件。

场景九:为什么压缩仍然可能丢细节

Codex 会提醒长线程和多次压缩会降低准确性。这个提醒是合理的。

压缩不是无损归档。可能损失的地方包括:

1. 工具输出限流时,中间日志已经被截断。
2. 本地 summary 没写进去的旧细节,后续模型就很难恢复。
3. 远端 encrypted compaction item 用户不可读,人工调试不如明文 summary 直观。
4. 多次压缩会形成“摘要的摘要”,细节密度逐步下降。
5. 如果任务跨度很大,一个 summary 很难同时保留所有分支上下文。

因此“Codex 不丢记忆”的准确说法应该是:

Codex 尽量保留继续当前任务所需的信息。
它不保证把整个 session 的每个 token 无损保留在模型上下文中。

场景十:什么时候该相信压缩,什么时候该开新会话

适合继续压缩的任务:

同一个 bug 还没修完。
同一个 PR 还在跑测试。
用户目标稳定,文件范围稳定。
最近上下文比早期闲聊更重要。

更适合开新会话的任务:

任务目标已经换了。
旧线程经历过多次压缩。
需要审计很早以前的完整细节。
远端 encrypted compaction 让你无法确认压缩内容。
上下文里混入了多个互不相关的大任务。

Codex 的上下文压缩是续航机制,不是无限记忆机制。它最擅长让一个连续工程任务跨过 context window 限制继续推进。

最终链路

把所有场景合起来,Codex 的上下文管理可以概括为:

1. 工具输出先按预算截断,保留头尾和 truncated marker。
2. active history 持续增长,但不会无限增长。
3. token 使用量达到阈值时触发 compaction。
4. 本地路径使用明文 handoff prompt。
5. 远端路径没有 Codex 本地可见的明文压缩 prompt。
6. OpenAI / Azure Responses provider 优先使用远端 compaction。
7. 压缩结果替换 active history。
8. 下一轮重新注入当前运行规则。
9. rollout 保存事件和 checkpoint,用于 resume / fork / debug。

所以这套机制的核心不是某一个“记忆魔法”,而是:

先限流,再压缩,再重注入,再用 checkpoint 恢复。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐