追查 Codex 的上下文压缩机制
这篇文章用一次很小的实验,把 Codex 的 compact() API 从“黑箱猜测”推进到了“可被证据约束的逆向观察”。核心结论作者发现,Codex 模型走的 compact() 路径大概率也会调用 LLM 对上下文做摘要。这条路径并不只是返回不可解释的加密产物,而是会先生成明文摘要,再把结果封装进加密 blob。…
转载说明:本文基于原文进行完整翻译转载。原文标题《Investigating how Codex context compaction works》,作者 Kangwook Lee,发布于 2026-03-04。来源:https://x.com/Kangwook_Lee/article/2028955292025962534。追查 Codex 的上下文压缩机制 对于非 codex 模型,开源 Codex CLI 会在本地进行上下文压缩:由 LLM 使用 compaction prompt 对整段对话做摘要。之后再使用这段压缩后的上下文时,responses.create() 会收到一个用于框定该摘要的 handoff prompt。这两个提示词都能在源码里直接看到。 而对于 codex 模型,CLI 改为调用 compact() API,返回的是一个 加密 blob。我们并不知道它内部是否也使用 LLM、具体用了什么提示词,或者是否同样存在 handoff prompt。 下面我会展示,怎样用一次简单的提示注入实验(2 次 API 调用、35 行 Python)证明:API 这条压缩路径确实也会用 LLM 来总结上下文,而且它也有自己的 compaction prompt,并且会在摘要前面再加上一层 handoff prompt。这些提示词与开源版本几乎一模一样。第一步:compact() 我先用一条精心构造的用户消息调用 compact()。在服务端,一个 压缩器 LLM 会结合它自己的隐藏系统提示词来处理我们的输入,而我此前从未见过这段提示词,也正想把它挖出来。 服务端看起来会像下面这样拼装这个压缩器的上下文: 压缩器 LLM 会把它的系统提示词和我们的输入一起读进去。由于我们的输入里包含了一段注入载荷(上图红字部分),压缩器就会被诱导,把它自己的系统提示词一并写进输出里。这个明文摘要只存在于 OpenAI 的服务器端,而我们在客户端能看到的只有加密后的 blob: 到这一步,我们还完全没法读出 blob 里面的内容。 它是用 AES 加密的,密钥也只保存在 OpenAI 的服务器上。我们现在只能 寄希望于 压缩器真的遵从了这次注入,把它的提示词写进了摘要里。要验证这一点,只能进入第二步。第二步:create() 接着我把这个加密 blob 和第二条用户消息一起传给 responses.create()。服务端会先解密 blob,再组装模型真正看到的上下文。 我发送的是: 模型看到的内容大概像这样: 如果第一步成功了,那么解密后的 blob 里就应该包含那段被注入“泄露”出来的 compaction prompt。与此同时,服务端还会在 blob 前面再 prepend 一段 handoff prompt。于是,只要我们的探针真的诱导模型把它看到的内容复述出来,最终输出里就应该同时暴露这三样东西:系统提示词、handoff prompt,以及 compaction prompt。输出 下面这张图展示的是一次 extract_prompts.py 运行得到的 完整、未经编辑的输出。黄色代表系统提示词,绿色代表 handoff prompt,粉色代表 compaction prompt。 我们怎么知道这些真的是提示词,而不是模型随手幻觉出来的文本?因为提取出来的 compaction prompt 和 handoff prompt,与开源 Codex CLI 中非 codex 模型所使用的已知提示词(prompt.md、summary_prefix.md)高度相似,这让“模型凭空编造出它们”的可能性大大降低。当然,不同运行之间的结果还是会波动。推测中的处理流水线 把这些线索合在一起,我们就能对服务端的 compact() 到底做了什么,给出一个目前最合理的猜测。 脚本 开放问题 既然底层使用的提示词几乎一样,为什么 Codex CLI 会给非 codex 模型和 codex 模型分别走两条完全不同的压缩路径:前者是本地 LLM,后者却是加密后的 API 流程?而且,它为什么非要把这个摘要加密? 很难说。也许这个加密 blob 里承载的不止是这次小实验能看到的东西,比如还包含了某些与工具结果如何压缩、如何恢复有关的额外信息。不过我没有继续往下测试。
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行