跳转至

Codex 源码研读指南

使用时间:W5(初遇)–W7(精读)。本指南回答四个问题:为什么选它、怎么读、读什么、怎么记。 前置阅读:W6 动手前先读《深入理解 AI Agent》第 5 章 Coding Agent(见 resources.md 中文体系化教材),建立生产级 Coding Agent 的全景认知。

一、为什么选 Codex 当解剖标本

事实卡(2026-09-02 抓取自 github.com/openai/codex):

事实 数据
许可证 Apache-2.0(可自由阅读、引用、魔改)
语言构成 Rust 96.6%,Python 2.7%,TS/Shell/PowerShell 少量
仓库规模 10,000+ commits,601 位贡献者,周级发版(v0.15x)
核心目录 codex-rs/(Rust 内核,核心所在)、docs/、sdk/、codex-cli/

选它的理由:

  1. 生产级:这是 OpenAI 真正发给用户的产品,不是教学 demo。每个设计决策都经过真实用户检验。
  2. 活跃:周级发版意味着它本身就是「生产级 agent 如何跟进模型能力演进」的活标本——你的信息雷达哨兵。
  3. 文档全:docs/ 目录 + AGENTS.md + config 文档,可以「读文档理解设计,读代码验证理解」。

二、为什么先造后读(W3 的 nano-agent 是门票)

没有参照系的源码阅读 = 看热闹。有了 nano-agent,你带着这些问题进 Codex:

  • 我卡过的地方(历史管理、停止条件、工具报错),生产级怎么解?
  • 我没意识到的问题(审批粒度、上下文压缩时机),为什么他们要专门写一套?

「读懂了」的标准(对照自检):

  1. 能不看资料画出一次对话的完整数据流
  2. 能讲出 ≥3 个设计决策及其理由(「他们选了 X 而不是 Y,因为…」)
  3. 能回答本指南每一步的问题清单
  4. 能把至少一个机制移植进 nano-agent

三、阅读策略:读设计,不逐行

Codex 96.6% 是 Rust,不要求会写 Rust,只要求能读——第六节给了一份「读码最小集」。

阅读顺序原则:文档 → 目录结构 → 数据结构 → 控制流。永远先找「数据长什么样」(struct/enum 定义),再找「流程怎么走」。Rust 代码当地图用,迷路了就退回文档层。

工具:GitHub 网页端即可起步(目录浏览 + 搜索);进阶装 ripgrep 本地 clone 后全文搜索(找系统提示词这种藏在深处的字符串,rg "You are" 一发命中)。本地 clone 只读不改,跟踪上游用 git pull。

四、六步阅读路径与问题清单

第 1 步:README + docs/ 全览(W6,1h)

读 github.com/openai/codex 的 README 与 docs/ 目录(install、config、contributing 等)。

带着问题:

  • Codex 的产品形态有哪些(CLI / IDE / 云端)?为什么 CLI 是开源主体?
  • 配置体系给了用户哪些决策(model、approval、sandbox…)?哪些坚决不给用户配?——配置面 = 产品对「用户需要控制什么」的回答
  • 文档里出现的安全模型(approval/sandbox 相关)怎么向普通用户解释?

第 2 步:AGENTS.md(W6,0.5h)

仓库根目录的 AGENTS.md——OpenAI 告诉 AI agent「在我这个仓库里怎么干活」的规范。

带着问题:

  • 这份文件约束了哪些行为?哪 3 条最关键?
  • 它本身就是 prompt 工程范例:结构、语气、禁止事项的写法,跟你的 nano-agent 系统提示词比差在哪?
  • 「用 agent 开发 agent」的流程透露了他们对 agent 能力边界的哪些判断?

第 3 步:codex-rs 工作区地图(W6,1h)

读 codex-rs/Cargo.toml 的 workspace members,列出每个 crate 的一句话职责。重点 crate(名称随版本可能调整,以实际目录为准):

  • core:会话、循环、prompt、工具定义——精读主战场
  • exec:命令执行与沙箱/审批
  • tui:终端界面
  • apply-patch:模型用「代码即行动」方式改文件的补丁机制
  • protocol / sdk:对外协议与 TS SDK

带着问题:

  • 画出 crate 依赖关系图:谁在最底层?为什么 tui 和 core 必须分离?
  • 为什么 apply-patch 值得独立成 crate?
  • 如果你用 Python 重写,模块会怎么划分?跟它的划分异同?

第 4 步:core——会话与循环(W6,1.5h)

带着问题:

  • 一个 turn 从用户输入到工具执行再到回复,经过哪些核心类型/函数?
  • 事件(event)如何从 core 流出到 UI?为什么用事件流而不是直接调用?
  • 停止条件有哪几种?与你 W3 的设计对比
  • 消息历史的数据结构长什么样?角色有哪几种?

第 5 步:prompt 构造与工具定义(W6,1.5h)

用 rg 搜系统提示词(搜 "You are Codex" 或类似开头),找到 prompt 模板文件。

带着问题:

  • 系统提示词分几段?每段在防什么问题(跑偏/越权/低质量输出…)?
  • 工具 schema 的 description 写作风格与你的差异?——直接抄一个好机制回 nano-agent
  • 哪些信息是动态注入的(工作目录、git 状态…)?为什么放系统提示词而不是用户消息?

第 6 步:exec/沙箱、压缩、持久化(W7,4h)

带着问题:

  • 审批分级怎么定义(读文件/执行命令/写文件各自的粒度)?为什么这么分?
  • 沙箱方案怎么选(平台差异如何处理)?
  • 上下文压缩(auto-compact)何时触发?保留什么、丢什么?压缩后的会话还「记得」什么?
  • 会话持久化(rollout/JSONL)为什么这样设计?重放怎么做?

五、笔记模板(每篇源码笔记都用它)

# Codex 源码笔记 N:主题
日期 / 阅读的文件路径 / 花费时间

## 事实(我看到了什么)
数据结构、流程、代码位置(带文件路径)

## 设计决策与理由(我认为为什么这么设计)
≥3 条。格式:他们选了 X 而不是 Y,因为 Z。
(不确定就标 [猜测],下次读到相关代码回来验证)

## 与我的实现对照
nano-agent 怎么做的 / Codex 怎么做的 / 差距的本质是什么

## 可借鉴进 nano-agent
具体到改哪个文件哪个函数

## 未解问题
(下一轮阅读或求助讨论区的清单)

六、Rust 读码最小集(不学写,只学读)

Rust 概念 一句话翻译 Python 大致对应
let x = ...; / let mut x 绑定变量 / 可变绑定 x = ...(mut ≈ 显式声明我要改它)
match x { A => ..., B => ... } 按模式分支 match/switch,但能解构数据
enum 可带数据的 tagged union 一个类带个类型标签 + 各类型字段
Result<T, E> + ? 显式错误传递 try/except 的类型化版本;? ≈ 出错就提前 return
Option<T> 可能为空 T | None
async fn + .await 异步函数与等待点 async def + await
#[derive(Serialize)] 自动生成 JSON 转换代码 @dataclass + to_dict
mod / use / pub 模块/导入/可见性 import + 公私有别(默认私有)
impl X for Y 给类型实现接口 类的方法定义,支持事后扩展

读不懂某段时:先看类型签名(函数名 + 参数 + 返回值),跳过泛型细节;再找这个函数被谁调用(自顶向下定位它的角色)。10 分钟仍卡住 → 记入「未解问题」,继续前进。

七、上游跟踪(信息雷达的一环)

  • Releases:每周日雷达扫描时看一眼;值得关注的条目记进 learning-log 雷达区,月度汇总进 ROADMAP 行业变化日志
  • Changelog:功能演进的官方叙事
  • Discussions:设计讨论的一手现场,比代码更能看懂「为什么」
  • 长期目标(阶段 4):从这里挑一个小 issue/文档 PR,完成第一个开源贡献

八、里程碑对齐

周 本指南进度
W5 黑盒观察(不读码,跑 CLI 记录行为)
W6 完成 1–5 步 + 2 篇笔记 + 抄一个机制
W7 完成第 6 步 + 2 篇笔记 + 移植一个机制进 v0.4
阶段 4 持续跟踪 releases,沉淀解读;争取第一个 PR