深入理解 Codex 嵌入架构:App Server 与 SDK 双路径解析

你跟同事聊 Codex 的时候,有没有过这种体验?你说「我用 Codex 写了个脚本」,「我用 Codex 审查了 PR」,他说「我在 VS Code 里用 Codex 重构了模块」。听起来都是 Codex,但背后走的路径完全不同。
你用的是 CLI,他是 IDE 插件,运维那边用 codex exec 跑 CI,平台组在往自己的产品里嵌入 Codex SDK。七种入口,七种交互方式,但底层跑的是同一套东西:一个 Agent 循环。
这篇文章把 Codex 的嵌入架构从里到外拆开:先从 Agent 循环讲起,然后看 Sandbox 和 Approval 两个关键控制点,最后深入 App Server 协议和两个 SDK 的本质差异。读完你就知道什么时候该用 SDK,什么时候必须直接上 App Server。
Codex 的七扇门#
先看全局。Codex 的入口可以分成三类:
交互式入口(给人用的)
- CLI:在终端里直接跟 Codex 对话,检查代码、做修改、跑命令,沙箱和审批策略按会话配置。
- IDE 扩展:支持 VS Code 和 JetBrains,直接把打开的文件和选中内容送进 Prompt,就地审查修改,还能把长任务丢到云端。
- 桌面应用:2026 年 7 月 9 日起合并进了 ChatGPT 桌面应用,像一个指挥中心,可以同时管理多个项目和 Agent。
- Codex Cloud:完全跳过你的本地机器,在隔离的云端环境里执行任务。你可以从网页、GitHub、Linear 或 Slack 派发任务,等结果就行。
编程式入口(用来集成和构建的)
codex exec:把 CLI 变成一行命令,给 CI 和自动化脚本用。进度以行分隔的 JSON 流输出。GitHub Action 本质上就是套了一层 CI 壳的codex exec。- Codex SDK:Python 和 TypeScript 两个版本。SDK 在你的机器上启动
codex二进制作为子进程,然后通过代码来开始和恢复对话。适合把 Codex 嵌入 CI/CD 系统,或者构建自定义 Agent 宿主。 codex app-server:一个 JSON-RPC 接口,IDE 扩展和 Python SDK 的底层都在用。它定义了「跟 Codex 对话」到底意味着什么。当你需要自定义 UI、自己的审批逻辑,或者用非 Node/Python 的语言做宿主时,这就是你要走的路。codex mcp-server(实验性):把 Codex 暴露为一个 MCP 工具,让其他 Agent 像调用普通工具一样调用 Codex。
前四个是给人用的,中间两个是给平台工程师和 CI 用的,最后两个才是真正的嵌入路径。很多人搞混的,就是 App Server 和 SDK。一个是原始协议,一个是预制的客户端。下面我们一步步说清楚。
Agent 循环:一次请求 = 多次行动#
在我解释 App Server 协议之前,得先理解它包裹的是什么。所有入口,无论 CLI、IDE 还是 Cloud,底层跑的都是同一个 Agent 循环。
很多人第一次用 Codex 会有一个错觉:我发一条消息,模型生成一个回复,结束。不是这样的。一次「回合」(turn)是一次完整的迭代过程:
- 模型读取你的请求
- 模型提出一个行动(比如运行测试、编辑文件、执行命令)
- 运行时在沙箱里执行这个行动
- 结果返回给模型
- 模型根据结果决定下一步
- 重复 2-5,直到模型认为任务完成
- 模型发出最终消息,回合结束
一条「诊断失败测试并修复它」的请求,可能在一次回合里展开成多次推理调用、多次 shell 命令和多次文件编辑。模型不是一次性想好所有步骤然后执行,它是一步一步试探,每步都根据前一步的结果来调整。
这个过程背后有两个关键优化。一是前缀缓存(prefix caching),让重复的上下文保持廉价;二是历史压缩(history compaction),当上下文超过阈值时自动压缩。但这些对你不可见,你看到的就是这个循环:提出 → 执行 → 观察 → 重复。
下面这张图描述了整个循环:你发送一条消息,模型在循环中反复执行,直到最终回复。理解了这个循环,后面看 App Server 协议的每个方法就清楚了,每个方法都对应这个循环的某个节点。
两道闸门:Sandbox 和 Approval#
在嵌入 Codex 之前,你必须理解两个独立但又常常被混淆的控制机制。一个是技术边界(Sandbox),一个是决策边界(Approval)。混用它们,要么给 Agent 过多自由,要么束缚得太紧。
Sandbox:技术边界#
Sandbox 定义 Agent 物理上能做什么,由运行时强制执行,不是靠 Agent 自觉。三个级别:
- read-only:Agent 可以查看文件,但不能编辑,不能运行命令。
- workspace-write(默认):可以在工作区内读写、编辑、运行常规本地命令。网络访问默认关闭,需要显式开启。
- danger-full-access:Agent 能做任何事情,包括访问网络、修改系统文件。慎用。
Sandbox 是一道围栏,围住了 Agent 的「能力范围」。Agent 天生就想干活,你不设围栏,它会帮你把整个项目目录清理了(别问我怎么知道的)。
Approval:决策边界#
Approval 决定 Agent 在跨过某些边界之前必须停下来问你。即使它在 workspace-write 沙箱里运行,有些操作你还是想看一眼。
- auto-accept:全部自动放行,Agent 永远不需要问你。
- ask-everything:每次操作都问你,包括读文件。安全但非常烦人。
- default:按照风险分级,常规操作自动放行,高风险操作(如
rm -rf、git push --force、网络请求)弹窗让你确认。
Sandbox 和 Approval 是正交的。你可以给 Agent workspace-write 的沙箱,但把 Approval 设成 ask-everything,让它在每次编辑前都征求你的意见。反过来,你也可以给 danger-full-access 但设 auto-accept,这就像把车钥匙交给一个不认识的人并告诉他「随便开」,技术上允许,但大概率你会后悔。
理解了这两个控制点,我们来看 App Server 协议本身。
App Server 协议:JSON-RPC 的本质#
codex app-server 是 Codex 真正的「语言」。CLI、IDE 扩展、Python SDK,最终都在说这门语言。它基于 JSON-RPC,通过标准输入输出(stdio)通信,定义了三个核心概念:线程(thread)、回合(turn)、事项(item)。
线程:持久化的对话容器#
一个线程就是一个对话容器,有唯一 ID。你用 thread/start 开启一个新线程,或者用 thread/resume 恢复一个已有线程。线程跨进程持久化,你可以断开连接,过几天再通过同一个线程 ID 把对话接回来。
还有一个 thread/fork,可以从某个线程的某个点分叉出去,创建一条平行的对话路径。这在探索不同方案时非常有用。
回合:一个完整的循环#
回合在线程内运行。你发送 turn/start,带上用户输入,服务器立刻返回 status: "inProgress"。注意,这里只是接受了请求,还没执行。
接下来你的宿主代码停止发送请求,转为读取服务器推送的通知流:
turn/started:回合开始- 一系列
item/started→item/agentMessage/delta(逐 token 流式推送)→item/completed turn/completed:回合结束,包含 token 用量
每个事项(item)可以是推理步骤、shell 命令、文件编辑或消息。所有事项都走同样的 start-delta-complete 序列,所以宿主可以实况渲染进度,而不是等整个回合跑完。
审批往返:协议里最重要的时刻#
当 Agent 想做一件 Approval 策略不放行的事情时,App Server 不会自己决定。它向你的宿主发送一个请求:
item/commandExecution/requestApproval(命令审批)item/fileChange/requestApproval(文件编辑审批)
请求里面包含命令内容、工作目录和理由。回合在这里阻塞,直到你的宿主回复决策。
你的宿主回复一个简单的 payload:{"decision": "accept"} 通过,或者 decline 拒绝,或者 acceptForSession 本次会话内记住。服务器收到后发送 serverRequest/resolved,事项继续执行直到 item/completed。
这就是 App Server 给你而 codex exec 给不了的东西:一个实时的、逐项决定的、你可以插入自己逻辑的决策席位。你的宿主不是旁观者,是参与者。
两个 SDK:名似而实异#
大多数人不需要手写 JSON-RPC 宿主。你只想调一个函数,传一个 prompt,拿一个结果。这就是 SDK 的定位:预制的宿主客户端。
Codex 提供了 Python 和 TypeScript 两个 SDK。它们暴露的 API 表面很像:startThread() → run(prompt) → finalResponse。但底层实现完全不同,这个差异决定了你能做什么、不能做什么。
TypeScript SDK:codex exec 的语法糖#
TypeScript SDK 的实现出人意料地简单:它不跟 App Server 协议对话,它直接 spawn codex exec --experimental-json 进程,然后读取行分隔的事件流。
import { Codex } from "@openai/codex-sdk";
const codex = new Codex();
const thread = codex.startThread();
const turn = await thread.run("Diagnose the test failure and propose a fix");
console.log(turn.finalResponse);
它暴露的事件是 codex exec 的 schema:thread.started、item.completed、turn.completed 这种点分隔的命名,而不是 App Server 的斜线命名。runStreamed() 方法让你拿到结构化事件流,但这套事件里根本没有 approval-request 这个东西,审批策略在进程启动时就锁死了,你无法中途介入。
Sandbox 控制也是通过 CLI 的 --sandbox 参数,不是类型化的枚举。一句话,TypeScript SDK 就是给 codex exec 套了一层好看的皮。
Python SDK:真正的协议封装#
Python SDK 是另一种东西。它的 CodexClient 明确定义自己是一个「针对 codex app-server 的 JSON-RPC stdio 客户端」,start() 方法 spawn 的也正是 App Server。
from openai_codex import Codex, Sandbox
with Codex() as codex:
thread = codex.thread_start(sandbox=Sandbox.workspace_write)
result = thread.run("Explain this repository in three bullets.")
print(result.final_response)
Python SDK 给你一等公民的 Sandbox 枚举(read_only、workspace_write、full_access)、ApprovalMode,以及通过 thread.turn(...).stream() 获取的原始协议通知流,不是 codex exec 的粗糙事件。
当你在协议交互图中切换「宿主」为「Python SDK」模式时,它把整个握手、回合、流式事项全部折叠成了一次阻塞调用,返回一个 TurnResult。
选择的关键:审批权在谁手里#
两个 SDK 都帮你处理了连接生命周期、消息关联和版本锁定。但它们也都吸收了你最想拿到的东西:审批决定权。
TypeScript SDK 根本不暴露审批事件。Python SDK 虽然能拿到原始协议流,但它的公开 API 只支持用预设的 ApprovalMode 策略自动回答审批,不允许你的代码在单个审批请求上做决定。
这就画出了一条清晰的分界线:
| 场景 | 用 SDK | 用 App Server |
|---|---|---|
| CI 脚本,一次性跑完 | ✅ | ❌ 太重 |
| 批量处理,不需要人工干预 | ✅ | ❌ |
| 内部工具,启动后读结果 | ✅ | ❌ |
| 需要实况渲染 Agent 工作过程 | ❌ | ✅ |
| 需要在每个审批决策上介入 | ❌ | ✅ |
| 宿主语言不是 Python 或 Node | ❌ | ✅ |
如果你选 SDK,Python 版比 TypeScript 版更强大:它直接说 App Server 协议,暴露了 Sandbox 枚举和原始事件流。TypeScript 版只是在 codex exec 外面包了一层。
为什么这很重要#
Codex 的开放架构正在改变我们对「AI 编程工具」的认知。它不是一个你只能通过官方 UI 访问的黑盒,而是一个可以嵌入任何产品、任何流水线的 Agent 运行时。
OpenAI 在 2026 年 6 月宣布收购 Ona(原 Gitpod),获取其安全云执行技术,让 Codex 能在持久化、快照化的云环境中执行长时间任务。「Agent 在笔记本合上之后还在工作」不再是一个科幻场景。
但无论 Agent 在哪里执行,你的笔记本、CI 容器、还是你永远看不到的云端数据中心,它的对话模型不变。 线程和回合的概念、事项流、审批往返,这套协议是稳定的基础设施。你学会一次,在哪都能用。
如果你只是想写个脚本跑完拉倒,SDK 够用。如果你想构建一个真正的 Agent 驱动产品,让用户在关键时刻做决策,去学 App Server 协议。它不复杂,只是一个 JSON-RPC 循环,但它是你真正「拥有」Codex 的方式。
参考来源:Akash Tandon, “Embedding OpenAI Codex: The App Server and SDKs”, July 2026.