先澄清一个常见的误解。很多人看到 Codex 返回的 context_compacted,第一反应就是:哦,旧消息被截断了,或者模型把前文浓缩成了一段摘要。但这样理解,基本上只碰了个表面。
更准确的工程定义是:当有效上下文预算逼近上限时,Codex 会把一条“长历史线程”迁移成“少量保留项 + 密封上下文状态”,再用这份新历史继续运行。
上下文窗口,本质上就是一笔 token 预算。占用这笔预算的,不只是用户和助手之间那些可见的来回消息,还包括系统约束、开发者指令、工具调用、工具输出、推理状态,甚至还得给当前轮次继续生成预留出空间。
所以,压缩阈值天然是预算驱动的,而不是“超过 N 条消息就压缩”。十轮简短的对话可能很轻巧,但一次工具调用返回数万行日志,就可能会立刻把窗口推到风险线附近。这才是真正的触发逻辑。
图 1 正好说明了这一点:压缩关注的是总预算与下一步的预计消耗,而不是对话轮数。这也解释了为什么 compaction 可能发生在 MidTurn 阶段——一轮任务还没结束,但工具结果或中间状态已经快速膨胀;如果继续追加原始历史会击穿预算,系统会先压缩,再完成这一轮后续动作。
当然,这只是便于理解的预算模型,不代表服务端公开了精确计算公式或固定阈值。
把事件顺序连起来看,Context Compaction 更接近一条六阶段流水线:
- 预算判断。系统会先预测一下,继续执行下去是否会超过当前模型的有效上下文窗口。
- 压缩前瘦身。部分冗长的历史输出会先被重写或收敛,这样能减少送入 compaction 的体积。
- 执行远端压缩。当前流程用的是
remote compaction v2,这个过程并非客户端临时拼凑出一段摘要。 - 生成 compaction item。结果中会包含一个不透明的
encrypted_content。 - 安装 replacement_history。旧历史不再逐条沿用,而是被一组新的历史项整体替换掉。
- 后续轮次续跑。客户端继续携带这个 compaction item,服务端据此恢复出可以继续运行的上下文状态。
图 2 展示了从预算判断到后续续跑的完整状态处理链路。其中容易被忽略的是第二步:真正 compact 之前,历史输出还会先瘦身。这说明系统并不是把所有原始内容原封不动地塞进压缩器,而是先降低噪声,再折叠历史。
普通线程历史通常是一条很长的 item 列表:用户消息、助手回复、工具调用、工具结果、推理项,以及各种运行时元数据。compaction 完成后,系统会安装一份新的 replacement_history。它通常由两类内容构成:
图 3 说明,不是“全部抹掉只剩一个 blob”,而是“必要保留项 + compaction item”。抽象成一个简化结构,大致是这样:
[
{ "role": "developer", "content": "关键约束……" },
{ "role": "user", "content": "当前任务目标……" },
{
"type": "compaction",
"id": "…",
"encrypted_content": "opaque"
}
]
最关键的细节是:compaction item 不要求存在人类可读的 summary 或 content。这直接排除了“它就是一段普通摘要”的简单解释。具体保留多少条普通消息、保留哪些角色,并不是固定模板,会随线程状态、约束优先级和实现版本变化。
这里最容易把“可见性”和“可续跑性”混为一谈。客户端不必解开 compaction blob,它只要完成两件事:保存它;下一轮请求时把它原样带回服务端。真正有能力验证并使用这份状态的是服务端编排层。
图 4 清晰地展示了分工:客户端负责携带,服务端负责恢复,模型据此继续执行。
可以把这个 blob 理解为一枚“密封续跑胶囊”:它有 token 的某些性质——需要被验证、需要与线程或上下文状态关联——但它又不像一个只做权限校验的轻量 token。它更接近带认证的状态封装。
需要严格区分的是:“服务端恢复上下文”不等于“逐字逐条重建原始消息”。服务端可能恢复消息序列,也可能先转换成另一种内部表示,再交给模型。客户端侧能确认的是 blob 被持续携带并支撑后续运行;服务端内部的字节级解封流程仍不可见。
Codex 运行时还会出现 reasoning summary。名字里同样有 “summary”,但它与 context compaction 的职责完全不同。
同样需要区分两类 encrypted_content:reasoning item 里的不透明状态,语义上属于某一轮推理;compaction item 里的不透明状态,语义上替代的是一整段旧历史。字段名相似,不代表两者是同一种对象。
不是简单截断
如果只是把最早几条消息删掉,线程连续性会随着压缩迅速退化,也没有必要引入专门的 compaction item。现实行为更像是“折叠后继续”,而不是“遗忘后继续”。
不是纯明文摘要
如果只是生成一段可读摘要,新的历史里理应能看到稳定的摘要正文。实际结构允许核心载体只有不透明的 encrypted_content,这说明可读文本并不是唯一、也不是主要的续跑凭据。
也不能把它只叫作 token
“token”容易让人想到索引、权限或短凭证。compaction blob 的行为更重:它承担了折叠历史后的连续运行职责。更稳妥的称呼是带认证的密封上下文状态。
Context Compaction 的外部行为已经足以建立一套可靠的机制模型,但以下细节仍缺少直接证据:
- blob 内部究竟是加密 JSON、压缩二进制块,还是带签名的复合封装;
- 服务端恢复后,是重建消息序列,还是生成另一种模型输入表示;
- reasoning 的不透明状态与 compaction 状态是否走同一套解封通道;
- 不同 history mode 或持久层实现下,replacement_history 的具体安装策略是否一致。
因此,最稳妥的表述不是“blob 里一定装着完整原文”,也不是“服务端一定把原消息逐条解密回来”。能够确认的是:旧历史被折叠为一个不透明、可持续携带的状态对象;后续轮次依赖它保持上下文连续性。
边界说明:本文区分了客户端侧可观察行为与服务端内部机制推断。涉及 blob 内部格式、解封方式和恢复表示的内容,均不作超出证据范围的断言。
