第 16 讲:Unified Exec 统一执行运行时

Codex 源码解析 · 第 16 讲

Codex 源码解析系列 第 16 讲:Unified Exec 统一执行运行时 基于 OpenAI Codex 源码 · 2026-10-10 💡 本讲一句话: Codex 把"跑命令"从一次性动作升级成可复用的长命 PTY 会话——进程 ID、输出缓冲、yield 窗口、stdin 审批门,四件套如何协同管理一个可能活几分钟的后台进程。 一、为什么需要"统一执行" 第 15 讲我们看了 Tool Registry 如何把工具注册成模型可调用的 spec。但真正让 Codex"像人一样干活"的,是它执行命令的方式:不是跑完即弃的一次性 shell,而是一个 可以持续交互的 PTY 会话 ——模型先 exec_command 启动一个进程,拿到 process_id,之后随时 write_stdin 往里喂输入、再 poll 输出。这就是 unified_exec(统一执行)模块。 它要同时解决四个工程难题:① 进程可能比一次工具调用活得久,生命周期必须独立于 turn;② 输出可能无限大,必须有界缓冲;③ 模型需要"先看看再决定"的 yield 窗口;④ 往已打开的终端里写输入本身就是一种提权行为,必须过审批。源码全部在 codex-rs/core/src/unified_exec/ (约 5.8K 行)。 二、模块布局与关键常量 mod.rs 的模块头注释把职责写得很清楚:管理交互式进程(创建、复用、有界缓冲)、支持 completion-only 调用、用共享 ToolOrchestrator 统一处理审批/沙箱选择/重试。先看它定义的一组"游戏规则"常量: 📄 codex-rs/core/src/unified_exec/mod.rs (第 73-82 行) pub(crate) const MIN_YIELD_TIME_MS: u64 = 250; // yield 下限:防止模型传 0/极小值导致"启动即返回"的忙轮询 pub(crate) const WINDOWS_INITIAL_EXEC_YIELD_TIME_FLOOR_MS: u64 = 10_000; // Windows PTY 启动慢,首次执行强制至少等 10s pub(crate) const MIN_EMPTY_YIELD_TIME_MS: u64 = 5_000; // write_stdin 空输入(纯轮询)的最小等待:给进程反应时间 pub(crate) const MAX_YIELD_TIME_MS: u64 = 30_000; // yield 上限 30s:再长的命令就该转后台,别阻塞 turn pub(crate) const DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS: u64 = 300_000; // 后台终端默认最长存活 5 分钟 pub(crate) const DEFAULT_MAX_OUTPUT_TOKENS: usize = 10_000; // 工具响应体里输出快照的 token 预算 pub(crate) const UNIFIED_EXEC_OUTPUT_MAX_BYTES: usize = 1024 * 1024; // 转录缓冲总容量 1MiB:head+tail 共享 pub(crate) const MAX_UNIFIED_EXEC_PROCESSES: usize = 64; // 单会话最多同时挂 64 个长命进程,防资源耗尽 为什么这样设计: 这组常量暴露了 unified_exec 的核心哲学—— 把"执行命令"拆成两个时间尺度 :yield 窗口(250ms~30s)是模型"看一眼输出再决策"的短周期;后台存活上限(5min/64个进程)是资源治理的长周期。所有边界都显式 clamp,而不是信任模型传进来的参数——模型完全可能给出 yield_time_ms=0 或天文数字,常量层直接兜底。 三、process_id:随机分配 + 保留集合 每个长命进程需要一个模型可见的 ID(后续 write_stdin/terminate 都靠它寻址)。分配逻辑在 process_manager.rs: 📄 codex-rs/core/src/unified_exec/p…

阅读全文:Codex 源码解析 第 16 讲