数据截至 (上游 commit f1087ff151b0)
OpenAI Codex CLI — 架构与原理
30 秒导读: Codex CLI 是 OpenAI 出的一个跑在你本机终端里的编码 agent——你用自然语言提需求,它读你的代码、跑命令、改文件,帮你把活干完。它用 Rust 写成,最值得学的三件事是:① 把「模型说话 → 执行工具 → 结果回灌」串成一个干净的回合循环;② 一套独门的
apply_patch模糊补丁格式,让模型不必逐字复现原文也能精确改代码;③ 用操作系统级沙箱(macOS seatbelt / Linux landlock)把模型跑的命令关进笼子,并在被拒时按策略再升级。
1. 这是什么(零基础也能懂)
-
一句话定义: Codex CLI 是一个本地运行的编码 agent——一个能读写你项目文件、执行 shell 命令、并由大模型驱动的命令行程序。
-
解决什么问题 / 给谁用: 假设你在终端里,想让 AI 帮你「给这个函数加单测」「把这个 bug 修了」「把依赖升级一版」。你不想把代码贴到网页、也不想 AI 在你机器上乱跑命令。Codex 就是干这个的:它在你本机跑,能看到整个仓库,能真的执行命令验证自己改得对不对,同时被沙箱和审批策略管着,不至于失控。
-
它能做什么:
- 多回合对话式地理解任务,自主决定下一步调哪个工具;
- 用
apply_patch改文件、用 shell 跑命令、跑测试看结果; - 按你设的「审批策略 + 沙箱策略」决定哪些操作自动放行、哪些要问你;
- 上下文塞满时自动压缩历史继续干;
- 接 MCP 工具、skills、子 agent、IDE 等扩展面。
-
用起来什么样: 装好后在项目目录里敲
codex,然后像聊天一样提需求:
$ codex
› 给 src/seek_sequence.rs 里的 normalise 函数补几个单测
• 读取 src/seek_sequence.rs
• apply_patch src/seek_sequence_tests.rs (+42 行) [自动批准]
• cargo test seek_sequence [在沙箱中运行]
test result: ok. 5 passed; 0 failed
已加好测试并验证通过。
注意每一步——读文件、打补丁、跑测试——都是模型主动发起的工具调用,Codex 负责执行、把结果喂回去,直到模型认为干完了。
- 一句话直觉/类比: 把 Codex 想成一个坐在你电脑前、戴着手铐的结对程序员。「大脑」是远端的模型,「手」是本地的工具(改文件 / 跑命令),「手铐」是沙箱(它只能在你划定的范围内动手),「管家」是审批策略(危险动作得先问你)。整份代码库就是在精心设计这套「大脑—手—手铐—管家」怎么协作。
2. 顶层全景(它大概怎么转)
Codex 是一个庞大的 Rust workspace(codex-rs/ 下有 100+ 个 crate),但价值高度集中在 codex-core 这一个 crate。其余 crate 大多是它的卫星:协议定义、各前 端(TUI / exec / MCP server)、沙箱实现、补丁解析器等。
先看大盘——一次请求的数据流:
你(终端 / IDE / exec)
│ Op::UserInput ← 提交「指令」(protocol crate 定义)
▼
┌─────────────────────────────────────────────┐
│ ThreadManager → CodexThread → Session │ 会话/线程编排
│ (core::thread_manager / session) │
└───────────────┬───────────────────────────────┘
│ 起一个 RegularTask
▼
┌─────────────────────────────────────────────┐
│ run_turn ── 回合循环 ──┐ │ ← 本项目的心脏
│ ① 压缩(如需) ② 采样请求 ③ 执行工具 ④ 回灌 │
│ (core::session::turn) │ │
└──────┬──────────────────┼─────────────────────┘
│ 采样 │ 工具
▼ ▼
ModelClient ToolRouter → ToolOrchestrator
(Responses API) (审批→选沙箱→执行→失败升级)
│ │
▼ ▼
远端大模型 shell / apply_patch / MCP …
│
▼
OS 沙箱(seatbelt / landlock)
怎么读这张图: 从上往下是一次用户指令的生命周期。左路「采样」去问模型下一步干嘛,右路「工具」把模型的决定落到真实世界,二者在 run_turn 里反复交替,直到模型只回一句话(不再要工具)为止。
主要部件一句话职责:
| 部件 | 干什么 | 在哪 |
|---|---|---|
protocol crate | 定义 agent 与前端之间的「指令(Op)/事件(EventMsg)」数据契约,以及审批/沙箱策略枚举 | codex-rs/protocol/src/protocol.rs |
ThreadManager / Session | 编排会话、线程、配置、各类 manager(MCP/skills/插件) | codex-rs/core/src/thread_manager.rs、session/session.rs |
run_turn(回合循环) | 反复「采样→执行工具→回灌」,中途按需压缩上下文 | codex-rs/core/src/session/turn.rs |
ModelClient | 通过 Responses API(WebSocket)流式向模型采样 | codex-rs/core/src/client.rs |
ToolRouter / ToolOrchestrator | 把模型的工具调用路由到 handler,并统一做审批+沙箱+重试 | codex-rs/core/src/tools/router.rs、tools/orchestrator.rs |
apply_patch | 解析并落地独门的模糊补丁格式 | codex-rs/apply-patch/、core/src/tools/handlers/apply_patch.rs |
sandboxing | seatbelt(mac)/ landlock+seccomp(linux)/ 受限令牌(win)三套 OS 沙箱 | codex-rs/sandboxing/ |
context_manager / compact | 维护对话历史,token 超限时压缩 | codex-rs/core/src/context_manager/、compact.rs |
主线走一遍(高层,不进代码):
- 前端(TUI/exec/MCP)把你的话包成一条
Op::UserInput提交给Session。 Session起一个RegularTask,进入run_turn。run_turn先把历史拼成一次采样请求,经ModelClient流式发给模型。- 模型回的若是工具调用(如 shell / apply_patch),
ToolRouter路由到对应 handler,ToolOrchestrator走「审批→选沙箱→执行→失败可升级」,结果作为 function output 回灌历史,继续下一轮采样。 - 模型回的若只是一句话(不再要工具),回合结束,把这句话作为最终回复发回前端。
- 任意一轮发现 token 快满,就触发自动压缩(把旧历史换成摘要)后再继续。
3. 核心机制(本库挑了三个最值得学的)
这个项目太大,面面俱到会变成「源码考古」。我们只深入讲最能代表 Codex、也最可借鉴的三条主线,各占一章:
| 机制 | 一句话 | 章节 |
|---|---|---|
| 回合循环 | 「采样→工具→回灌」如何串成一个会自动压缩、能并发执行工具、能被打断的循环 | 01-agent-loop.md |
| apply_patch | 一套让模型「大致写对就能精确改代码」的模糊补丁格式 + 四级容错匹配 | 02-apply-patch.md |
| 沙箱与安全 | 审批策略 × OS 沙箱 × 失败再升级,三层叠起来既安全又少打扰 | 03-sandbox-safety.md |
4. 阅读地图(建议顺序)
- 先读本页 §1–§2——建立「这是什么、大盘怎么转」的直觉。
01-agent-loop.md——理解 Codex 的「心跳」。读懂它,其余都好挂上去。02-apply-patch.md——Codex 最独特的工程亮点,可单独拿走借鉴。03-sandbox-safety.md——Codex 区别于「玩具 agent」的地方:它敢在你真机上跑命令,靠的就是这套护栏。
5. 横向对比(同 shelf 兄弟)
Codex 在 ai-agent-reference / coding-agents 这一格,和 Aider、Claude Code 等是兄弟。几个取舍上的差异:
| 维度 | Codex 的取舍 |
|---|---|
| 实现语言 | Rust(多数同类是 Python/TS)——换来单二进制分发、OS 沙箱能力、和原生进程隔离 |
| 编辑格式 | 独门 apply_patch(*** Begin Patch 标记 + 上下文锚点 + 多级模糊匹配),而非 unified diff 或整文件重写 |
| 安全模型 | 把 OS 级沙箱(seatbelt/landlock)做成一等公民,且「沙箱被拒 → 按审批策略再升级」 |
| 模型接口 | 走 OpenAI Responses API(支持 WebSocket 流式),回合内复用同一连接 |
具体「为什么模糊匹配」「沙箱为什么分三层」见对应章节;跨库的「编辑落地」「沙箱化」原理对比见本 shelf 总库 doc。
6. 代码地图(导航索引)
| 主题 | 文件 | 关键符号 |
|---|---|---|
| 回合循环入口 | codex-rs/core/src/session/turn.rs | run_turn、run_sampling_request |
| 任务包装 | codex-rs/core/src/tasks/regular.rs | RegularTask、SessionTask::run |
| 工具路由 | codex-rs/core/src/tools/router.rs | ToolRouter、dispatch_tool_call_with_terminal_outcome |
| 工具编排(审批+沙箱+重试) | codex-rs/core/src/tools/orchestrator.rs | ToolOrchestrator、run、run_attempt |
| 补丁解析 | codex-rs/apply-patch/src/parser.rs | parse_patch、Hunk、UpdateFileChunk |
| 模糊匹配 | codex-rs/apply-patch/src/seek_sequence.rs | seek_sequence、normalise |
| 补丁拦截/落地 | codex-rs/core/src/tools/handlers/apply_patch.rs | intercept_apply_patch |
| 协议数据契约 | codex-rs/protocol/src/protocol.rs | Op、EventMsg、AskForApproval、SandboxPolicy |
| 安全评估 | codex-rs/core/src/safety.rs | assess_patch_safety、SafetyCheck |
| 沙箱管理 | codex-rs/sandboxing/src/manager.rs | SandboxManager、SandboxType |
| seatbelt 策略 | codex-rs/sandboxing/src/seatbelt_base_policy.sbpl | (deny default) 起的策略 |
| 上下文/历史 | codex-rs/core/src/context_manager/history.rs | ContextManager |
| 压缩 | codex-rs/core/src/compact.rs | SUMMARIZATION_PROMPT、run_inline_auto_compact_task |