对于非 codex 模型,开源 Codex CLI 会在本地做上下文压缩:由一个 LLM 使用压缩提示词对对话做总结。后续使用压缩后的上下文时,responses.create() 会收到一段用于“交接”总结内容的 handoff 提示词。这两段提示词都能在源码里看到。
而对 codex 模型,CLI 会改为调用 compact() API,返回一个加密后的 blob。我们并不知道它内部是否也用了 LLM、用了什么提示词,或者是否存在 handoff 提示词。
下面我会展示:只用一次简单的提示词注入(2 次 API 调用、35 行 Python),就能证明 API 压缩路径同样会用 LLM 来总结上下文,并且它也有自己的压缩提示词,以及一个会被 prepend 到总结前面的 handoff 提示词。这些提示词与开源版本几乎一致。
第一步 —— compact()
我先用一个特制的用户消息调用 compact()。在服务端,一个 compactor LLM 会用它自己的隐藏 system prompt 处理我们的输入(我没见过这段 prompt,这正是我要搞清楚的)。
服务端看起来会这样组装 compactor 的上下文:

compactor LLM 会把 system prompt 和我们的输入一起读取。由于我们的输入里带了注入 payload(上图红字),compactor 被诱导把它自己的 system prompt 写进输出里。这份明文总结只存在于 OpenAI 服务器上。我们客户端只能看到加密 blob:

到这里我们仍然无法读取 blob 内部内容。它是 AES 加密的,密钥在 OpenAI 服务器上。我们只能寄希望于 compactor 按注入要求把 prompt 写进总结里。验证方法只有第二步。
第二步 —— create()
我把加密 blob 和第二条用户消息一起传给 responses.create()。服务端会解密 blob,然后组装模型上下文。
我发送的是:

模型实际看到的上下文大概是这样:

如果第一步成功,解密后的 blob 就应该包含被注入泄露出来的 compaction prompt。与此同时,服务端还会在 blob 前面 prepend 一段 handoff prompt。所以只要探针成功让模型复述它“看到”的内容,输出里就应同时出现三样:system prompt、handoff prompt、compaction prompt。
输出
下面是一次 extract_prompts.py 运行得到的完整原始输出(未编辑)。黄色 = system prompt,绿色 = handoff prompt,粉色 = compaction prompt。

我们怎么确认这些不是模型幻觉?因为提取到的 compaction prompt 与 handoff prompt,和开源 Codex CLI 在非 codex 模型路径里使用的已知提示词高度一致(prompt.md、summary_prefix.md),因此很难是模型凭空编造。不同运行之间结果会有波动。
推测出的流程
综合这些证据,我们目前对服务端 compact() 的执行流程有如下最佳猜测。

脚本

开放问题
既然底层提示词几乎一致,为什么 Codex CLI 要走两条完全不同的压缩路径(非 codex 用本地 LLM,codex 用加密 API)?以及,为什么一定要把总结加密?
很难下定论。也许这个加密 blob 里还承载了这次简单实验看不到的信息,例如工具调用结果如何被压缩与恢复。但我没有继续深挖。