Responses WebSocket 协议详解:为什么它会让 Agent 工作流更快
WebSocket”。这个理解不算错但也不够准确。真正关键的点在于Responses WebSocket 优化的不是单次文本生成本身而是多轮、工具密集、长链路 Agent 工作流里的 continuation 成本。本文主要Daniel Vaughan 那篇文章讲的是Codex app-server 的 WebSocket 远程控制协议本文真正聚焦的是OpenAI Responses WebSocket 协议。两者都使用 WebSocket但不是同一个应用层协议。先说结论先给出这篇文章最重要的结论Responses WebSocket 的价值不是“流式输出更酷”而是“多轮工具回路更轻”。OpenAI 官方明确提到对于20 次 tool call 的 rolloutWebSocket mode端到端最多可带来约 40% 的速度提升。首 TokenTTFT通常也会更快但官方没有公开给出单独的百分比官方只明确说明了低延迟 continuation 路径和generate: falsewarmup 机制。Routin.ai 已经支持 OpenAI-compatible 的 Responses WebSocket 路径。从实际可用的 Codex CLI provider 配置可以直接看出这一点。RoutinAI 是一个企业级统一的 LLM API 网关提供一个单一且类型安全的接口访问来自 GPT、Claude 和 Gemini 系列的超过 100 个领先大语言模型例如 gpt-5.4、claude-opus-4-6、gemini-3.1-pro-preview等更多模型。它通过提供零延迟的边缘路由、无需改动代码即可无缝切换模型、统一计费以及以支出上限和访问策略进行集中治理消除了管理多个 AI 供应商的复杂性。如果只用一句话概括Responses WebSocket 不是为了替代 HTTP Streaming 的“表现形式”而是为了降低 Agent 连续多轮执行时的控制面延迟。Daniel Vaughan 那篇文章和本文到底是什么关系Daniel Vaughan 的文章讨论的是Codex CLI app-server底层是一个 JSON-RPC 2.0 风格服务既支持 stdio也支持 WebSocket目标是把 Codex 从本地 CLI 变成可远程接入、可重连、可 headless 部署的 agent runtime这说明了一件很重要的事当 Agent 从单机命令行工具演进为远程、长任务、可协作的系统时长连接会越来越重要。但 Daniel 文中的 WebSocket承载的是客户端与 app-server 之间的 JSON-RPC 控制协议远程 TUI、审批、线程恢复、状态同步而 OpenAI 官方文档中的 WebSocket承载的是客户端与/v1/responses之间的模型交互协议response.create请求response.output_text.delta这类流式事件基于previous_response_id的低延迟 continuation所以最准确的理解方式是Codex app-server WebSocket上层 agent runtime 的远程控制协议Responses WebSocket底层模型 API 的长连接 continuation 协议两者方向一致但分工完全不同。第一层WebSocket 协议本身在做什么在讲 OpenAI 的应用层协议之前先把 WebSocket 自身讲清楚。1. 它不是一个独立于 HTTP 的全新握手协议WebSocket 的建立过程大致分为四步建立 TCP 连接如果是wss://再建立 TLS 会话发起一次 HTTP Upgrade 请求服务端返回101 Switching Protocols连接升级为 WebSocket典型握手请求大致如下GET /v1/responses HTTP/1.1 Host: api.openai.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Version: 13 Sec-WebSocket-Key: random_base64 Authorization: Bearer OPENAI_API_KEY服务端接受升级后会返回HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: server_hash其中Sec-WebSocket-Accept是服务端根据客户端的Sec-WebSocket-Key加上固定 magic GUID 计算出来的摘要值用来证明这不是普通 HTTP 响应而是真正的 WebSocket 升级响应。2. 建立成功后通信不再是 HTTP 请求/响应而是帧frame连接升级后双方发送的就不是 HTTP body 了而是 WebSocket 帧。常见 opcode 如下Opcode含义0x1文本帧text0x2二进制帧binary0x8关闭连接close0x9Ping0xAPongOpenAI 的 Responses WebSocket 在实际使用中一条业务消息通常就是一个 JSON 文本消息也就是承载在 text frame 里。3. WebSocket 的几个关键特征全双工客户端和服务端都可以主动发送消息而不需要等待对方先发起请求。长连接建立一次连接后可以连续发送很多轮业务事件不必每一轮都重新发起 HTTP 请求。心跳与保活协议内建ping/pong机制适合长任务、长连接场景下做连接探活。显式关闭通信结束时可以通过 close frame 做比较干净的关闭流程而不是粗暴断开 TCP。4. 一个容易被忽略的细节客户端帧要 mask按照 WebSocket 标准客户端发给服务端的帧必须带 masking服务端发给客户端的帧通常不 mask这件事通常由 WebSocket 库自动处理但从协议层理解它很重要WebSocket 不是“纯裸 TCP JSON 流”它本身是有严格帧格式和控制语义的标准协议。第二层OpenAI Responses WebSocket 的应用层协议理解了 WebSocket 本体之后再来看 OpenAI 在这条连接上定义的应用层语义。1. 连接地址与鉴权官方文档给出的接入点是wss://api.openai.com/v1/responses鉴权方式仍然是标准 Bearer TokenAuthorization: Bearer OPENAI_API_KEY2. 客户端不是发 HTTP POST而是在 socket 上发送事件WebSocket mode 下客户端通过发送response.create事件来发起一次 Responses 请求。一个最小示例大致如下{ type: response.create, model: gpt-5.4, store: false, input: [ { type: message, role: user, content: [ { type: input_text, text: Find fizz_buzz() } ] } ], tools: [] }它和普通POST /responses的请求体非常接近但有一个关键差异WebSocket mode 不使用streamWebSocket mode 不使用background因为流式能力本身已经由 WebSocket 连接承载了。3. 服务端返回的是一串 Responses streaming eventsOpenAI 明确说明WebSocket mode 的服务端事件与现有 Responses streaming event model 保持一致。也就是说WebSocket 只替换了传输方式没有重新发明一套新的流式事件语义。最常见的一组事件包括response.createdresponse.in_progressresponse.output_item.addedresponse.content_part.addedresponse.output_text.deltaresponse.output_text.doneresponse.output_item.doneresponse.completederror如果是工具调用场景还会看到类似事件response.function_call_arguments.deltaresponse.function_call_arguments.doneresponse.mcp_call_arguments.deltaresponse.mcp_call_arguments.doneresponse.file_search_call.in_progressresponse.web_search_call.searching4. 为什么这些事件很重要因为 Responses API 从一开始就不是“只产出一段文本”的接口它的输出是一个output item 流里面可能包含assistant messagefunction callmcp callshell callreasoning summaryrefusalfile search / web search 等 hosted tool 输出所以更准确的说法不是“模型在输出 token”而是模型在一个统一的事件流里逐步产出文本、工具调用、工具结果状态与最终完成信号。5.sequence_number的意义每个服务端事件都带有sequence_number。这意味着客户端可以按顺序消费事件即使前端内部有异步 UI 渲染也能根据序号恢复正确顺序对调试和事件回放很有帮助这也是 Responses WebSocket 比“手搓文本流协议”更工程化的地方。一个完整的 Responses WebSocket 工作流长什么样1. 普通单轮生成OpenAIClientOpenAIClientWebSocket connect (wss://api.openai.com/v1/responses)response.createresponse.createdresponse.in_progressresponse.output_item.addedresponse.content_part.addedresponse.output_text.deltaresponse.output_text.doneresponse.output_item.doneresponse.completed2. 带工具调用的 Agent 回路真正能体现 WebSocket 价值的是下面这种多轮工具回路OpenAIClientOpenAIClientresponse.create(input, tools)response.created / in_progressfunction_call_arguments.deltafunction_call_arguments.done本地执行工具response.create(previous_response_id, function_call_output)response.in_progressresponse.output_text.deltaresponse.completed这里最关键的一点是第二轮 continuation 并不是把整段历史重发一遍。你只需要发送previous_response_id新增的inputitems例如{ type: response.create, model: gpt-5.4, store: false, previous_response_id: resp_123, input: [ { type: function_call_output, call_id: call_123, output: tool result }, { type: message, role: user, content: [ { type: input_text, text: Now optimize it. } ] } ], tools: [] }为什么它比 HTTP SSE 更适合 Agent如果只是单轮问答HTTP SSE 已经足够好用。但 Agent 工作流和单轮问答完全不是一个问题。HTTP SSE 的优势接入简单浏览器和后端生态成熟单次流式输出体验好但 Agent 工作流天然更偏向双向、连续、低开销典型 Agent 回路通常是模型输出中间解释模型发起工具调用客户端执行工具客户端把工具输出回传给模型模型继续下一轮如有需要继续重复多次这时问题就来了SSE 擅长的是服务端单向下行流Agent 需要的是客户端与服务端双向持续交换事件continuation 次数一多HTTP 请求边界本身就会变成额外延迟来源所以WebSocket 更适合 Agent不是因为它“更先进”而是因为它更符合 Agent 的通信形态。性能提升到底来自哪里OpenAI 官方文档把逻辑写得很清楚核心可以归结为三层。1. 长连接减少每轮 continuation 的固定开销如果使用 HTTP每一次工具回传都需要重新进入一次请求生命周期发起 HTTP 请求附带请求头重新过一遍请求分发重新解析 continuation 请求WebSocket 模式下连接已经建立完成直接在活跃连接上继续发送response.create即可。这类开销单看一次不大但在多轮工具回路中会反复出现。2. 只发送增量输入而不是重复发送整段历史在 WebSocket mode 下continuation 的方式是previous_response_id 上一轮 response idinput 仅新增 items这意味着你不需要在每一轮都重发整段上下文。直接收益包括更少的请求序列化成本更小的网络传输体积更少的服务端输入解析成本3. 活跃连接上存在 connection-local 的最近响应缓存这是官方文档里最关键的一点之一。OpenAI 明确说明在活跃 WebSocket 连接上服务端会把最近一次 previous response state保存在connection-local in-memory cache中如果你继续的是这一次最近 response服务端可以直接复用这份内存态上下文这带来的收益非常直接continuation 不必每一轮都从更慢的持久化状态恢复路径出发而是可以命中连接内的低延迟路径。官方给出的量化收益20 Tool Calls 最多约 40% 提速这是目前官方最明确的一条公开性能数字对于 20 次以上工具调用的 rolloutWebSocket mode 端到端最多可带来约 40% 的速度提升。这条数字为什么合理因为在工具密集场景里真正占时间的不只是模型推理还包括continuation 请求建立历史上下文重传response state 恢复每轮串行控制流的固定管理成本当这些固定成本在 20 轮中反复出现时WebSocket 的收益会被明显放大。哪些场景收益最大coding agentorchestration loop多次 function calling多次 shell / MCP / hosted tools 往返哪些场景收益不会特别夸张一次性问答单轮短回答没有工具调用没有 continuation所以不要把这 40% 简化成“所有请求都更快 40%”。更准确的说法是越像 Agent收益越大。首 Token 为什么通常也会更快这里需要讲得严谨一点。可以明确说的部分首 TokenTTFTTime To First Token通常更快主要不是因为模型本身突然“每秒解码更快”而是因为控制面延迟降低了。具体来源包括少了一次新的 HTTP continuation 开销少了大历史 payload 的上传与解析命中连接内最近 response 的内存缓存可以使用generate: false进行 warmupgenerate: false是什么OpenAI 文档明确提到客户端可以先发送一条{ type: response.create, model: gpt-5.4, generate: false, tools: [...], instructions: ..., input: [...] }它不会直接返回模型输出但会预热 request state返回一个 response ID让后续真正要生成的那一轮可以更快开始这个机制对即将进入复杂工具回路的请求尤其有价值。但不能过度宣传的部分官方没有公开给出 TTFT 的单独提升百分比。因此最稳妥的技术表述应该是Responses WebSocket 往往能够改善首 Token 延迟尤其是在 continuation turn、工具密集工作流和 warmup 之后的下一轮生成阶段但 OpenAI 官方目前公开量化的数据主要是 20 tool calls 场景下端到端最多约 40% 的提速而不是单独的 TTFT 百分比。重要但容易被误解的一点更快不等于更省 Token 费用previous_response_id能让 continuation 更轻、更快但这不意味着计费时只算新增输入。OpenAI 在 Conversation State 文档里明确说明即便使用previous_response_id链路中之前的输入 token 在计费上仍然会作为 input tokens 参与统计。所以要把两个概念分开传输与调度成本WebSocket 会优化上下文 token 计费不会因为你只发送增量 items 就自动变成“只付增量 token”这是架构设计时必须知道的边界。工程限制与边界条件WebSocket mode 很强但它不是“无限制银弹”。1. 单连接只有一个 in-flight response官方明确说明一个 WebSocket 连接上可以收到多个response.create但它们是顺序执行的当前不支持 multiplexing这意味着如果你需要并行跑多个独立任务就应该建多条 WebSocket 连接而不是把并发期待建立在一条连接上2. 连接时长限制为 60 分钟到达上限时会返回类似错误websocket_connection_limit_reached因此生产环境必须做好reconnectcontinuation recovery长任务分段续跑3.storefalse与 ZDR 是兼容的这点很重要因为它直接决定了合规与性能是否能兼得。OpenAI 明确写道WebSocket mode 与storefalse兼容也与 Zero Data Retention 兼容原因在于最近响应状态只保留在连接本地内存里不写入磁盘。4. 但storefalse更依赖活跃连接如果你使用storefalse并且连接断了或者引用的previous_response_id已经不在连接本地缓存里那么就没有持久化回退路径了可能会收到previous_response_not_found所以最准确的工程总结是storefalse WebSocket可以很快也更利于隐私与 ZDR但它更依赖“连接还活着、最近状态仍在缓存里”。5. 失败会驱逐缓存官方还提到如果某一轮 continuation 失败4xx 或 5xx服务端会把这次引用的previous_response_id从连接本地缓存中驱逐这样做是为了避免后续继续复用一份已经可能不一致的缓存状态。Compaction 在 WebSocket 模式下怎么理解长链路 Agent 不可避免会遇到上下文膨胀因此 compaction 是配套机制而不是可选附属功能。OpenAI 文档把它分成两种情况。1. 服务端 compactioncontext_management如果你开启服务端 compaction例如配置compact_threshold仍然按正常方式继续发送response.create仍然使用最新的previous_response_id仍然只发送新增 input items也就是说对调用方来说continuation 模式不变。2. 独立POST /responses/compact这个接口返回的是一个新的 compacted input window而不是一个新的 response id所以 compact 完成后你需要在 WebSocket 上开启一条新的 response chain把 compacted output 当作新的input此时可以省略previous_response_id或显式设为null这说明 WebSocket mode 并不是“上下文无限长永远不用管”而是和 compaction 机制一起工作。Codex app-server WebSocket 为什么值得被拿来做对照回到 Daniel Vaughan 那篇文章它的真正价值在于它展示了 Agent 产品形态正在如何变化。从文章可以看到Codex app-server 正在走向远程接入轻客户端 / 重服务端可重连可审批可 headless 部署用 WebSocket 做长连接控制通道这与 Responses WebSocket 的关系并不是“同一个协议”而是前者解决 agent runtime 的远程控制问题后者解决模型 API 的低延迟 continuation 问题也正因为这两层同时成立现代 coding agent 才能真的做到前端很轻模型与工具回路很长任务中断后可恢复远程服务端持续运行Routin.ai 已经支持 Responses WebSocket 路径这一点不需要猜直接看你提供的 Codex CLI 配置就很清楚model gpt-5.4 model_provider meteor-ai disable_response_storage true approval_policy never sandbox_mode danger-full-access model_supports_reasoning_summaries true rmcp_client true model_reasoning_effort xhigh personality pragmatic service_tier fast [model_providers.meteor-ai] name meteor-ai base_url https://api.routin.ai/v1 env_key OPENAI_API_KEY wire_api responses supports_websockets true requires_openai_auth true [features] unified_exec true shell_snapshot true steer true skills true powershell_utf8 true collaboration_modes true fast_mode true multi_agent true responses_websockets_v2 true这段配置至少说明了四件事1.wire_api responses说明它走的是Responses 协议栈而不是旧的 Chat Completions 兼容层。2.supports_websockets true说明这个 provider 支持Responses over WebSocket。3.base_url https://api.routin.ai/v1说明 Routin.ai 暴露的是 OpenAI-compatible API 基址。4.responses_websockets_v2 true这是Codex CLI 侧的功能开关说明当前这条链路已经启用了它所期待的新版 Responses WebSocket 集成能力。需要注意的是