在 AI Agent 系统的工程实践中,agent loop 是连接用户意图、模型推理与工具执行的核心控制骨架。OpenAI 近期发布的《Unrolling the Codex agent loop》技术文章,首次系统性地公开了 Codex CLI 的底层实现细节,其设计思路对于构建高可靠、低成本的自主代理系统具有重要参考价值。本文将从控制流、上下文管理与性能优化三个维度展开分析,并提炼可操作的工程参数。
Agent Loop 的核心控制流
Codex CLI 的 agent loop 本质上是一个状态驱动的迭代闭环,其执行路径可概括为四个关键阶段:输入构建、模型推理、响应解析与工具调用。每个阶段的设计都直接影响系统的响应质量与资源消耗。
在输入构建阶段,Codex 将用户指令与系统配置组装为符合 OpenAI Responses API 规范的 JSON payload。值得注意的是,输入项被赋予不同的角色优先级:system > developer > user > assistant。system 消息由 Responses API 服务器注入,开发者消息包含沙箱配置与环境说明,用户消息承载具体指令,而 assistant 消息则记录模型的历史输出。这种分层机制确保了关键指令在 token 序列中获得更高的注意力权重,同时也为缓存优化提供了结构化基础。
模型推理阶段通过 HTTP POST 请求触发 Responses API,返回值为 Server-Sent Events(SSE)流。SSE 事件类型涵盖 response.output_text.delta(支持 UI 流式输出)与 response.output_item.added(生成后续请求的输入项)。Codex 在内部将原始 SSE 事件转换为结构化的内部事件对象,这一转换过程对前端展示与后端逻辑实现了职责分离。当模型输出 type=function_call 时,agent 执行对应工具并将结果追加至输入序列;当输出 type=assistant 且包含直接回复时,本轮对话结束,控制权交还用户。
从时序视角观察,单轮对话(turn)可能包含多轮推理 - 工具调用的迭代。Codex 在每次迭代中严格保持 "旧提示作为新提示的前缀",这一设计是后续 prompt caching 生效的关键前提。
上下文累积与性能权衡
随着对话轮次增加,输入序列的 token 数量呈现二次方增长趋势。每次新的用户消息不仅携带当前指令,还需携带完整的历史对话记录、系统配置与工具定义。这种设计确保模型具备完整的上下文感知能力,但同时也带来了严峻的资源压力。
Responses API 虽支持 previous_response_id 参数以实现有状态请求复用,但 Codex 出于两个工程考量选择弃用。其一是保持请求的无状态性,简化服务端实现与错误恢复逻辑;其二是兼容 Zero Data Retention(ZDR)配置 —— 在 ZDR 模式下,服务端不持久化用户数据,而 previous_response_id 的正确运作依赖服务端存储历史状态。因此,Codex 采用全量上下文传输策略,将性能优化的重心转移至 prompt caching 与上下文压缩两个方向。
Prompt caching 是缓解二次增长成本的核心机制。Responses API 的缓存策略要求 "精确前缀匹配":只有当新的 prompt 与历史请求的起始部分完全一致时,缓存方可命中。Codex 的 "旧提示作为新提示前缀" 的设计正是为此服务。当缓存命中时,模型采样成本从 O (n) 降至 O (1)(相对),采样计算量与上下文长度解耦。然而,以下三类操作将触发缓存失效:工具列表变更(如动态注册 MCP 工具)、模型切换(影响第三位 prompt 项的模型指令)以及沙箱配置或工作目录变化。
为应对不可避免的上下文膨胀,Codex 集成了 /responses/compact 端点进行自动上下文压缩。当 auto_compact_limit 阈值被触发时,系统将完整对话压缩为代表性摘要,同时保留 type=compaction 的加密内容项以维持模型对原始对话的潜在理解。这一机制在释放上下文空间与保持对话连贯性之间取得了平衡。
工程实践:缓存保护与动态工具处理
基于 Codex 的设计经验,我们可以提炼出若干可落地的工程实践建议。首先,在系统配置层面,应尽可能在会话初期完成工具注册与模型选定,避免运行时的动态变更。Codex 自身曾因 MCP 工具枚举顺序不一致而引入缓存失效 bug,最终通过确保工具列表的确定性排序予以修复。
其次,对于必须支持动态工具的场景(如 MCP 服务器通过 notifications/tools/list_changed 实时更新工具集),应评估变更频率与缓存失效成本的权衡。若工具集高频变化,可考虑为每个工具集快照建立独立会话,而非在单一会话中容忍反复的缓存失效。
再次,配置变更(如工作目录迁移、权限模式切换)应采用 "追加而非修改" 策略。Codex 通过插入新的 role=developer 或 role=user 消息来反映变更,而非篡改历史消息内容,从而保护前缀结构的完整性。这一设计模式适用于任何需要动态更新上下文但又不想破坏缓存的场景。
最后,上下文压缩阈值的设定需结合具体业务场景调优。阈值过低会导致频繁压缩,模型可能因信息丢失而丧失对早期上下文的理解;阈值过高则可能浪费缓存空间并增加首次采样的成本。Codex 的 auto_compact_limit 默认值未在公开文档中披露,开发者应根据目标模型的上下文窗口大小(如 GPT-4o 支持 128K tokens)、平均对话轮次与工具调用密度进行基准测试后确定。
小结
Codex CLI 的 agent loop 设计揭示了 AI Agent 系统在控制流、上下文管理与性能优化之间的复杂权衡。通过 "旧提示作为新提示前缀" 的缓存友好设计、基于 /responses/compact 的自动上下文压缩,以及配置变更时的追加式消息策略,Codex 在保持会话连贯性的同时有效控制了推理成本。这些工程实践对于构建生产级 Agent 系统具有直接的借鉴意义 —— 在追求模型能力上限的同时,不应忽视工程实现中的细节打磨。
参考资料
- OpenAI, "Unrolling the Codex agent loop", https://openai.com/index/unrolling-the-codex-agent-loop