如果你第一次打开 codex-main 这个源码目录,很容易被它的规模吓住:顶层有 npm 包、Rust workspace、SDK、app-server、MCP、插件、技能、沙箱、TUI、云任务、线程存储、模型提供商、登录认证等大量模块。它不像一个传统命令行工具,也不像一个简单的 ChatGPT 包装器。更准确地说,Codex CLI 是一个“本地运行的智能软件工程代理”:它能理解用户目标,读取项目上下文,调用模型推理,决定是否执行命令或修改文件,把工具结果回传给模型,再持续推进任务直到给出最终结果。

本文基于当前工作区的 codex-main 源码目录进行分析,目标是让初学者也能看懂 Codex 的基本原理,同时给有工程背景的读者足够的架构细节。文章会围绕四个问题展开:

第一,Codex 到底是什么?它和普通命令行工具、普通聊天机器人有什么区别?

第二,Codex 的源码是如何组织的?哪些 crate 或目录承担核心职责?

第三,Codex 的核心执行原理是什么?从用户输入一条需求,到模型调用 shell、修改文件、读取 MCP 资源、输出最终答案,中间经过了哪些关键步骤?

第四,从工程实践角度看,我们可以怎样使用 Codex、扩展 Codex,或者从它的架构中学习如何设计自己的 AI Agent?

先给出一句通俗但准确的定义:

Codex 是一个以 Rust 为核心实现的本地软件工程 Agent 运行时,它通过协议层连接 UI、CLI、App Server 和无交互执行入口,通过 core 会话循环连接模型和工具,通过沙箱、审批、配置、MCP、技能、插件等机制把“模型会想”变成“系统能安全地做事”。

从源码看,Codex 并不是把用户问题直接发给模型,然后打印模型回答这么简单。它更像一个小型操作系统,里面有输入队列、事件队列、会话状态、权限系统、工具注册表、上下文管理器、模型客户端、执行沙箱、插件系统和持久化存储。模型只是决策核心之一,真正把 Agent 做成产品的是围绕模型的一整套工程系统。

为了帮助初学者建立直觉,我们先用一个简化流程表示 Codex 的工作方式:

普通回复

工具调用

用户输入任务

CLI/TUI/App Server 接收请求

加载配置、权限、AGENTS.md、技能和插件

构建模型可见上下文

向模型发起 Responses API 请求

模型输出什么

记录消息并展示给用户

ToolRouter 匹配工具

审批与沙箱检查

执行 shell、apply_patch、MCP、web、子代理等工具

工具结果写回会话历史

结束当前 turn

这个循环是理解 Codex 的关键。传统 CLI 往往是“一条命令 -> 一个结果”,聊天机器人往往是“一段上下文 -> 一段文本”。Codex 则是“一段目标 -> 多轮推理 -> 多次工具调用 -> 状态更新 -> 最终交付”。它的源码复杂度主要来自三个方面:

  1. 模型需要看到足够上下文,但上下文窗口有限,所以需要压缩、裁剪和结构化注入。
  2. 模型需要调用真实工具,但工具可能读写文件、联网、执行命令,所以必须有权限、沙箱和审批。
  3. Codex 要服务多种入口,包括交互式 TUI、无交互 exec、IDE/桌面 App、MCP Server、Cloud 任务等,所以需要稳定协议和分层架构。

接下来进入源码层面的系统拆解。

2. 内容

简要介绍:codex-main 是一个多语言单仓库,外层 npm 包负责分发和启动,核心能力集中在 codex-rs Rust workspace。最重要的主线是:codex-cli/bin/codex.js 找到对应平台的原生二进制,Rust cli 解析命令,tui 或 exec 或 app-server 建立会话,core 运行 Agent 主循环,protocol 定义客户端与 Agent 之间的操作和事件,tools 负责把模型输出映射成真实工具调用,sandboxing 和权限系统负责限制风险。

2.1 Codex 不是“聊天壳”,而是 Agent Runtime

很多初学者第一次理解 AI 编程工具时,会把它想成:

用户:帮我修 bug

程序:把问题发给模型

模型:返回一段代码

程序:显示代码

这只是最早期的代码助手形态。Codex 源码展示的是更成熟的 Agent 形态:

用户:帮我修 bug

Codex:读取项目规则

搜索相关文件

运行测试

分析失败

修改代码

再运行测试

汇总结论

这个过程中,模型需要不断“看见”外部世界。它不能只凭训练记忆回答,因为当前项目的代码、测试失败、用户本地环境、未提交变更、配置文件和工具输出都在实时变化。Codex 的核心价值就在于把这些外部信息纳入一个受控循环。

在 codex-rs/core/src/session/turn.rs 中,源码对 run_turn 的注释已经把核心机制讲得很清楚:每一次 sampling request,模型可能返回函数调用,也可能返回助手消息。如果返回工具调用,Codex 执行工具并把工具输出作为下一次请求的输入;如果返回普通助手消息,就记录进历史并认为当前 turn 完成。

也就是说,Codex 的“智能”不只是模型能力,还包括它周围的运行时能力:

  • 它能把模型输出解析成结构化工具调用。
  • 它能把工具调用映射到本地实现。
  • 它能在执行前检查权限与审批策略。
  • 它能把执行结果转换成模型能理解的 ResponseInputItem
  • 它能维护线程、turn、上下文窗口、token 预算和持久化记录。

如果我们把 Codex 当成一个系统来观察,可以把它拆成五层:

用户入口层:CLI / TUI / exec / App Server / MCP Server

协议层:Op / Event / Thread / Turn

核心层:Session / Turn / Context / ModelClient

工具层:ToolRouter / ToolRegistry / ToolRuntime

执行与安全层:sandbox / approval / permission profile

模型与外部服务:OpenAI Responses API / WebSocket / HTTP / MCP

其中最重要的源码目录如下:

codex-main/
├── README.md                         # 项目入口说明,介绍安装方式和产品形态
├── codex-cli/
│   └── bin/codex.js                  # npm 包入口,定位并启动平台原生二进制
├── codex-rs/
│   ├── Cargo.toml                    # Rust workspace,列出大量内部 crate
│   ├── cli/                          # 顶层命令行解析与子命令分发
│   ├── tui/                          # 交互式终端 UI
│   ├── exec/                         # 非交互执行入口,适合脚本和 CI
│   ├── core/                         # Agent 核心:会话、turn、工具、上下文、模型调用
│   ├── protocol/                     # 核心协议类型:Op、Event、SandboxPolicy 等
│   ├── app-server/                   # App/IDE 等宿主形态可复用的服务端
│   ├── app-server-protocol/          # App Server v1/v2 JSON-RPC 协议
│   ├── codex-api/                    # OpenAI API / Responses API 访问层
│   ├── codex-client/                 # HTTP/SSE/WebSocket 客户端基础能力
│   ├── model-provider/               # 模型提供商抽象
│   ├── mcp-server/、codex-mcp/       # MCP 相关能力
│   ├── core-skills/、skills/         # 技能加载与注入
│   ├── core-plugins/、plugin/        # 插件 manifest、市场和本地插件
│   ├── sandboxing/                   # 跨平台沙箱抽象
│   ├── linux-sandbox/                # Linux Landlock / bubblewrap 支持
│   ├── windows-sandbox-rs/           # Windows 受限 token、ACL、WFP 等
│   ├── thread-store/                 # 线程持久化抽象
│   ├── rollout/、rollout-trace/      # 会话记录、回放和调试
│   └── tools/                        # 工具规范和共享工具定义
└── sdk/
    ├── python/                       # Python SDK
    └── typescript/                   # TypeScript SDK

从这个目录可以看出,Codex 的核心不是某一个巨大文件,而是一组职责明确的 crate。core 是大脑和调度中心,但它并不直接承担所有事情:协议在 protocol,UI 在 tui,无交互运行在 exec,App 集成在 app-server,沙箱在 sandboxing,插件和技能也拆成独立模块。

这正是大型 Agent 工程的第一条经验:不要把“模型调用、工具实现、UI 展示、权限控制、配置读取、状态存储”塞进一个文件。它们变化频率不同,风险边界不同,测试方式也不同。

2.2 从安装启动看 Codex 的第一层架构

Codex 可以通过 npm install -g @openai/codex、Homebrew 或安装脚本安装。源码中的 codex-cli/package.json 定义了 npm 包名和可执行入口:

{
  "name": "@openai/codex",
  "bin": {
    "codex": "bin/codex.js"
  },
  "type": "module"
}

但 codex.js 并不实现 Agent 本身。它做的是平台适配:根据 process.platform 和 process.arch 判断目标三元组,例如 macOS arm64 对应 aarch64-apple-darwin,Linux x64 对应 x86_64-unknown-linux-musl,Windows x64 对应 x86_64-pc-windows-msvc。然后它到对应平台包的 vendor/<target>/bin/codex 下寻找真正的原生二进制,最后用 spawn 把参数原样转发过去。

简化版代码可以这样理解:

// 简化示例:根据平台选择原生 Codex 二进制
const targetMap = {
  "darwin-arm64": "aarch64-apple-darwin",
  "darwin-x64": "x86_64-apple-darwin",
  "linux-x64": "x86_64-unknown-linux-musl",
  "win32-x64": "x86_64-pc-windows-msvc",
};

const key = `${process.platform}-${process.arch}`;
const targetTriple = targetMap[key];

// 真实源码会处理更多平台、包管理器提示和信号转发
const binaryPath = `vendor/${targetTriple}/bin/codex`;

// 关键逻辑:Node 只负责启动,Agent 主体在 Rust 二进制里
spawn(binaryPath, process.argv.slice(2), {
  stdio: "inherit",
  env: process.env,
});

这个设计有几个好处:

  1. npm 生态用户安装方便,不需要自己编译 Rust。
  2. 真正运行时代码是原生二进制,启动快,资源控制强。
  3. 平台差异被集中处理,Rust 侧可以根据目标平台启用不同沙箱实现。
  4. Node 入口保留了信号转发能力,用户按 Ctrl-C 时能把信号传给子进程。

初学者可以把 codex-cli/bin/codex.js 理解为“门卫”,它不负责推理,只负责把你带到真正的入口。

进入 Rust 之后,codex-rs/cli/src/main.rs 使用 clap 定义了顶层命令。源码里的 Subcommand 很能说明 Codex 的产品边界:

  • Exec:非交互运行 Codex。
  • Review:无交互代码审查。
  • Login / Logout:认证管理。
  • Mcp:管理外部 MCP server。
  • Plugin:管理 Codex 插件。
  • McpServer:把 Codex 作为 MCP server 运行。
  • AppServer:运行 app server 或相关工具。
  • App:启动桌面 App。
  • Doctor:诊断本地安装、配置、认证和运行环境。
  • Sandbox:在 Codex 提供的沙箱里运行命令。
  • Resume / Fork / Archive / Delete / Unarchive:会话管理。
  • Cloud:浏览 Codex Cloud 任务并应用变更。

这说明 Codex CLI 不是单一命令,而是一个多入口工具箱。默认不带子命令时进入交互式 TUI;带 exec 时进入无交互模式;带 mcp-server 时变成 MCP 服务;带 app-server 时面向桌面或 IDE 宿主。

2.3 Rust workspace:为什么 Codex 拆成这么多 crate

codex-rs/Cargo.toml 是理解源码组织的关键。它的 workspace members 非常多,包括 coreprotocoltuiexecapp-servercodex-apicodex-mcpsandboxingthread-storecore-skillscore-pluginsmodel-provider 等。

初学者可能会问:为什么不用一个 crate?原因很实际。

第一,Codex 是多宿主系统。TUI、exec、App Server 和 MCP Server 都需要复用同一个核心 Agent,但它们的输入输出完全不同。把协议、核心、UI、无交互处理拆开,才能让同一个 core 服务多种入口。

第二,Codex 是安全敏感系统。执行 shell、修改文件、联网、读取本地资源都需要被严格约束。沙箱和权限逻辑必须独立、可测试、可复用,不能和 UI 代码混在一起。

第三,Codex 是可扩展系统。MCP、插件、技能、动态工具、子代理都属于扩展点。扩展点如果散落在主循环里,会让系统越来越难维护。

第四,Codex 需要跨平台。macOS 有 Seatbelt,Linux 有 Landlock/bubblewrap,Windows 有受限 token、ACL、WFP 等机制。跨平台安全抽象需要独立模块承载。

源码中的 AGENTS.md 也明确提醒贡献者:“resist adding code to codex-core”。这句话很重要。codex-core 已经很大,团队希望新功能优先放到更合适的 crate,而不是继续膨胀核心 crate。这是大型 Rust 项目常见的工程约束:核心越大,编译越慢,依赖越乱,测试越难,评审风险越高。

我们可以把核心 crate 职责概括如下:

入口层:
  cli/               解析命令,分发到 TUI、exec、登录、插件、MCP 等功能
  tui/               交互式终端体验
  exec/              非交互模式,保证 stdout/stderr 语义清晰
  app-server/        给桌面、IDE、远程控制等提供服务端能力

协议层:
  protocol/          Codex 内部 Op/Event/权限/配置/用户输入等类型
  app-server-protocol/ App Server JSON-RPC 协议和 v2 API

核心层:
  core/              Session、Turn、上下文、工具调度、模型请求、审批
  thread-store/      会话持久化抽象
  rollout/           本地记录和恢复

工具与扩展层:
  tools/             工具名称、规范和共享结构
  core-skills/       技能发现、加载、渲染、注入
  core-plugins/      插件 manifest、市场和安装状态
  codex-mcp/         MCP server 配置、工具暴露和连接

执行与安全层:
  sandboxing/        跨平台沙箱选择和命令转换
  linux-sandbox/     Linux 沙箱实现
  windows-sandbox-rs/ Windows 沙箱实现
  shell-command/     shell 命令解析与安全判断
  execpolicy/        执行策略检查

模型与服务层:
  codex-api/         Responses API、SSE、WebSocket、Realtime 等端点封装
  codex-client/      HTTP 传输、重试、错误等基础客户端
  model-provider/    模型提供商抽象
  login/             ChatGPT/API key/令牌等认证

如果你想快速入门源码,不建议从 core/src/session/turn.rs 第一行开始硬啃。更好的阅读顺序是:

  1. 看 README.md,理解产品形态。
  2. 看 codex-cli/bin/codex.js,理解 npm 入口只负责启动原生二进制。
  3. 看 codex-rs/cli/src/main.rs,理解顶层子命令。
  4. 看 codex-rs/protocol/src/protocol.rs,理解 Op 和 EventMsg
  5. 看 codex-rs/core/src/session/turn.rs 的 run_turn 注释和主循环。
  6. 看 codex-rs/core/src/tools/spec_plan.rs 和 router.rs,理解工具如何注册与分发。
  7. 看 codex-rs/core/src/exec.rssafety.rssandboxing/src/lib.rs,理解执行安全。

3. 核心原理:一个 Codex turn 是怎样跑起来的

3.1 协议层:Submission Queue 与 Event Queue

codex-rs/protocol/src/protocol.rs 的文件注释写明:它定义了 Codex session 中客户端与 Agent 之间的协议,采用 Submission Queue / Event Queue 模式进行异步通信。

这个设计非常关键。Codex 不是同步函数调用:

answer = codex.ask(prompt)

而是更接近:

客户端提交 Op

Agent 异步处理

Agent 不断发出 Event

客户端根据 Event 更新 UI

Submission 结构包含:

  • id:用于关联提交和事件。
  • op:实际操作,例如用户输入、取消、配置更新等。
  • client_user_message_id:客户端侧用户消息 id。
  • trace:W3C trace 上下文,用于跨异步任务追踪。

Op 是“客户端要 Agent 做什么”,EventMsg 是“Agent 告诉客户端发生了什么”。这种设计有两个直接好处:

第一,UI 可以实时展示状态。模型推理、工具执行、shell 输出、补丁应用、审批请求、错误信息都可以变成事件流,而不是等所有事情结束才一次性返回。

第二,多入口可以复用同一套事件。TUI 可以把事件渲染成终端界面;exec --json 可以输出 JSONL;App Server 可以把事件转成 JSON-RPC 通知;测试可以捕获事件做断言。

可以用下面的简化类型帮助理解:

// 简化示例:真实源码里的类型更丰富
enum Op {
    UserTurn { input: Vec<UserInput> },
    Interrupt,
    ConfigureSession,
}

enum EventMsg {
    SessionConfigured,
    TurnStarted,
    AgentMessageDelta,
    ExecCommandBegin,
    ExecCommandOutputDelta,
    ApplyPatchApprovalRequest,
    TurnCompleted,
    Error,
}

对于初学者来说,只要记住一点:Codex 的 UI 不直接驱动模型细节,它通过协议提交请求并消费事件。协议层是 Codex 多端复用的基础。

3.2 会话层:Thread、Session、Turn 的关系

Codex 源码中逐渐用 Thread 替代早期的 Conversation 命名。一个 thread 可以理解为一次长期任务会话,里面包含多个 turn;每个 turn 是一次用户输入或自动推进触发的模型执行周期。

在 codex-rs/core/src/codex_thread.rs 中,CodexThread 是对底层 Codex session 的封装。它提供了:

  • submit:提交 Op
  • shutdown_and_wait:关闭会话。
  • steer_input:向运行中的 turn 注入用户输入。
  • inject_if_running:向当前活跃 turn 注入模型可见项目。
  • try_start_turn_if_idle:在线程空闲时启动自动 turn。
  • set_thread_memory_mode:设置线程是否适合后续记忆生成。

ThreadConfigSnapshot 则保存当前线程配置快照,包括:

  • 模型和模型提供商。
  • service tier。
  • approval policy。
  • permission profile。
  • workspace roots。
  • reasoning effort 和 summary。
  • personality。
  • collaboration mode。
  • multi-agent mode。
  • session source。

这说明 Codex 的 thread 不是“聊天记录”这么简单,它携带运行时配置、权限、工作目录、模型选择、协作模式和来源信息。这样的设计让 resume、fork、App Server、多代理协作成为可能。

再看 codex-rs/core/src/session/session.rsSession 保存当前 Agent 运行上下文:

  • thread_id:线程 id。
  • tx_event:向客户端发送事件。
  • agent_status:Agent 状态。
  • conversation:实时会话管理。
  • active_turn:当前活跃 turn。
  • input_queue:用户输入队列。
  • guardian_review_session:审查/审批相关会话。
  • services:模型客户端、MCP、插件、analytics、扩展等服务集合。

SessionConfiguration 则保存运行配置,例如 provider、collaboration mode、developer instructions、加载到的 AGENTS.md、base instructions、approval policy、permission profile、workspace roots、codex home、session source、dynamic tools 等。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐