📢 转载信息
原文链接:https://openai.com/index/unlocking-the-codex-harness
原文作者:Celia Chen, Member of the Technical Staff
OpenAI 的编程代理 Codex 存在于许多不同的界面中:网页应用(在新窗口中打开)、CLI(在新窗口中打开)、IDE 扩展(在新窗口中打开),以及新的 Codex macOS 应用。在底层,它们都由同一个 Codex 架构(harness)驱动——即所有 Codex 体验的底层代理循环和逻辑。它们之间的关键链接是什么?答案是 Codex 应用服务器 (Codex App Server),这是一个对客户端友好、双向的 JSON-RPC1 API。
在本文中,我们将介绍 Codex 应用服务器;分享我们迄今为止在如何将 Codex 的能力集成到您的产品中以帮助用户提升工作流程方面的经验。我们将介绍应用服务器的架构和协议,以及它如何与不同的 Codex 界面集成,并提供利用 Codex 的技巧,无论您是想将 Codex 变成代码审查员、SRE 代理还是编程助手。
应用服务器的起源
在深入探讨架构之前,了解应用服务器的背景很有帮助。最初,应用服务器是一种实用的方法,用于跨产品重用 Codex 架构,后来它逐渐演变成了我们的标准协议。
Codex CLI 最初是一个 TUI(终端用户界面),这意味着 Codex 是通过终端访问的。当我们构建 VS Code 扩展(一种更适合 IDE 方式与 Codex 代理交互的工具)时,我们需要一种方法来使用相同的架构,以便在不重新实现的情况下从 IDE UI 驱动相同的代理循环。这意味着需要支持超越请求/响应的丰富交互模式,例如探索工作区、在代理推理时流式传输进度以及发出差异(diffs)。我们首先尝试将 Codex 作为 MCP 服务器暴露出来,但发现以一种对 VS Code 有意义的方式来维护 MCP 语义非常困难。因此,我们引入了一个镜像 TUI 循环的 JSON-RPC 协议,这成为了应用服务器的非官方首个版本。当时,我们没有预料到其他客户端会依赖该应用服务器,因此它并非被设计为稳定的 API。
在接下来的几个月里,随着 Codex 的普及,内部团队和外部合作伙伴都希望能够在自己的产品中嵌入相同的架构,以加速其用户的软件开发工作流程。例如,JetBrains 和 Xcode 想要获得 IDE 级别的代理体验,而 Codex 桌面应用则需要并行编排许多 Codex 代理。这些需求促使我们设计了一个平台界面,供我们的产品和合作伙伴集成都可以长期安全地依赖。它需要易于集成且向后兼容,这意味着我们可以在不破坏现有客户端的情况下演进协议。
接下来,我们将介绍我们如何设计架构和协议,以便不同的客户端可以使用相同的架构。
Codex 架构内部
首先,让我们深入了解 Codex 架构内部是什么,以及 Codex 应用服务器如何将其暴露给客户端。在我们上一篇 Codex 博客文章中,我们分解了编排用户、模型和工具之间交互的核心代理循环。这是 Codex 架构的核心逻辑,但完整的代理体验还有更多内容:
1. 线程生命周期和持久化。线程是用户与代理之间的一次 Codex 对话。Codex 创建、恢复、分支和归档线程,并持久化事件历史记录,以便客户端可以重新连接并渲染一致的时间线。
2. 配置和认证。Codex 加载配置、管理默认值,并运行认证流程,例如“使用 ChatGPT 登录”,包括凭证状态。
3. 工具执行和扩展。Codex 在沙箱中执行 shell/文件工具,并连接 MCP 服务器和技能等集成,使它们能够在一致的策略模型下参与代理循环。
我们在此提到的所有代理逻辑,包括核心代理循环,都位于 Codex CLI 代码库中称为“Codex 核心”的部分。Codex 核心既是一个包含所有代理代码的库,也是一个可以启动以运行代理循环和管理单个 Codex 线程(对话)持久性的运行时。
为了有用,Codex 架构需要对客户端可访问。这就是应用服务器发挥作用的地方。
应用服务器既是客户端和服务器之间的 JSON-RPC 协议,也是托管 Codex 核心线程的长期运行进程。正如我们在上图中所看到的,一个应用服务器进程有四个主要组件:stdio 读取器、Codex 消息处理器、线程管理器和核心线程。线程管理器为每个线程启动一个核心会话,然后 Codex 消息处理器直接与每个核心会话通信,以提交客户端请求并接收更新。
一个客户端请求可能导致许多事件更新,而这些详细事件使我们能够在应用服务器之上构建丰富的 UI。此外,stdio 读取器和 Codex 消息处理器充当客户端和 Codex 核心线程之间的翻译层。它们将客户端 JSON-RPC 请求转换为 Codex 核心操作,监听 Codex 核心的内部事件流,然后将这些低级别事件转换为一组稳定、为 UI 准备好的 JSON-RPC 通知。
客户端和应用服务器之间的 JSON-RPC 协议是完全双向的。一个典型的线程有一个客户端请求和许多服务器通知。此外,当代理需要输入(例如批准)时,服务器可以发起请求,然后暂停该轮次,直到客户端响应为止。
对话原语
接下来,我们将分解对话原语,即应用服务器协议的构建块。为代理循环设计 API 是一项棘手的任务,因为用户/代理交互不是简单的请求/响应。一个用户请求可能会演变成一个结构化的操作序列,客户端需要忠实地表示出来:用户的输入、代理的增量进度、沿途产生的工件(例如 diffs)。为了使该交互流易于集成并跨 UI 具有弹性,我们确定了三个具有清晰边界和生命周期的核心原语:
1. Item(项): 项是 Codex 中输入/输出的原子单位。项是类型化的(例如,用户消息、代理消息、工具执行、审批请求、diff),并且每个都有明确的生命周期:
item/started当项开始时- 可选的
item/*/delta事件,随着内容流式传输(针对流式传输的项类型) item/completed当项以其最终有效载荷完成时
此生命周期允许客户端在 started 时立即开始渲染,在 delta 时流式传输增量更新,并在 completed 时最终确定。
2. Turn(轮次): 轮次是由用户输入启动的一次代理工作单元。它始于客户端提交一个输入(例如,“运行测试并总结失败情况”),并在代理完成为该输入生成输出时结束。一个轮次包含一个项目序列,代表沿途产生的中间步骤和输出。
3. Thread(线程): 线程是用户与代理之间持续的 Codex 会话的持久化容器。它包含多个轮次。线程可以被创建、恢复、分支和归档。线程历史记录会被持久化,以便客户端可以重新连接并渲染一致的时间线。
现在,我们将看一下客户端和代理之间的简化对话,其中对话由原语表示:
在对话开始时,客户端和服务器需要建立 initialize 握手。客户端必须在任何其他方法之前发送一个单一的 initialize 请求,服务器会以响应确认。这让服务器有机会宣传其能力,并让双方在真正工作开始前就协议版本控制、功能标志和默认值达成一致。以下是来自 OpenAI VS Code 扩展的一个示例载荷:
JSON
1{2 "method": "initialize",3 "id": 0,4 "params": {5 "clientInfo": {6 "name": "codex_vscode",7 "title": "Codex VS Code Extension",8 "version": "0.1.0"9 }10 }11}
这是服务器返回的内容:
JSON
1{2 "id": 0,3 "result": {4 "userAgent": "codex_vscode/0.94.0-alpha.7 (Mac OS 26.2.0; arm64) vscode/2.4.22 (codex_vscode; 0.1.0)"5 }6}
当客户端发出新请求时,它将首先创建一个线程,然后创建一个轮次。服务器将返回进度通知(thread/started 和 turn/started)。它还会返回它注册为项的输入,例如此处的用户消息。
工具调用也会作为项发送回客户端。此外,服务器可能会在执行操作前请求客户端批准,方法是发送一个服务器请求。该批准将暂停该轮次,直到客户端以“允许”或“拒绝”进行回复为止。以下是 VS Code 扩展中审批流程的样子:
最后,服务器发送一个代理消息,然后以 turn/completed 结束该轮次。代理消息 delta 事件会流式传输消息的片段,直到消息通过 item/completed 最终确定。
图中显示的消息为了清晰起见已被简化。如果您想查看完整轮次的 JSON,可以运行 Codex CLI 仓库中的测试客户端:
Bash
1codex debug app-server send-message-v2 "run tests and summarize failures"
与客户端集成
现在,我们来看看不同的客户端界面如何通过应用服务器嵌入 Codex。我们将介绍三种模式:本地应用和 IDE、Codex Web 运行时和 TUI。
在这三种情况下,传输层都是基于 stdio 的 JSON-RPC(JSONL)。JSON-RPC 使得用您选择的语言构建客户端绑定变得很直接。Codex 界面和合作伙伴集成已在包括 Go、Python、TypeScript、Swift 和 Kotlin 在内的语言中实现了应用服务器客户端。对于 TypeScript,您可以通过运行以下命令直接从 Rust 协议生成定义:
Bash
1codex app-server generate-ts
对于其他语言,您可以生成一个 JSON Schema 包,并将其输入到您首选的代码生成器中,方法是运行:
Bash
1codex app-server generate-json-schema
本地应用和 IDE
本地客户端通常会捆绑或获取特定于平台的应用服务器二进制文件,将其作为长期运行的子进程启动,并保持一个用于 JSON-RPC 的双向 stdio 通道打开。例如,在我们的 VS Code 扩展和桌面应用中,所提供的工件包括特定于平台的 Codex 二进制文件,并固定到一个经过测试的版本,以便客户端始终运行我们验证过的确切代码。
并非所有集成都能频繁地发布客户端更新。像 Xcode 这样的某些合作伙伴通过保持客户端稳定并允许它在需要时指向更新的应用服务器二进制文件来分离发布周期。这样,他们就可以采用服务器端改进(例如,Codex 核心中更好的自动压缩或新支持的配置键),并在不等待客户端发布的情况下推出错误修复。应用服务器的 JSON-RPC 表面被设计为向后兼容,因此旧客户端可以安全地与新服务器通信。
Codex Web
Codex Web 使用 Codex 架构,但在容器环境中运行它。一个工作进程(worker)会配置一个包含已检出工作区的容器,在该容器内启动应用服务器二进制文件,并维护一个长期的 JSON-RPC over stdio2 通道。Web 应用(在用户的浏览器标签页中运行)通过 HTTP 和 SSE 与 Codex 后端通信,SSE 会流式传输工作进程产生的任务事件。这使得浏览器端 UI 保持轻量级,同时仍能在桌面和 Web 之间提供一致的运行时。
由于 Web 会话是短暂的(标签页关闭、网络中断),Web 应用不能作为长期运行任务的真实来源。将状态和进度保留在服务器上意味着即使标签页消失,工作也会继续。流式协议和保存的线程会话使得新会话可以轻松地重新连接、接续上次中断的地方并赶上进度,而无需在客户端重建状态。
TUI/Codex CLI
从历史上看,TUI 是一个“原生”客户端,与代理循环在同一进程中运行,直接与 Rust 核心类型通信,而不是应用服务器协议。这使得早期迭代速度很快,但也使得 TUI 成为了一个特殊情况的界面。
现在应用服务器已经存在,我们计划重构 TUI 以使用它,使其行为像任何其他客户端:启动一个应用服务器子进程,通过 stdio 讲 JSON-RPC,并渲染相同的流式事件和批准。这解锁了 TUI 可以连接到运行在远程机器上的 Codex 服务器的工作流程,使代理保持靠近计算资源,并在笔记本电脑休眠或断开连接时继续工作,同时仍在本地提供实时更新和控件。
选择正确的协议
Codex 应用服务器将是我们今后维护的一流集成方法,但也存在其他功能更有限的方法。默认情况下,我们建议客户端使用 Codex 应用服务器与 Codex 集成,但值得研究不同的集成方法并了解它们的优缺点。以下是驱动 Codex 最常见的方式以及每种方式可能适用的场景。我们在默认情况下建议客户端使用 Codex 应用服务器与 Codex 集成,但了解不同集成方法的优缺点也很重要。下面是驱动 Codex 的最常见方式以及每种方式可能适用的场景。
JSON-RPC 协议
将 Codex 作为 MCP 服务器
运行 codex mcp-server 并从支持 stdio 服务器的任何 MCP 客户端连接(例如,OpenAI Agents SDK(在新窗口中打开))。如果您已经拥有基于 MCP 的工作流程,并希望将 Codex 作为可调用工具来调用,这是一个很好的选择。缺点是您只能获得 MCP 暴露的内容,因此依赖于更丰富会话语义的特定于 Codex 的交互(例如 diff 更新)可能无法通过 MCP 端点清晰地映射。
跨提供商的代理架构协议
一些生态系统提供了一个可移植的接口,可以以多个模型提供商和运行时为目标。如果您想要一个协调多个代理的抽象,这是一个很好的选择。权衡是这些协议通常会收敛于通用功能子集,这使得表示更丰富的交互变得困难,尤其是在提供商特定的工具和会话语义很重要的时候。这个领域正在快速发展,我们预计随着我们确定表示现实世界代理工作流(skills 是一个很好的例子)的最佳原语,将出现更多通用标准。
Codex 应用服务器
当您希望将完整的 Codex 架构暴露为稳定、对 UI 友好的事件流时,请选择应用服务器。您可以获得代理循环的全部功能以及“使用 ChatGPT 登录”、模型发现和配置管理等其他支持功能。主要的成本是集成工作,因为您需要在自己的语言中构建客户端 JSON-RPC 绑定。然而,在实践中,如果您向 Codex 提供 JSON 架构和文档,它可以在很多繁重的工作中提供帮助。许多我们合作过的团队都能快速使用 Codex 实现有效的集成。
嵌入 Codex 的其他方式
Codex Exec(在新窗口中打开)
一种轻量级、可脚本化的 CLI 模式,用于一次性任务和 CI 运行。它非常适合自动化和管道,在这些场景中,您希望通过一个命令以非交互方式运行直到完成,为日志流式传输结构化输出,并以明确的成功或失败信号退出。
Codex SDK(在新窗口中打开)
一个 TypeScript 库,用于从您的应用程序内部以编程方式控制本地 Codex 代理。当您希望在不构建单独的 JSON-RPC 客户端的情况下,为服务器端工具和工作流程提供原生库接口时,这是最佳选择。由于它的发布时间早于应用服务器,目前它支持的语言较少,覆盖的范围也较小。如果有开发者感兴趣,我们可能会添加其他包装应用服务器协议的 SDK,以便团队无需编写 JSON-RPC 绑定就能覆盖更多的架构范围。
展望未来
在本文中,我们分享了我们设计与代理交互的新标准以及如何将 Codex 架构转变为稳定、对客户端友好的协议的方法。我们介绍了应用服务器如何暴露 Codex 核心,允许客户端驱动完整的代理循环,并为包括 TUI、本地 IDE 集成和 Web 运行时在内的各种界面提供支持。
如果本文激发了您将 Codex 集成到自己工作流程中的想法,那么尝试应用服务器是值得的。所有源代码都位于 Codex CLI 开源仓库中。欢迎随时分享您的反馈和功能请求。我们期待您的反馈,并继续使代理对每个人都更易于访问。
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。
评论区