对于非 codex 模型,开源的 Codex CLI 会在本地压缩上下文:一个 LLM 使用压缩提示词来总结对话。当压缩后的上下文稍后被使用时,responses.create() 会接收它,并附带一个交接提示词来框定这个总结。这两个提示词在源代码中都是可见的。
对于 codex 模型,CLI 转而调用 compact() API,该 API 会返回一个加密的数据块。我们不知道它内部是否使用了 LLM、使用了什么提示词,或者是否完全没有交接提示词。
下面,我将展示一个简单的提示词注入(2 次 API 调用,35 行 Python 代码)如何揭示:API 压缩路径确实使用了一个 LLM 来总结上下文,它有自己的压缩提示词,并且有一个交接提示词被前置到总结之前。这些提示词与开源版本几乎相同。
第一步 — compact()
我使用一条精心构造的用户消息调用了 compact()。在服务器端,一个压缩器 LLM 使用其自身隐藏的系统提示词(我从未见过,并且想要弄清楚)来处理我们的输入。
服务器似乎是这样组装压缩器的上下文的:

压缩器 LLM 会同时读取其系统提示词和我们的输入。因为我们的输入包含一个注入载荷(上方的红色文本),压缩器被欺骗,将其自身的系统提示词包含在了输出中。这个纯文本总结只存在于 OpenAI 的服务器上。我们只能看到加密的数据块:

此时我们无法读取数据块内部的内容。 它经过了 AES 加密,密钥保存在 OpenAI 的服务器上。我们只能希望压缩器遵循了注入指令,并将其提示词写入了总结中。找出答案的唯一方法是第二步。
第二步 — create()
我将加密的数据块和第二条用户消息传递给 responses.create()。服务器解密数据块并组装模型的上下文。
我发送:

模型似乎看到了类似这样的内容:

如果第一步成功,解密后的数据块应该包含压缩提示词(通过我们的注入泄露出来)。服务器还会在数据块前面添加一个交接提示词。因此,如果我们的探测成功让模型重复它看到的内容,那么输出应该会揭示所有三个部分:系统提示词、交接提示词和压缩提示词。
输出
以下是运行 extract_prompts.py 一次得到的完整、未经编辑的输出。黄色 = 系统提示词,绿色 = 交接提示词,粉色 = 压缩提示词。

我们如何知道这些是真实的提示词,而不是模型凭空捏造的?提取出的压缩提示词和交接提示词与开源 Codex CLI 中用于非 codex 模型的已知提示词(prompt.md,summary_prefix.md)高度吻合,这使得模型从头编造它们的可能性很低。不同运行的结果会有所变化。
推测的流程
综合以上信息,根据提取结果所揭示的内容,以下是我们对 compact() 在服务器端所做操作的最佳推测。

脚本

未解之谜
为什么 Codex CLI 使用两种完全不同的压缩路径(非 codex 模型使用本地 LLM,codex 模型使用加密 API),而底层的提示词却几乎相同?又为什么要对总结进行加密?
很难说。也许加密的数据块携带了比这个简单实验所能揭示的更多信息,例如,关于工具结果如何被压缩和恢复的某些特定细节。但我没有进一步测试。





