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/ |
选它的理由:
- 生产级:这是 OpenAI 真正发给用户的产品,不是教学 demo。每个设计决策都经过真实用户检验。
- 活跃:周级发版意味着它本身就是「生产级 agent 如何跟进模型能力演进」的活标本——你的信息雷达哨兵。
- 文档全:
docs/目录 + AGENTS.md + config 文档,可以「读文档理解设计,读代码验证理解」。
二、为什么先造后读(W3 的 nano-agent 是门票)¶
没有参照系的源码阅读 = 看热闹。有了 nano-agent,你带着这些问题进 Codex:
- 我卡过的地方(历史管理、停止条件、工具报错),生产级怎么解?
- 我没意识到的问题(审批粒度、上下文压缩时机),为什么他们要专门写一套?
「读懂了」的标准(对照自检):
- 能不看资料画出一次对话的完整数据流
- 能讲出 ≥3 个设计决策及其理由(「他们选了 X 而不是 Y,因为…」)
- 能回答本指南每一步的问题清单
- 能把至少一个机制移植进 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 |