设计不是功能清单
从公开实现看,Codex 的核心选择可以概括为:
让模型负责不确定的下一步决策,让本地 runtime 负责确定性的状态、工具、安全和观察。
这条边界贯穿 Context、Tool、Session 和 Event。它带来能力,也带来复杂度。
选择一:推理与行动分离
模型产生结构化 ToolCall,Rust runtime 执行。好处是:
- 可以校验参数;
- 可以统一插入审批与沙箱;
- 可以记录开始、输出和结束;
- 可以替换界面而复用核心。
代价是每种能力都需要 schema、handler、错误模型和事件设计。模型也可能选错工具或构造无效参数。
选择二:用事件连接核心与界面
Event 让 TUI、exec 和 App Server 观察同一过程,而不必窥探 Session 内部。流式命令输出和审批尤其受益。
代价是协议演进需要兼容;消费者必须正确处理顺序、增量、取消与遗漏。
选择三:Context 渐进构建
Codex 不预先索引并注入整个仓库,而是利用 Shell、文件读取等工具按需探索,再把观察放回历史。
优势:
- 适用于任意仓库与工具链;
- 信息来自当前磁盘,减少陈旧索引;
- 能围绕任务逐步收窄。
限制:
- 搜索策略取决于模型;
- 大仓库中可能耗时或遗漏;
- 工具输出噪声会挤占窗口;
- compaction 会有损。
选择四:Shell 作为通用适配层
复用 git、rg、语言工具链和项目脚本,使 Codex 无需为每个生态重写集成。它也是 CLI Agent 能迅速覆盖真实项目的原因之一。
代价是 Shell 语义广、跨平台复杂、输出不稳定,安全边界必须靠沙箱和审批补上。
选择五:Patch 作为一等修改表达
Patch 比任意脚本更容易审查、验证上下文和生成 diff,但它不擅长所有机械变换。大规模生成、格式化或 AST 迁移仍可能通过专用命令更合适。
flowchart LR M["模型自主性"] --- C["控制与审批"] S["Shell 通用性"] --- B["Sandbox 边界"] L["长任务能力"] --- X["Context 压缩损失"] E["事件细粒度"] --- P["协议复杂度"] A["本地环境真实性"] --- R["环境差异与风险"]
既要让 Agent 处理开放式工程任务,又不能把模型当成可信操作系统用户。
不确定决策与确定执行分层,每次副作用都经过协议、策略和事件边界。
局部可验证、可取消、可观察的行动比一次性生成完整方案更稳健。
run_turn + ContextManager + ToolOrchestrator + Op/Event 共同形成边界。
系统复杂,延迟高于补全;正确性依赖仓库测试与人类验收,无法消除模型错误。
优势:在哪些地方特别强
- 真实环境闭环:能直接消费编译器、测试和 Git 的反馈;
- 语言/框架中立:Shell 和项目脚本让它适应不同生态;
- 多表面复用:CLI、非交互与 App Server 共享核心概念;
- 控制面明确:审批、沙箱、指令和事件都有独立落点;
- 源码可审计:本地 runtime 的大量行为可从公开 Rust 代码验证。
限制:不要用产品叙事掩盖
模型仍会犯错
它可能修改错误层、写出只通过窄测试的实现,或把“命令成功”误当目标完成。
环境不一定可复现
缺失服务、凭据、平台差异和测试数据会让本地验证停在有限范围。
长任务会漂移
历史不断增长,压缩会损失细节;早期目标可能被后续错误带偏。
安全是系统属性
审批、沙箱、凭据管理、依赖安全和代码审查必须共同工作。任何一个“安全模式”都不是万能开关。
公开源码有边界
模型训练、托管推理基础设施、云任务调度等不在本仓库中。本文不会从客户端类型名推测未公开内部实现。
适用性判断
把任务放进四象限:
| 易验证 | 难验证 | |
|---|---|---|
| 可回滚 | 最适合自主执行 | 先澄清验收,保持小步 |
| 不可回滚 | 执行前人工确认 | 不应交给通用 Agent 自主完成 |
下一章用同一组架构轴比较 Claude Code、Aider、Cursor Agent 与 Agents SDK。