

























如果你第一次打开 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 的工作方式:
flowchart TD A[用户输入任务] --> B[CLI/TUI/App Server 接收请求] B --> C[加载配置、权限、AGENTS.md、技能和插件] C --> D[构建模型可见上下文] D --> E[向模型发起 Responses API 请求] E --> F{模型输出什么} F -->|普通回复| G[记录消息并展示给用户] F -->|工具调用| H[ToolRouter 匹配工具] H --> I[审批与沙箱检查] I --> J[执行 shell、apply_patch、MCP、web、子代理等工具] J --> K[工具结果写回会话历史] K --> E G --> L[结束当前 turn]
这个循环是理解 Codex 的关键。传统 CLI 往往是“一条命令 -> 一个结果”,聊天机器人往往是“一段上下文 -> 一段文本”。Codex 则是“一段目标 -> 多轮推理 -> 多次工具调用 -> 状态更新 -> 最终交付”。它的源码复杂度主要来自三个方面:
exec、IDE/桌面 App、MCP Server、Cloud 任务等,所以需要稳定协议和分层架构。接下来进入源码层面的系统拆解。
简要介绍:codex-main 是一个多语言单仓库,外层 npm 包负责分发和启动,核心能力集中在 codex-rs Rust workspace。最重要的主线是:codex-cli/bin/codex.js 找到对应平台的原生二进制,Rust cli 解析命令,tui 或 exec 或 app-server 建立会话,core 运行 Agent 主循环,protocol 定义客户端与 Agent 之间的操作和事件,tools 负责把模型输出映射成真实工具调用,sandboxing 和权限系统负责限制风险。
很多初学者第一次理解 AI 编程工具时,会把它想成:
flowchart LR U[用户:帮我修 bug] --> P[程序:把问题发给模型] P --> M[模型:返回一段代码] M --> S[程序:显示代码]
这只是最早期的代码助手形态。Codex 源码展示的是更成熟的 Agent 形态:
flowchart LR U[用户:帮我修 bug] --> A[Codex:读取项目规则] A --> B[搜索相关文件] B --> C[运行测试] C --> D[分析失败] D --> E[修改代码] E --> F[再运行测试] F --> G[汇总结论]
这个过程中,模型需要不断“看见”外部世界。它不能只凭训练记忆回答,因为当前项目的代码、测试失败、用户本地环境、未提交变更、配置文件和工具输出都在实时变化。Codex 的核心价值就在于把这些外部信息纳入一个受控循环。
在 codex-rs/core/src/session/turn.rs 中,源码对 run_turn 的注释已经把核心机制讲得很清楚:每一次 sampling request,模型可能返回函数调用,也可能返回助手消息。如果返回工具调用,Codex 执行工具并把工具输出作为下一次请求的输入;如果返回普通助手消息,就记录进历史并认为当前 turn 完成。
也就是说,Codex 的“智能”不只是模型能力,还包括它周围的运行时能力:
ResponseInputItem。如果我们把 Codex 当成一个系统来观察,可以把它拆成五层:
flowchart TB U[用户入口层:CLI / TUI / exec / App Server / MCP Server] --> P[协议层:Op / Event / Thread / Turn] P --> C[核心层:Session / Turn / Context / ModelClient] C --> T[工具层:ToolRouter / ToolRegistry / ToolRuntime] T --> S[执行与安全层:sandbox / approval / permission profile] C --> M[模型与外部服务: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 展示、权限控制、配置读取、状态存储”塞进一个文件。它们变化频率不同,风险边界不同,测试方式也不同。
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,
});
这个设计有几个好处:
初学者可以把 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 宿主。
codex-rs/Cargo.toml 是理解源码组织的关键。它的 workspace members 非常多,包括 core、protocol、tui、exec、app-server、codex-api、codex-mcp、sandboxing、thread-store、core-skills、core-plugins、model-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 第一行开始硬啃。更好的阅读顺序是:
README.md,理解产品形态。codex-cli/bin/codex.js,理解 npm 入口只负责启动原生二进制。codex-rs/cli/src/main.rs,理解顶层子命令。codex-rs/protocol/src/protocol.rs,理解 Op 和 EventMsg。codex-rs/core/src/session/turn.rs 的 run_turn 注释和主循环。codex-rs/core/src/tools/spec_plan.rs 和 router.rs,理解工具如何注册与分发。codex-rs/core/src/exec.rs、safety.rs、sandboxing/src/lib.rs,理解执行安全。codex-rs/protocol/src/protocol.rs 的文件注释写明:它定义了 Codex session 中客户端与 Agent 之间的协议,采用 Submission Queue / Event Queue 模式进行异步通信。
这个设计非常关键。Codex 不是同步函数调用:
answer = codex.ask(prompt)
而是更接近:
flowchart LR A[客户端提交 Op] --> B[Agent 异步处理] B --> C[Agent 不断发出 Event] C --> D[客户端根据 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 多端复用的基础。
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 则保存当前线程配置快照,包括:
这说明 Codex 的 thread 不是“聊天记录”这么简单,它携带运行时配置、权限、工作目录、模型选择、协作模式和来源信息。这样的设计让 resume、fork、App Server、多代理协作成为可能。
再看 codex-rs/core/src/session/session.rs,Session 保存当前 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 等。
从这些结构可以看出 Codex 的状态模型:
flowchart LR Thread[Thread 长期会话] --> Session[Session 运行上下文] Session --> Turn1[Turn 1] Session --> Turn2[Turn 2] Session --> TurnN[Turn N] Session --> History[历史与 rollout] Session --> Config[配置快照] Session --> Services[模型/MCP/插件/技能/状态服务]
这种分层能解决一个实际问题:用户可能在一个任务里连续输入多次,也可能中断、恢复、fork,甚至让子代理执行子任务。如果没有清晰的 Thread/Session/Turn 边界,状态很快会乱。
run_turn:Codex 的核心循环codex-rs/core/src/session/turn.rs 是整套系统最核心的文件之一。它的 run_turn 做了很多事情,但可以拆成以下阶段:
第一阶段,准备模型客户端 session。ModelClientSession 是 turn 级别的对象,用于缓存 WebSocket 连接、sticky routing token 和前一次请求信息。源码注释强调:每个 turn 都要创建新的 ModelClientSession,不能跨 turn 复用,否则会把上一个 turn 的 sticky routing token 带到下一个 turn。
第二阶段,必要时执行 pre-sampling compact。上下文窗口有限,如果历史太长,Codex 会在采样前进行压缩,避免请求超过模型上下文限制。
第三阶段,记录上下文更新。Codex 会把当前工作目录、AGENTS.md、技能、插件、工具说明、用户输入等组织成模型可见内容。
第四阶段,构建技能和插件注入。build_skills_and_plugins 会根据用户显式提及、配置、可用技能、插件和连接器,决定哪些内容注入模型上下文。
第五阶段,运行 hooks 并记录输入。Codex 支持生命周期 hooks,例如 session start、pre tool use、post tool use、turn stop 等。这些 hook 可以为企业治理、日志、审批和上下文增强提供入口。
第六阶段,进入 loop。每轮循环会:
run_sampling_request。把这个主循环写成伪代码,大概是:
// 简化示例:用中文注释解释 Codex turn 的核心思想
async fn run_turn(input: Vec<TurnInput>) -> Result<Option<String>> {
// 1. 为当前 turn 创建模型会话,缓存本 turn 内的连接和路由状态
let mut client_session = model_client.new_session();
// 2. 如果上下文太长,先压缩历史,避免超过上下文窗口
run_pre_sampling_compact_if_needed().await?;
// 3. 注入 AGENTS.md、技能、插件、环境信息和用户输入
record_context_and_inputs(input).await?;
loop {
// 4. 把会话历史转换成模型请求
let request_input = history.for_prompt();
// 5. 向模型发请求,模型可能返回文本,也可能返回工具调用
let output = run_sampling_request(&mut client_session, request_input).await?;
// 6. 如果模型请求工具,执行工具并把结果写回历史
if output.needs_tool_follow_up {
execute_tools_and_record_outputs(output.tool_calls).await?;
continue;
}
// 7. 如果期间用户又输入了内容,继续循环处理
if has_pending_input().await {
continue;
}
// 8. 没有后续工作,当前 turn 结束
return Ok(output.last_agent_message);
}
}
这个循环体现了 Agent 与普通 LLM 应用的根本差异:模型不是一次性给答案,而是在“模型 -> 工具 -> 模型 -> 工具”的闭环里逐步完成任务。
flowchart LR A[模型推理] --> B{需要工具吗} B -->|需要| C[调用工具] C --> D[工具返回结果] D --> A B -->|不需要| E[输出最终回复]
codex-rs/core/src/client.rs 是 Codex 与模型提供商通信的重要封装。文件开头的注释非常有价值,它说明了几个设计点:
ModelClient 是 session 级别对象,保存稳定配置和状态,例如认证、provider 选择、conversation id、传输 fallback 状态。ModelClientSession 是 turn 级别对象,用于在一个 turn 内复用 Responses WebSocket 连接。源码里能看到一系列请求头和端点常量,例如:
X_CODEX_INSTALLATION_ID_HEADERX_CODEX_TURN_STATE_HEADERX_CODEX_TURN_METADATA_HEADERX_CODEX_PARENT_THREAD_ID_HEADERRESPONSES_ENDPOINT = "/responses"RESPONSES_COMPACT_ENDPOINT = "/responses/compact"这说明 Codex 不是简单地把 prompt 发给模型。它还维护安装 id、turn metadata、窗口 id、父线程 id、sticky routing 状态等工程信息。这些信息用于服务端路由、调试、指标、压缩、子代理关联和稳定性保障。
对初学者来说,可以这样理解:
sequenceDiagram participant Core as codex-core participant Client as ModelClientSession participant API as Responses API Core->>Client: 创建 turn 级会话 Client->>API: 可选 WebSocket prewarm Core->>Client: stream(request_input, tools, metadata) Client->>API: /responses 或 WebSocket 请求 API-->>Client: SSE/WebSocket 事件流 Client-->>Core: ResponseEvent Core->>Core: 解析文本、推理、工具调用
这种设计让 Codex 可以在交互式体验中边生成边展示,也可以在无交互模式中输出结构化 JSONL。
Agent 的关键能力不是会聊天,而是能安全地调用工具。Codex 的工具系统主要由几个文件构成:
codex-rs/core/src/tools/spec_plan.rs:决定当前 turn 暴露哪些工具。codex-rs/core/src/tools/router.rs:把模型输出转换成 ToolCall 并分发。codex-rs/core/src/tools/registry.rs:工具运行时接口、hook、telemetry 和输出转换。codex-rs/core/src/tools/parallel.rs:控制工具并行执行、取消和失败响应。codex-rs/core/src/tools/handlers/:内置工具 handler。handlers 目录列出了 Codex 的很多内置工具能力:
shell / unified_exec:执行 shell 命令。apply_patch:应用补丁。mcp:调用 MCP 工具。mcp_resource:列出和读取 MCP 资源。plan:更新计划。request_permissions:请求权限。request_user_input:请求用户输入。tool_search:搜索延迟加载工具。view_image:查看本地图像。current_time:读取当前时间。multi_agents / agent_jobs:多代理协作。new_context_window:开启新上下文窗口。list_available_plugins_to_install / request_plugin_install:插件发现与安装请求。ToolRouter::build_tool_call 会把模型输出中的 ResponseItem 转成内部 ToolCall。它处理三类主要工具调用:
FunctionCall:普通函数工具。ToolSearchCall:工具搜索。CustomToolCall:自定义工具调用。简化后可以理解为:
// 简化示例:把模型输出转换为 Codex 内部工具调用
fn build_tool_call(item: ResponseItem) -> Option<ToolCall> {
match item {
// 模型请求函数工具
ResponseItem::FunctionCall { name, arguments, call_id, .. } => {
Some(ToolCall {
tool_name: ToolName::plain(name),
call_id,
payload: ToolPayload::Function { arguments },
})
}
// 模型请求自定义工具
ResponseItem::CustomToolCall { name, input, call_id, .. } => {
Some(ToolCall {
tool_name: ToolName::plain(name),
call_id,
payload: ToolPayload::Custom { input },
})
}
// 普通消息不是工具调用
_ => None,
}
}
工具注册表 ToolRegistry 则保存工具名到 handler 的映射。每个 handler 实现统一接口,提供:
这让 Codex 可以做到“同一套工具协议,不同工具实现”。shell、patch、MCP、插件工具、动态工具都能通过统一的路由和执行框架运行。
codex-rs/core/src/tools/parallel.rs 处理工具并行执行。这里有一个工程细节值得学习:不是所有工具都能安全并行。比如两个只读查询工具可以并行,但两个写文件工具如果同时跑,可能互相覆盖。源码中的 ToolCallRuntime 会询问 router:这个工具是否支持并行。
它使用一个 RwLock:
这样多个并行安全工具可以同时运行,而互斥工具会串行执行。
伪代码如下:
// 简化示例:用读写锁控制工具并行
async fn dispatch_tool(call: ToolCall) {
let supports_parallel = router.tool_supports_parallel(&call);
if supports_parallel {
// 中文注释:并行安全工具共享读锁,可以同时执行
let _guard = parallel_execution.read().await;
router.dispatch(call).await;
} else {
// 中文注释:有副作用或不安全工具拿写锁,避免并发冲突
let _guard = parallel_execution.write().await;
router.dispatch(call).await;
}
}
同时,工具执行还需要支持取消。用户可能中断 turn,shell 命令可能超时,后台进程可能需要清理。ToolCallRuntime 使用 CancellationToken 和 AbortOnDropHandle 处理取消。如果工具被取消,它会返回一个模型可见的 aborted response,而不是让整个系统状态不明。
这也是 Agent 工程很容易被忽视的地方:工具调用不是函数调用那么纯粹。真实命令可能卡住、超时、输出巨大、产生子进程、修改文件、要求审批。Codex 在工具层做了大量工程防护。
Codex 有多个入口,但核心都汇聚到同一套 session/thread 机制。
交互式 TUI 在 codex-rs/tui/。tui/src/lib.rs 中可以看到大量 UI 模块:app、bottom_pane、chatwidget、history_cell、markdown_render、slash_command、status、token_usage、resume_picker 等。TUI 的职责是把协议事件渲染成用户能理解的终端界面,同时收集用户输入并发送到 App Server/Core。
无交互模式在 codex-rs/exec/。exec/src/lib.rs 文件顶部明确要求:
--json 模式下,stdout 必须是 JSONL,每行一个事件。这个要求非常工程化。因为 codex exec 很可能用于脚本、CI 或管道,如果 stdout 混入日志,就会破坏调用者解析。
App Server 在 codex-rs/app-server/,协议在 app-server-protocol/。v2 协议里有 ThreadStartParams、ThreadStartResponse、ThreadSettingsUpdateParams 等结构,说明它面向更复杂的宿主,例如桌面 App、IDE、远程控制和其他客户端。App Server 把 Codex 的能力封装成 JSON-RPC 风格接口,让前端或宿主不用直接链接 core 内部实现。
三者关系可以这样理解:
flowchart TD CLI[cli/src/main.rs] --> TUI[tui: 交互式终端] CLI --> EXEC[exec: 无交互任务] CLI --> APPSERVER[app-server: 宿主服务] TUI --> CORE[core: Agent 主循环] EXEC --> APPSERVER APPSERVER --> CORE CORE --> PROTOCOL[protocol: Op/Event/Model/Permission 类型]
这里有一个有趣细节:TUI 和 exec 都越来越多地复用 app-server client/in-process app server。这说明 Codex 正在把“运行一个 Agent thread”从具体 UI 中抽离出来,让不同客户端都通过稳定服务接口访问核心能力。
Codex 有两类重要协议:
第一类是 codex-rs/protocol,它是 core 内部会话协议,定义 Op、EventMsg、SandboxPolicy、AskForApproval、UserInput、ResponseItem 等核心类型。
第二类是 codex-rs/app-server-protocol,它面向 App Server 客户端,提供 v1/v2 JSON-RPC API,包含 thread、turn、permission、model、plugin、mcp、config、environment 等接口。
为什么要分两层?因为 core 内部协议更贴近 Agent 运行时,而 App Server 协议更贴近产品宿主。内部可以演进得更快,外部协议需要更稳定、更容易导出 schema、TypeScript 类型和实验字段控制。
在 app-server-protocol/src/protocol/v2/thread.rs 中,ThreadStartParams 包含很多宿主可传的配置:
modelmodel_providerservice_tiercwdruntime_workspace_rootsapproval_policyapprovals_reviewersandboxpermissionsconfigbase_instructionsdeveloper_instructionspersonalitymulti_agent_modeephemeralenvironmentsdynamic_toolsselected_capability_roots这说明 Codex 的外部 API 不是“传 prompt”那么简单,而是允许宿主完整控制运行环境、权限、模型和工具。
对于想设计自己 Agent 系统的人,这里有一个启发:如果你希望同一个 Agent 核心能服务 CLI、Web、IDE、桌面端和自动化任务,就应该尽早抽象协议边界,不要把 UI 操作直接写进核心逻辑。
codex-rs/core/src/config/mod.rs 是一个很大的文件,涉及配置加载、权限 profile、模型 provider、MCP server、插件、特性开关、Windows 沙箱、网络代理、认证存储、project doc 限制等。
Codex 的配置不是“读取一个 config.toml 然后用默认值补齐”。它需要合并多个配置层:
-c 覆盖。它还需要做约束检查。例如企业管理员可能限制某些权限或 hook,配置层必须知道某个值来自哪里,是否允许被更高优先级覆盖。
源码中可以看到 ConfigLayerStack、ConfigRequirements、Constrained、RequirementSource 等概念。这些都是为了把“配置”升级成“可追踪、可约束、可解释”的运行时输入。
一个简化的 config.toml 可能像这样:
# 示例:Codex 配置片段,真实字段以当前版本文档和源码为准
model = "gpt-5.2-codex"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[permissions]
# 中文注释:限制 Codex 默认只能写工作区,避免误改系统文件
default = "workspace-write"
[mcp_servers.docs]
# 中文注释:注册一个 MCP server,让 Codex 能读取外部文档资源
command = "node"
args = ["./mcp-docs-server.js"]
配置层的关键不是字段多少,而是“配置影响运行时行为”。比如:
approval_policy 会影响 shell 和 patch 是否需要用户确认。sandbox_mode 会影响文件系统和网络访问。model 会影响请求的模型和 reasoning 参数。codex-rs/core/src/agents_md.rs 专门处理 AGENTS.md 发现和用户指令拼装。文件注释说明了规则:
.git。AGENTS.md。AGENTS.override.md。project_doc_max_bytes 限制,默认来自 DEFAULT_PROJECT_DOC_MAX_BYTES。这个机制很重要,因为代码库里的约定通常比通用模型知识更可靠。比如:
just test,不要直接 cargo test。Codex 会把这些规则作为模型可见上下文注入,让模型在当前项目里“守规矩”。
一个典型 AGENTS.md 可以这样写:
# 项目协作规则
- 始终使用中文回复用户。
- 修改 Rust 代码后运行 `just fmt`。
- 涉及 `core` 行为变更时优先添加集成测试。
- 不要直接修改生成文件,先修改生成源。
- 代码注释保持简短,只解释关键逻辑。
从 Agent 设计角度看,AGENTS.md 是一种“仓库级长期提示词”,但它不是随便拼 prompt,而是有明确发现顺序、大小限制和来源记录。这比把所有规则硬编码在系统提示词里更灵活。
Codex 支持 skills 和 plugins。源码中相关模块包括:
codex-rs/core/src/skills.rscodex-rs/core-skills/codex-rs/skills/codex-rs/core-plugins/codex-rs/plugin/技能可以理解为可复用工作流。例如“创建 Word 文档”“处理电子表格”“控制浏览器”“生成图片”等。技能通常包含 SKILL.md,里面描述什么时候使用、如何使用、需要读取哪些参考文件、有哪些脚本或模板。
插件则更像一个可安装包,可以包含:
core-plugins/src/manifest.rs 会解析插件 manifest。源码里能看到 manifest 支持字段:
nameversiondescriptionkeywordsskillsmcpServersappshooksinterface一个简化插件 manifest 可以这样理解:
{
"name": "docs-helper",
"version": "0.1.0",
"description": "为项目文档提供检索和生成能力",
"skills": "./skills",
"mcpServers": "./mcp.json",
"hooks": "./hooks.toml",
"interface": {
"displayName": "Docs Helper",
"shortDescription": "项目文档助手"
}
}
技能与插件的区别可以这样记:
Codex 在每个 turn 里会根据用户提及、配置和可用技能,决定是否注入技能说明。maybe_emit_implicit_skill_invocation 还会根据命令和工作目录识别隐式技能调用,并上报 analytics。这个设计让技能不是“永远塞进上下文”,而是按需注入,减少 token 浪费。
MCP 是 Model Context Protocol 的缩写。Codex 源码中 codex-rs/core/src/mcp.rs 的 McpManager 负责把配置、插件和扩展贡献的 MCP server 合成运行时配置。
它支持几类来源:
McpManager::runtime_config 会应用内置兼容、插件注册和 runtime overlay,最终得到当前 session/thread 可用的 MCP 配置。effective_servers 还会结合认证状态做 gating。
MCP 对 Codex 很重要,因为它把 Agent 从“只能访问本地 shell 和文件”扩展到“可以访问外部授权数据和工具”。例如:
在工具层,Codex 有 mcp handler 和 mcp_resource handler,用于调用 MCP 工具、列出 MCP 资源、读取 MCP 资源模板等。模型看到的是统一工具接口,Codex 负责把调用转发到对应 MCP server。
一个简化 MCP server 配置可以这样写:
[mcp_servers.local_docs]
command = "node"
args = ["./tools/mcp-local-docs.js"]
# 中文注释:Codex 启动时会根据配置拉起该 server,并把可用工具暴露给模型
一旦 Agent 具备执行命令、修改文件、访问网络或调用外部工具的能力,它就不再只是“生成文本”的系统,而是在真实开发环境里产生副作用的执行主体。Codex 的安全机制不是单点实现,而是由配置、审批、权限 profile、沙箱和工具安全检查共同组成。
codex-rs/protocol/src/protocol.rs 定义了 AskForApproval、SandboxPolicy 等核心类型。SessionConfiguration 中保存 approval_policy、approvals_reviewer 和 permission_profile_state。工具执行前会根据当前策略决定:
codex-rs/core/src/safety.rs 的 assess_patch_safety 是一个很好的例子。它会判断 apply_patch 是否为空、审批策略是什么、补丁目标是否被限制在可写路径内、当前平台是否有可用沙箱、是否需要询问用户。如果补丁试图写出项目外,且策略不允许审批升级,就会拒绝。
简化逻辑如下:
// 简化示例:补丁安全判断
fn assess_patch_safety(action: Patch, policy: ApprovalPolicy, sandbox: SandboxPolicy) -> Decision {
if action.is_empty() {
return Decision::Reject("空补丁不能执行");
}
if action.only_writes_allowed_paths(&sandbox) {
// 中文注释:补丁只写允许路径,可以在沙箱中自动执行
return Decision::AutoApprove;
}
if policy.allows_user_approval() {
// 中文注释:风险较高但允许用户审批,交给用户决定
return Decision::AskUser;
}
// 中文注释:既不安全,也不能升级审批,直接拒绝
Decision::Reject("写入路径不被允许")
}
这个机制体现了一个重要原则:Agent 的默认能力应该受限,只有在策略允许时才扩大权限。尤其是写文件、联网、执行命令这些操作,不能完全交给模型自觉。
codex-rs/sandboxing/src/lib.rs 是跨平台沙箱抽象入口。它会根据平台导出不同实现:
sandboxing 模块提供:
SandboxManagerSandboxCommandSandboxExecRequestSandboxTypecompatibility_sandbox_policy_for_permission_profileget_platform_sandbox真正执行 shell 时,codex-rs/core/src/exec.rs 会先构建 ExecParams,再通过 build_exec_request 转成可执行请求,最终走 sandboxing::execute_env。ExecParams 包含命令、cwd、timeout/cancellation、环境变量、网络代理、sandbox permissions、Windows sandbox level、justification 等信息。
一个 shell 调用不是简单的:
Command::new("bash").arg("-lc").arg(cmd).output()
而是类似:
flowchart TD A[模型请求 shell] --> B[Codex 解析命令] B --> C[检查审批策略] C --> D[选择沙箱类型] D --> E[准备网络策略和文件系统权限] E --> F[启动子进程] F --> G[流式采集 stdout/stderr] G --> H{是否超时或取消} H -->|是| I[清理进程组] H -->|否| J[等待命令正常结束] I --> K[截断过大输出] J --> K K --> L[把结构化结果回传模型]
core/src/exec.rs 里还有很多细节:
DEFAULT_EXEC_COMMAND_TIMEOUT_MS 为 10 秒。这说明 Codex 对真实命令执行的复杂性有充分处理。很多自制 Agent demo 只调用 subprocess.run,一旦命令卡住、输出巨大或产生后台进程,就会出现不稳定行为。Codex 的实现更接近生产系统。
Codex 对不同工具采用不同安全策略。
对于 apply_patch,安全重点是路径约束:补丁是否只修改允许写入的路径?是否会写出项目外?当前平台能否 enforce sandbox?
对于 shell,安全重点更复杂:命令可能删除文件、联网、启动服务、写系统目录、泄露环境变量、执行无限循环。Codex 通过 shell command 解析、安全命令判断、审批策略、沙箱和输出限制共同控制风险。
对于 MCP,安全重点是外部授权和工具后果。某些 MCP 工具可能是只读资源查询,某些可能修改外部系统。Codex 需要根据工具暴露、审批模板和配置决定是否允许模型直接调用。
对于插件和 hooks,安全重点是来源和启用策略。企业环境可能只允许 managed hooks,避免用户或项目任意 hook 影响执行。
这也是为什么 Codex 源码中有大量“看起来不是 AI”的代码:权限、沙箱、配置、认证、持久化、事件、日志、测试。这些代码不是附属品,而是 Agent 产品可用的前提。
Codex 每次请求模型时,不是只发送用户输入。它会构建一个模型可见上下文,可能包含:
这些内容由 core/src/context/、context_manager/、session/turn.rs、skills.rs、plugins/ 等模块共同完成。
源码中的 AGENTS.md 贡献规则也体现了上下文预算思想:项目文档有最大字节数,超过会截断。AGENTS.md 不是越多越好,因为模型上下文窗口有限,太多规则会挤占真正任务内容。
Codex 的 AGENTS.md 中也强调模型可见上下文的工程要求:
这些规则非常适合所有 Agent 工程学习。上下文不是字符串拼接,而是有生命周期、预算、来源和结构的运行时数据。
Agent 执行复杂任务时,历史会越来越长。Codex 通过 compact 机制处理上下文窗口压力。
在 run_turn 中可以看到:
这类机制解决的是长期任务问题。比如用户让 Codex 分析一个大型代码库并修复多个测试,过程中可能产生几十次工具调用。如果每次都把完整历史塞给模型,很快超出上下文窗口;如果随意丢历史,模型又会忘记任务目标和已做决策。
压缩的目标不是“把历史变短”这么简单,而是保留决策相关信息:
可以把 compact 看成 Agent 的“工作记忆整理”。它决定长期任务能否可靠继续。
源码和项目规则都强调避免频繁改变模型可见上下文,因为这会影响 prompt cache。对于长上下文任务,缓存命中能显著降低延迟和成本。Codex 因此倾向于:
这对初学者可能有点抽象。可以类比浏览器缓存:如果网页静态资源 URL 每次都变,浏览器就没法缓存;如果 prompt 前缀每次都变,模型侧缓存也难命中。
因此,一个高质量 Agent 不只是“prompt 写得好”,还要“prompt 结构稳定”。
codex exec 做无交互代码审查codex exec 适合脚本和 CI 场景。它的关键特点是输出可控:默认 stdout 只输出最终消息,--json 输出 JSONL 事件流。
示例命令:
# 中文注释:让 Codex 无交互审查当前工作区改动
codex exec "请审查当前 git diff,找出可能的 bug、风险和缺失测试"
如果希望机器读取事件,可以使用 JSON 模式:
# 中文注释:JSONL 模式适合 CI 或上层系统解析
codex exec --json "运行测试并修复失败,如果需要修改文件请直接修改"
从源码角度看,这会走 codex-rs/exec/src/lib.rs。它会加载配置、解析 CLI 参数、创建 in-process app server/client,启动 thread/turn,并用不同 event processor 处理事件:
你可以把 codex exec 当成“可脚本化的 Codex Agent”。它和交互式 TUI 共享核心能力,但更适合自动化。
假设你的项目是 Rust 服务,要求所有修改必须格式化并运行特定测试。可以在仓库根目录创建:
# AGENTS.md
## 开发规则
- 始终使用中文回复。
- 修改 Rust 代码后运行 `just fmt`。
- 不要直接运行全量测试,除非用户要求;优先运行相关 crate 的测试。
- 修改 `core` 或协议类型时,必须说明兼容性影响。
- 生成代码要添加简短中文注释解释关键逻辑。
## 验证命令
- 格式化:`just fmt`
- core 测试:`just test -p codex-core`
- TUI 测试:`just test -p codex-tui`
Codex 会从项目根到当前目录收集 AGENTS.md。若子目录有更具体规则,它也会按路径顺序追加。比如:
repo/
├── AGENTS.md
└── crates/
└── api/
└── AGENTS.md
当 Codex 在 crates/api 下工作时,会看到根目录规则和 crates/api/AGENTS.md 的规则。这样不同子项目可以有局部约束。
如果你想让 Codex 访问一个本地知识库,可以写一个 MCP server。下面不是完整生产实现,只展示思想:
// mcp-local-notes.js
// 中文注释:这是极简示意,真实 MCP server 需要按 SDK 协议实现
const notes = {
"release-process": "发布前需要运行测试、更新 changelog、创建 tag。",
"deploy": "部署由 CI 自动完成,不要手动登录服务器修改文件。",
};
async function searchNotes(query) {
// 中文注释:根据关键词返回相关笔记
return Object.entries(notes)
.filter(([key, value]) => key.includes(query) || value.includes(query))
.map(([key, value]) => ({ key, value }));
}
// 中文注释:真实实现中,这里需要把 searchNotes 暴露为 MCP tool
在 Codex 配置中注册:
[mcp_servers.local_notes]
command = "node"
args = ["./mcp-local-notes.js"]
当 MCP server 正确实现协议后,Codex 可以在工具列表中看到它,并在需要时调用。这样你就能把企业内部知识库、项目文档、数据库查询、工单系统等接入 Codex。
Codex 的工具 handler 实际接口比较复杂,因为要支持 schema、暴露模式、hooks、telemetry、并行、取消等。我们用一个简化 Rust 示例表达核心思想:
// 中文注释:这是教学示例,不是 Codex 源码的完整接口
trait ToolRuntime {
fn name(&self) -> &'static str;
fn schema(&self) -> JsonSchema;
fn supports_parallel(&self) -> bool;
async fn handle(&self, input: serde_json::Value) -> ToolResult;
}
struct CurrentTimeTool;
impl ToolRuntime for CurrentTimeTool {
fn name(&self) -> &'static str {
"current_time"
}
fn schema(&self) -> JsonSchema {
// 中文注释:告诉模型这个工具需要什么参数
JsonSchema::object()
}
fn supports_parallel(&self) -> bool {
true
}
async fn handle(&self, _input: serde_json::Value) -> ToolResult {
// 中文注释:执行真实逻辑,并把结果转换成模型可读输出
ToolResult::text(chrono::Utc::now().to_rfc3339())
}
}
真实 Codex 的 CoreToolRuntime 做得更完整,还支持:
pre_tool_use_payloadpost_tool_use_payloadwith_updated_hook_inputtelemetry_tagscreate_diff_consumerwaits_for_runtime_cancellation这些能力让工具不只是“执行函数”,还可以被 hook 检查、被监控、被取消、被增量展示。
如果你想自己实现一个非常简化的 Codex-like Agent,可以从这个伪代码开始:
// 中文注释:教学版迷你 Agent,只保留核心循环
async fn mini_agent_loop(user_goal: String, tools: ToolRegistry) -> anyhow::Result<String> {
let mut history = Vec::new();
// 中文注释:记录用户目标
history.push(Message::user(user_goal));
loop {
// 中文注释:把历史和工具 schema 发给模型
let response = call_model(&history, tools.schemas()).await?;
match response {
ModelResponse::FinalText(text) => {
// 中文注释:模型给出最终答案,任务结束
history.push(Message::assistant(text.clone()));
return Ok(text);
}
ModelResponse::ToolCall(call) => {
// 中文注释:模型请求工具,先检查权限
if !is_allowed(&call) {
history.push(Message::tool_error(call.id, "权限不足"));
continue;
}
// 中文注释:执行工具,并把结果写回历史
let output = tools.dispatch(call).await;
history.push(Message::tool_output(output));
}
}
}
}
这个示例缺少大量生产能力:沙箱、审批、上下文压缩、并行控制、取消、事件流、持久化、MCP、插件、技能、认证、错误恢复。但它已经体现 Codex 的核心范式:模型负责决策,宿主负责执行和约束,结果再回到模型。
Codex 最直接的用途是本地开发助手。它能:
与传统代码补全相比,Codex 更适合跨文件、跨步骤任务。比如:
请分析这个项目的认证流程,找出 access token 过期后的刷新路径,并补充缺失测试。
这个任务需要阅读多个文件、理解调用链、修改测试、运行验证。它不是单行补全能解决的。
codex exec 让 Codex 可以进入脚本化场景:
因为 exec 模式严格区分 stdout/stderr,适合上层系统集成。
Codex 的 review 子命令和 guardian/review 相关模块说明它也面向审查场景。它可以帮助识别:
当然,AI 审查不能替代人工评审,尤其是安全、金融、隐私、生产事故相关变更。但它可以做第一轮扫描,让人工评审更聚焦。
源码中出现了 multi_agents、agent_jobs、agent-graph-store、external-agent-sessions 等模块,说明 Codex 正在支持更复杂的多代理协作。
多代理的典型价值是并行探索。例如一个大任务可以拆成:
这能减少等待时间,也能让不同上下文分开管理。但多代理也带来新问题:如何传递上下文、如何防止重复修改、如何合并结论、如何限制并发、如何避免子代理无限扩散。Codex 源码中有最大深度、最大并发、等待超时等配置,正是在处理这些工程风险。
通过 MCP、插件、skills 和 hooks,Codex 可以接入企业内部系统:
相比把所有数据复制进 prompt,MCP 让 Agent 按需访问资源;相比把所有逻辑写进核心,插件让能力可以独立发布和启用;相比把规则写在口头约定里,hooks 可以做机械化治理。
Codex 的 SQ/EQ 模式让 Agent 运行过程变成事件流。这对用户体验和调试都很重要。用户可以看到:
对开发者来说,事件流也利于测试。测试可以等待某个事件,而不是 sleep 固定时间。
源码中对输出 cap、I/O drain timeout、token budget、上下文大小、AGENTS.md 最大字节数都有明确限制。大型 Agent 最怕“无界”:
Codex 的实现处处体现“给每个入口加上边界”。
TUI、exec、App Server、MCP Server 都建立在相同 core 能力上。这避免了不同入口行为不一致。例如同样的审批策略、沙箱规则、工具执行、AGENTS.md 加载应该在所有入口一致生效。
Codex 不假设模型永远正确,也不假设用户希望 Agent 拥有无限权限。它通过 permission profile、sandbox、approval policy 和 tool hooks 让权限可控。
这对 AI 编程工具尤其重要。因为模型可能误判命令后果,例如执行 rm -rf、覆盖配置、安装未知依赖、访问网络等。安全系统的目标不是让 Agent 什么都不能做,而是让它在“可解释、可审批、可约束”的框架内做事。
MCP、插件、技能、hooks 都让 Codex 变得可扩展。但源码也显示,扩展不是无边界的。比如:
这说明成熟 Agent 平台必须同时提供“扩展能力”和“治理能力”。
过去的代码助手主要解决“写一段代码”。Codex 这类 Agent 更进一步,解决“完成一个工程任务”。工程任务通常包括:
未来的软件工程 Agent 会越来越像一个初级到中级工程师的工作台,而不是一个补全插件。
Codex 源码和 README 都显示它有本地 CLI、IDE、桌面 App 和 Codex Web/Cloud 等形态。未来很可能形成混合模式:
这对开发者意味着:AI 工具不会只存在于编辑器侧边栏,而会贯穿本地终端、CI、代码托管平台、知识库和云端执行环境。
当 Agent 能改代码、跑命令、访问内部系统后,企业一定会关注:
Codex 源码中的 telemetry、approval、permission profile、hooks、thread store、rollout trace 都是在为这些问题打基础。未来 Agent 平台的竞争,不只在模型能力,也在安全、审计、治理和可观测性。
单个 Agent 的上下文和时间有限。复杂任务天然适合拆分。多代理能带来并行收益,但也需要更好的协调机制。Codex 里已经有多代理工具、agent job、spawn/wait/send message 等能力。未来可能会看到:
今天我们写一个 Agent demo 很容易,但写一个可用的 Agent 产品很难。Codex 源码展示了平台化方向:
未来开发者可能不会从零写 Agent,而是在类似 Codex 的平台上写技能、插件、MCP server 和策略。
先不要急着读所有代码。建议按下面顺序:
README.md
codex-cli/bin/codex.js
codex-rs/Cargo.toml
codex-rs/cli/src/main.rs
codex-rs/protocol/src/protocol.rs
目标是回答:
重点读:
codex-rs/core/src/session/turn.rs
codex-rs/core/src/session/session.rs
codex-rs/core/src/codex_thread.rs
codex-rs/core/src/client.rs
目标是回答:
run_turn 做了哪些阶段?重点读:
codex-rs/core/src/tools/spec_plan.rs
codex-rs/core/src/tools/router.rs
codex-rs/core/src/tools/registry.rs
codex-rs/core/src/tools/parallel.rs
codex-rs/core/src/tools/handlers/
目标是回答:
重点读:
codex-rs/core/src/config/mod.rs
codex-rs/core/src/safety.rs
codex-rs/core/src/exec.rs
codex-rs/sandboxing/src/lib.rs
codex-rs/linux-sandbox/src/
codex-rs/windows-sandbox-rs/src/
目标是回答:
重点读:
codex-rs/core/src/agents_md.rs
codex-rs/core/src/skills.rs
codex-rs/core-skills/
codex-rs/core-plugins/src/manifest.rs
codex-rs/core/src/mcp.rs
codex-rs/codex-mcp/
目标是回答:
shell 是重要工具,但 Codex 还有 apply_patch、MCP、技能、插件、计划、权限请求、用户输入请求、图像查看、多代理等能力。shell 只是工具生态的一部分。
模型可以请求工具,但宿主会检查权限、沙箱、审批、工具暴露、并行策略和取消状态。真正执行权在 Codex runtime,不在模型文本本身。
AGENTS.md 是模型可见的项目规则文件。它会进入 Codex 上下文,影响模型行为。README 面向人类,AGENTS.md 面向 Agent 协作规范。
MCP 是连接外部工具和资源的协议。插件是可安装能力包,可能包含 MCP 配置、skills、hooks、apps 和界面元数据。二者可以组合使用。
上下文太多会浪费 token、降低关注重点、影响缓存命中,甚至触发压缩。高质量 Agent 需要精准注入上下文,而不是把所有东西都塞给模型。
Codex 源码最值得学习的地方,不是某一个神奇 prompt,也不是某一个复杂算法,而是它把“AI 编程助手”工程化成了一个完整 Agent 平台。
从 codex-main 可以看到一个清晰分层:
codex-cli 负责 npm 入口和平台二进制启动。cli 负责顶层命令分发。tui、exec、app-server 提供不同使用形态。protocol 定义核心操作和事件。core 负责 session、turn、上下文、模型请求和工具调度。tools 体系让模型能安全调用 shell、patch、MCP、计划、多代理等能力。sandboxing、safety、permissions、approval 确保 Agent 能做事但不乱做事。AGENTS.md、skills、plugins、MCP 让 Codex 适配不同项目和组织环境。thread-store、rollout、rollout-trace 支持持久化、恢复和调试。如果用一句话概括 Codex 的架构思想:
模型负责推理和决策,Codex runtime 负责上下文、工具、安全、状态和产品化体验。
这也是未来软件工程 Agent 的核心方向。真正可用的 Agent 不会只是一个大模型接口,而是一套把模型接入真实工程世界的运行时系统。它需要会读项目规则,会管理上下文,会安全执行命令,会请求审批,会连接外部工具,会记录历史,会恢复任务,会在不同入口提供一致能力。
对于初学者,建议不要一开始就陷入所有细节。先抓住主线:
flowchart LR A[用户输入] --> B[协议提交] B --> C[会话配置] C --> D[上下文构建] D --> E[模型请求] E --> F[工具调用] F --> G[安全执行] G --> H[结果回灌] H --> I{是否完成} I -->|否| D I -->|是| J[结束任务]
理解了这条主线,再看 core/src/session/turn.rs、tools/router.rs、tools/spec_plan.rs、core/src/client.rs、core/src/exec.rs、core/src/safety.rs,很多看似复杂的源码都会变得有章可循。
这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!
另外,博主出新书了《Hadoop与Spark大数据全景解析》、同时已出版的《深入理解Hive》、《Kafka并不难学》和《Hadoop大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。