Codex Field GuideSOURCE EDITION · 2026.07源码 ↗
04 · ACTION LAYER

Tool、Shell 与 Patch

模型只提出结构化意图;Router、Registry、Orchestrator 和 Handler 才把它变成受策略约束的真实动作。

Tool 是模型与现实之间的协议

模型输出的是“调用某个工具,参数如下”;它并没有任意 Rust 函数指针,也不直接拥有 Shell。Runtime 先把工具规格发给模型,再校验返回的名字和参数,最后选择实现。

DIAGRAMTool 调用链
flowchart LR
A["Model output item"] --> B["stream_events_utils<br/>识别 ToolCall"]
B --> C["ToolRouter<br/>解析 payload"]
C --> D["ToolRegistry<br/>选择 handler + hooks"]
D --> E["ToolOrchestrator<br/>approval + sandbox"]
E --> F{"Handler"}
F --> G["Shell / Unified exec"]
F --> H["Apply patch"]
F --> I["MCP / collaboration / other"]
G --> J["Tool output"]
H --> J
I --> J
J --> K["ContextManager"]
统一调用链让审批、沙箱、遥测、事件和错误格式不必散落在每个工具里。
01解决什么

让概率模型操作确定性系统,同时保持参数可校验、行为可观察、权限可控制。

02如何工作

模型可见 schema → 结构化 ToolCall → 路由 → 策略编排 → handler → 结构化结果。

03为何这样设计

能力和策略解耦后,可增加工具而不复制一套安全与事件逻辑。

04源码落点

router.rs、registry.rs、orchestrator.rs 形成主干,handlers/ 提供具体能力。

05取舍与失败

schema 不能保证意图正确;工具过宽会放大风险,工具过窄又会限制任务。

Shell:通用但锋利

Shell 的优势是覆盖面:搜索、读取、测试、构建、Git、项目脚本都能复用现有命令。代价同样明显:

  • 命令字符串存在注入和引用风险;
  • 一个命令可能读写大量状态;
  • 跨平台行为不同;
  • 长输出会挤占 Context;
  • 后台进程和交互式程序需要生命周期管理。

Codex 源码同时包含 Shell handler、统一执行工具以及工具规格。执行仍要经过审批和沙箱策略。

Patch:把修改表达为数据

sed -i 或任意脚本写文件相比,Patch 有几个工程优势:

  • 明确列出增加、删除、修改的文件;
  • 上下文不匹配时可以拒绝,而不是静默改错;
  • 适合展示和审查;
  • 工具 schema 可以约束格式;
  • 更容易在写入前做路径检查。

Codex 的 apply_patch 是 freeform 工具:模型提交一段符合特定 grammar 的 patch 文本。实现会解析、校验,然后应用。

示意:模型看到的边界

*** Begin Patch
*** Update File: src/retry.ts
@@
-const limit = 2;
+const limit = 3;
*** End Patch

语法示意 这段只演示工具格式,并非官方仓库中的真实修改。

Orchestrator:策略真正生效的地方

工具 handler 不应自己随意决定“是否可以绕过沙箱”。ToolOrchestrator::run 把流程统一为:

  1. 根据工具与策略判断是否需要批准;
  2. 等待批准或得到拒绝;
  3. 在选定沙箱中进行第一次尝试;
  4. 若策略允许并且失败确实与沙箱有关,再走升级路径;
  5. 返回可供模型继续判断的结果。

工具结果怎样回到模型

结果不能只写终端。它需要被编码成模型协议中的 tool output,并与原始 call id 对应。这样模型才能知道:

  • 哪个动作完成了;
  • 标准输出与错误是什么;
  • 是否超时或被拒绝;
  • 文件改变了什么;
  • 下一步应重试、修复还是结束。

设计一个好工具

最小检查表:

维度 问题
输入 schema 是否足够窄,错误参数能否尽早拒绝?
权限 读、写、网络、进程各需要什么边界?
输出 是否结构化、限长,并保留恢复所需信息?
幂等性 重试会不会重复创建或破坏状态?
观察性 是否产生开始、完成、失败事件?
取消 长任务能否中断和清理?

接下来把单个工具放回更大的运行时对象模型:Runtime 与 Session

ESC
没有匹配章节。试试 “Context” 或 “Approval”。