Codex 源码解析 · 第 10 讲
Codex 源码解析系列 第 10 讲:Agent Loop / Turn 执行循环 基于 OpenAI Codex 源码 · 2026-10-04 💡 本讲一句话: Codex 的 agent loop 不是"while 循环里调模型"这么简单——它是一个 三层嵌套的状态机 :外层 run_turn 管"要不要再来一轮",中层 run_sampling_request 管"这次请求失败能不能重试",内层 SSE 事件循环管"流里每个 item 怎么分发"。工具调用被做成 挂起的 future 按序收集,用户中途插话(steer)有专门的排空时机控制。读完你会明白一个生产级 agent loop 的骨架长什么样。 一、先建立地图:一个 turn 里到底有几层循环 前几讲我们把 Session / TurnContext / StepContext(第 8 讲)和系统提示词组装(第 9 讲)拆完了。这一讲进入 agent loop 本体: 用户输入进来之后,模型、工具、harness 是怎么一轮轮"对话"下去的? 源码里这条链路横跨两个文件:主循环在 core/src/session/turn.rs (3039 行),流事件分发在 core/src/stream_events_utils.rs 。骨架是三层嵌套: 🔹 外层 run_turn(L163) :turn 级循环——每轮采样后决定"继续 / 压缩后再来 / Stop hook 拦截 / 结束" 🔹 中层 run_sampling_request(L1538) :请求级重试状态机——流断了、可恢复错误,按 provider 配置的重试上限恢复 🔹 内层 try_run_sampling_request(L2409) :SSE 事件消费循环——逐事件分发,工具调用挂成 future,直到 response.completed 先看外层入口。run_turn 的文档注释把整个 agent loop 的契约写得很直白: 📄 codex-rs/core/src/session/turn.rs (第 149-170 行) /// Takes initial turn input and runs a loop where, at each sampling request, // 文档注释:run_turn 拿到本轮输入后进入循环,每次采样请求模型要么要工具、要么回消息 /// the model replies with either: // ——回复只有两种形态 /// - requested function calls // 形态一:函数调用(harness 执行完把结果喂回去) /// - an assistant message // 形态二:助手消息(记入历史,本轮结束) pub(crate) async fn run_turn( // Turn 的执行入口:一个 turn = "用户输入 → 模型/工具多轮往返 → 最终回复" sess: Arc<Session>, // 会话本体(共享状态、事件总线、input_queue),Arc 因为要跨任务传递 turn_context: Arc<TurnContext>, // 本轮上下文快照:配置、审批策略、provider、sub_id mut input: Vec<TurnInput>, // 用户输入列表(文本/图片/@提及等);mut 因为 guardian 路径会改写它 mcp_startup_requirements: &mut McpStartupRequirements, // MCP 启动需求跨 turn 保留:显式 @ 的 server/plugin 必须拉起 prewarmed_client_session: Option<ModelClientSession>, // 预热好的模型会话(缓存 WebSocket/粘性路由),没有就新建 cancellation_token: CancellationToken, // 取消令牌:用户中断时所有 await 点都能快速退出 ) -> CodexResult<Option<String>> { // 返回本轮最后一条助手消息;None = 被 hook 拦截或…
阅读全文:Codex 源码解析 第 10 讲