本教程到这里拆完了 Codex 的十四个面。最后一章做三件事:把 Pi、dsh、Codex 三种哲学摆在一起;汇总前面散落的 26 条可迁移判断;说清楚哪些该抄、哪些不该。
三个 harness 其实在回答同一道题的不同问法:
| Pi | DeepSeek Harness | Codex | |
|---|---|---|---|
| 它在问什么 | 最少需要什么? | 最多能拆成什么? | 全都做完要付多少? |
| 它的答案 | 4 个包 | 185 个包 | 102 个 crate / 147 万行 |
| 优化目标 | 可读完、可改动 | 可替换 | 可验证、可交付 |
| 质量保证 | 代码少到能全读 | 接口契约 + 每包文档 | 14168 个测试 |
| 用户是谁 | 会读源码的开发者 | 要定制运行时的团队 | 任何人 |
| 你能改它吗 | 能,鼓励你改 | 能,改配置就行 | 基本不能 |
| 它给你的东西 | 一个骨架 | 一份能力接缝清单 | 一份工程总账单 |
这张表最右一列的"基本不能改"不是缺点。Codex 不是给你改的,是给你用的——就像你不会去改 Chrome 的渲染引擎,但你会读它的沙箱策略。
Pi 教程列出了三件刻意不做的事。看看另外两家怎么处理:
| Pi 不做的事 | Pi 的理由 | dsh | Codex |
|---|---|---|---|
| 子 Agent | 用 tmux 就行 | 四种委派机制 | 两代实现 + 密码学身份(第 14 章) |
| 权限弹窗 | "安全表演" | approval seam | 四档策略 + Starlark 规则 + 模型判官(第 11 章) |
| 计划模式 | 写 plan.md 就行 | dsh-plan-mode 插件 | 内置 plan 工具 + 计划流式渲染 |
Pi 的判断在它的定位下是对的。 一个给开发者改的 SDK,弹窗确实是负担;一个假设用户能对自己机器负责的工具,沙箱确实是过度设计。
差别在谁承担风险:
这决定了三者的全部差异,包括代码量。
前面十四章里,有五件事是另外两个 harness 没有的,值得单独列出来。
第 3 章的 SQ/EQ 双队列是 Codex 全部架构特征的原点:多前端、可远程、可嵌入、可测试、事件即日志。
代价也是真实的:所有人机交互变成往返消息(EventMsg 里 5 个"要东西"的变体 + Op 里 5 个回应变体)、协议版本冻结(task_started/turn_started 双标签)、一个 Session 只能跑一个 Task。
第 5、6 章:真正生效的系统提示词在 models-manager/models.json 里,随模型元数据远程下发,带 client_version 分版本。仓库里那 6 个 *_prompt.md 已经没人引用了。
这是"提示词工程"走向"提示词运维"的标志。 提示词有了版本、有了灰度、有了和模型能力的绑定关系。
第 11 章的 Guardian。8281 字节的 policy.md 是目前公开的 agent 项目里少见的东西——一份可评审、可版本控制、可针对性测试的 LLM 判官策略。
它的两个设计尤其值得记:二维判定(风险等级 × 用户授权)、一半篇幅在防误报。
第 10、11 章加起来是四级防线 + 三套操作系统沙箱实现。跨平台成本比 Windows 19852 : Linux 9694 : macOS 1036。
这个数据可以直接拿去做估算:给一个 CLI 工具加沙箱,Windows 那一份大概是 macOS 的 20 倍工作量。
第 14 章的 agent-identity(Ed25519 + Curve25519 + JWT)+ workload-identity + 存储中立的 agent-graph-store + 第 9 章的远程执行环境。
这几条线指向同一个方向:分布式的、有身份的、可跨机器编排的 agent 集群。 目前还看不出完整形态,但基础设施在铺。
按主题重排,★ 标记本教程认为最值得优先采纳的十条。
| # | 判断 | 章 |
|---|---|---|
| ★⑨ | 把环境状态当成可 diff 的结构化对象,每轮只把 diff(RFC 7386 merge patch)告诉模型 | 6 |
| ★⑧ | 每段注入的上下文带一对可识别标记 + 稳定分类 ID,便于事后剔除"哪些是系统注入的" | 6 |
| ★⑦ | 让"这个模型该被怎么提示"和"这个模型有什么能力"住在同一份可远程刷新的元数据里 | 5/6 |
| ⑪ | 把压缩写成"给下一个模型的交接"而不是"总结",并在压缩前后给出一致叙事 | 7 |
| ⑮ | 长输出截断头尾各留一半,并明确告诉模型省略了多少 | 9 |
| ⑫ | 来自模型训练分布的约束必须写成注释,否则会被"顺手优化掉" | 7 |
| # | 判断 | 章 |
|---|---|---|
| ★④ | 给每次模型请求冻结一份不可变的"世界视图"——广告出去的和实际执行的必须是同一份 | 4 |
| ★② | 长耗时操作统一用 Begin / Delta / End 三段式事件 | 3 |
| ③ | 把压缩、代码复核做成和普通对话平级的任务类型,而不是主循环里的 if 分支 | 4 |
| ⑤ | 会话级与轮次级的客户端状态分成两个类型,把跨界复用的后果写在类型定义上 | 5 |
| ㉑ | append-only 日志要配一个反向读取器 | 12 |
| # | 判断 | 章 |
|---|---|---|
| ★⑬ | 工具可见性不是布尔值:至少拆成"初始直出 / 可被检索 / 可代码化调用"三个维度 | 8 |
| ★⑭ | 需要模型产出结构化编辑时,设计一种"不数行号、靠内容定位、有明确边界"的格式,文法可放进提示词 | 8 |
| ⑯ | agent 的 shell 环境要么干净要么像用户,必须显式选一个 | 9 |
| ① | 把"以子进程方式调用自己"设计成显式的分发入口(arg0 技巧) | 2 |
| # | 判断 | 章 |
|---|---|---|
| ★⑲ | 让权限/安全规则的定义格式自带示例断言,并在加载时执行(execpolicy 的 match/not_match) | 11 |
| ★⑳ | LLM 判官的判定标准写成可读、可版本控制、可评审的策略文档,而不是提示词角落里的几句话 | 11 |
| ★㉓ | 区分「发现」和「启用」两个权限——仓库里的文件可以声明钩子,但启用必须在用户层,且内容哈希绑定 | 13 |
| ★㉖ | 委派权限单调收缩:子任务权限 ⊆ 父任务权限,无例外 | 14 |
| ⑩ | 安全策略要有两份表达(给代码执行的、给模型阅读的),且同源 | 6 |
| ⑰ | 安全相关的外部程序写死绝对路径,并在注释里声明威胁模型的边界 | 10 |
| ⑱ | 拦截必须可观测——只会拒绝不说理由的安全层,会让模型反复重试烧完预算 | 10 |
| # | 判断 | 章 |
|---|---|---|
| ★㉕ | 多 agent 系统里"主 agent 派活之后该干什么"必须显式规定,否则它两边都做 | 14 |
| ㉒ | 兼容别人的配置格式时只在"输入匹配"层兼容,不让别人的命名渗进自己的输出契约 | 13 |
| ㉔ | 内部扩展平面要诚实命名("Contributor" 而不是 "Plugin"),传达"只能加不能换" | 13 |
| ⑥ | 模型差异从第一天就设计成配置而不是 match model_name 分支 | 5 |
这条单独拿出来,因为它在本教程里出现了至少五次:
| 场景 | 自由的部分 | 硬性上限 |
|---|---|---|
| 模型重试(第 5 章) | provider 可配 stream_max_retries | hard cap,配不过天花板 |
| 自动压缩(第 5 章) | 用户可配 auto_compact_token_limit | 取 min(用户值, 窗口 90%) |
| Guardian(第 11 章) | 模型自由判断风险 | 连续拒绝 3 次熔断本轮 |
| Guardian 上下文(第 11 章) | 转录内容由模型决定 | 每一档都有独立 token 上限 |
| 多 agent(第 14 章) | 提示词鼓励"尽可能每步派一个" | AgentRegistry 限制累计总数 |
模式是:把"做什么"交给策略(可能是用户配置,也可能是模型判断),把"最多做多少"写死在代码里。
这解决的是同一类问题:任何交给模型或用户的自由度,都需要一个它们够不到的兜底。 模型会陷入循环、用户会配错数值——上限是唯一不会失效的防线。
如果本章只带走一条 就带这条。它不需要你抄任何 Codex 的代码,只需要你在每次给出一个"可配置"或"由模型决定"的旋钮时,问一句:这个旋钮的最坏情况是什么?谁来兜?
诚实地列四条。
第 5 章的 WireApi 只有一个变体,是因为 Codex 是 OpenAI 的产品。如果你的产品需要接多家模型,这就是错误示范。
但要抄它背后的认知:"支持所有模型"意味着你只能用到所有 API 的交集能力。做这个决定时要清楚自己放弃了什么。
147 万行、102 个 crate、14168 个测试,对应的是"每天几百万人用"和"跑在别人机器上执行任意命令"这两个前提。
如果你的 agent 跑在自己的服务器上、用户是内部同事,沙箱、四级审批、跨平台适配这些成本大部分可以省掉。Pi 的答案对你可能更合适。
ext/ 的 12 个 Contributor 是 Codex 自己用的,外部只能走五条受限通道。这个不对称对一个开源产品是合理的(他们要控制质量和安全边界),但对一个你希望社区参与的框架就是毒药。
dsh 的做法(对内对外同一套 seam)在那个语境下更对。
Codex 敢做四种压缩实现、六档工具可见性、三套沙箱,是因为有 14168 个测试兜着。同样的复杂度放在一个没有测试的项目里,就是一堆没人敢改的代码。
复杂度的准入条件是可验证性。这是第 2 章讲的"拆成 102 个 crate 是为了独立编译和测试"那句话的另一面。
这一节是本教程的落地部分。
Codex 的 SKILL.md 和本仓用的是同一套 frontmatter(name + description),且都有"禁止模型自主调用"的机制(Codex 的 allow_implicit_invocation: false ≈ 本仓的 disable-model-invocation: true)。
可以直接借鉴的:
第 13 章那条"项目层可以发现钩子,但无权启用"直接适用于本仓:
Codex 的两道防线——权限分离 + trusted_hash 内容绑定——是现成的答案。
第 11 章的 execpolicy match / not_match 加载时断言,对本仓的 permissions 列表直接适用。现在的 Bash(git *) 这类模式,写错了没有任何反馈,只能等到被拦或没被拦时才发现。
第 12 章末尾的引申:本仓的 sessions/(Codescope 问答留存)和 GBrain/(研究摘要留存)与 Codex 的 rollout 解决的是同一类需求——agent 的价值有相当一部分在它跑过的过程里,不只在最终答案里。
差别在粒度和消费者:Codex 存给机器分析,本仓存给 GBrain 检索和人阅读。两者可以互相借鉴——比如本仓的 sessions/ 目前只记 Q&A,不记"为什么问这个""中间试错了什么"。
诚实列出盲区,供后续补充:
| 没讲 | 在哪 | 为什么跳过 |
|---|---|---|
| TUI 的 27 万行 | tui/ | 终端渲染,和 agent 架构无关 |
| 实时语音会话 | core/src/realtime_conversation.rs 等 | 独立子系统,值得单独一篇 |
| 云端任务 | cloud-tasks* | 需要服务端配合才能验证 |
| 遥测与分析 | otel / analytics | 8121 + 13720 行,工程价值高但不影响架构理解 |
| 登录与认证 | login / chatgpt / aws-auth | 16041 行,产品化细节 |
| Code Mode 的 V8 细节 | code-mode-runtime | 只讲了它在工具系统里的位置 |
| 网络代理的实现 | network-proxy(18491 行) | 只讲了它的定位 |
| Bazel 构建 | bazel/ / *.bazel | CI 基础设施 |
另外三个天然盲区(第 1 章提过):
本教程从"147 万行"这个数字开始,到这里可以给它一个更准确的解读:
它不是一个 agent 架构的复杂度,是一个 agent 产品的完整账单。
Pi 问"最少需要什么",答案是四个包;dsh 问"最多能拆成什么",答案是 185 个可替换位置;Codex 问"全都做完要付多少",答案摆在那里,每一行都能查证。
三个答案都对。你的项目该站在哪个位置,取决于你的用户是谁、风险由谁承担。
而不管你站在哪,这份账单都有用——它告诉你,你现在欠着哪些账。