Codex 源码解析 · 第 12 讲
Codex 源码解析系列 第 12 讲:LLM Client 与 Responses API 流式通信 基于 OpenAI Codex 源码 · 2026-10-06 💡 本讲一句话: Codex 每次向模型要答案,背后都跑着一条"WebSocket 优先、HTTP/SSE 兜底"的流式管道——本讲逐行拆这条管道的四个关键件:传输分发(client.rs)、SSE 解析与错误分类(codex-api/sse/responses.rs)、事件桥接与遥测(map_response_events)、以及三级重试状态机(responses_retry.rs),读完你能说清"断线重连、降级 HTTP、限流退避"分别是谁在什么时机做的。 一、stream():一个入口,两种传输 第 10 讲我们看过 Agent Loop 怎么驱动一轮对话,但"把 prompt 发给模型、把 token 流式收回来"这件事发生在更底层。入口就是 ModelClientSession::stream() ——它先问 provider 支持哪种 wire API,再决定走 WebSocket 还是 HTTP/SSE。 📄 codex-rs/core/src/client.rs (第 1961-2030 行) pub async fn stream( // 对外唯一入口:一次模型请求,返回事件流 &mut self, // 会话级客户端(持有 WebSocket 连接状态),可变借用因为要改传输状态 prompt: &Prompt, // 本轮完整提示词(含历史 + 工具结果) model_info: &ModelInfo, // 模型元信息:slug、是否支持 WS、重试上限等 session_telemetry: &SessionTelemetry, // 会话级遥测句柄,后面每个分支都要打点 effort: Option<ReasoningEffortConfig>, // 推理强度(可选),透传给模型侧 summary: ReasoningSummaryConfig, // 是否要推理摘要 service_tier: Option<String>, // 服务等级(如 priority),影响路由与计费 responses_metadata: &CodexResponsesMetadata, // turn_id/session_id/thread_id 等元数据 inference_trace: &InferenceTraceContext, // rollout trace 上下文,显式传入避免传输分支各写一套 ) -> Result<ResponseStream> { // 统一返回事件流,调用方不关心底层是 WS 还是 HTTP let wire_api = self.client.state.provider.info().wire_api; // 从 provider 配置读协议类型(Responses/Chat) match wire_api { // 目前只有 Responses 一种走这条路径 WireApi::Responses => { // 进入 Responses API 分支 if self.client.responses_websocket_enabled() { // WS 开关:provider 支持 && 本会话没被降级过 let request_trace = current_span_w3c_trace_context(); // 抓当前 W3C trace 上下文,跨传输传递链路 ID match self // 先尝试 WebSocket 传输 .stream_responses_websocket( // WS 路径:连接复用 + 增量 delta(第五节细讲) prompt, model_info, session_telemetry, effort.clone(), summary, // 参数原样透传 …
阅读全文:Codex 源码解析 第 12 讲