启动预热不仅做 TCP/WebSocket 握手,还发送一份 generate=false 的完整 Responses 请求并等待 Completed。成功后的连接、请求基线和 Response ID 可以被首个真实 Turn 消费;失败则不阻断 Session。
具体问题与启用条件
本节聚焦 startup prewarm 的构造、超时和交接。普通增量请求判断在 5.10,previous response 生命周期在 5.11。
| 条件来源 | 决定字段或状态 | 对本机制的影响 |
|---|---|---|
| Provider/Session | Responses WebSocket enabled | 调度完整预热 |
| 无 WebSocket | 仅 auth prewarm | 不构建工具和 warmup request |
| 首个 Regular Turn | 消费 startup handle | 获得 Ready/Unavailable/Cancelled |
协议、类型与状态所有权
| 状态或协议 | 所有者 | 生命周期 | 关键不变量 |
|---|---|---|---|
| Startup handle | Session | 启动到首个 Regular Turn | AbortOnDrop 且只消费一次 |
| 预热 Turn/StepContext | 预热任务 | 任务内 | 使用真实模型与工具快照 |
| 预热 ModelClientSession | 预热任务→首 Turn | 交接后属于 Turn | 保留连接与 last response |
| 预热 inference trace | 禁用 trace | 预热请求 | 不冒充真实模型推理 |
机制调用链如下:
Session 初始化
→ 若 WS 可用则 spawn startup prewarm
→ 创建 startup TurnContext/StepContext 与 ToolRouter
→ 用空 Input 构造真实 Prompt
→ response.create(generate=false)
→ 等待 Completed
→ 首 Turn 在剩余超时内 resolve
→ 交接预热 ModelClientSession
机制怎样工作
预热发生在 run_turn 之前,因此必须自行捕获 StepContext、构建工具 Router,并用 Base Instructions、工具规格和空 Input 构造 Prompt。metadata 的 request kind 标为 Prewarm。prewarm_websocket 发送 response.create,将 generate 设为 false,并一直读到 Completed;这样 last request 和 last response receiver 都已建立。
首个 Regular Turn 解析 handle 时,超时不是从“开始等待”重新计时,而是用总预热 timeout 减去任务年龄,避免一个已经拖很久的启动任务再占用完整等待窗口。取消会 abort task;失败、join failure、超时都成为 Unavailable,正常 Turn 另行建连。若预热看到 426,它会直接激活 HTTP 回退,首 Turn 不再重复 WebSocket 握手。
Python 风格伪代码
这段伪代码保留生产实现中会改变结果的状态、分支和异步边界;认证 SDK、遥测字段和 Rust 所有权样板被折叠为明确的领域对象。
async def startup_prewarm(session: Session) -> ModelTurnSession:
turn = await session.make_startup_turn()
step = await session.capture_step_context(turn, CancellationToken())
prompt = build_prompt(input=[], tools=step.router.visible_specs,
instructions=session.base_instructions)
client = session.model_client.new_turn_session()
stream = await client.websocket_stream(prompt, generate=False, kind="prewarm")
async for event in stream:
if isinstance(event, Completed):
return client
raise StreamError("prewarm ended without completed")
async def consume_prewarm(handle: PrewarmHandle, turn_cancel: asyncio.Event):
remaining = max(0.0, handle.timeout - handle.age())
try:
return await wait_task_or_cancel(handle.task, remaining, turn_cancel)
except (TimeoutError, Exception):
handle.task.cancel()
return None # 正常 Turn 继续
失败、取消与恢复
| 故障或边界 | 已发生的状态 | 对上层的结果 | 能否直接重试 | 恢复动作 |
|---|---|---|---|---|
| 预热超时 | 任务可能部分建连 | Unavailable | 正常 Turn 可重试 | abort 预热任务 |
| 首 Turn 取消 | handle 尚未交接 | Cancelled | 否 | abort 并结束 Turn |
| 预热流错误 | 连接/基线不可信 | Unavailable | 是 | 正常请求重新建立 |
| HTTP 426 | Session 已禁 WS | 预热视为可继续 | 不再试 WS | 首 Turn 直接 SSE |
设计取舍与验证
发送 generate=false 比仅握手更贵,但能预先验证请求方言、工具 payload 和服务端状态,并为 previous response 建立基线。它增加启动并发任务和工具构建成本,所以被设计为尽力优化而不是正确性前置条件。禁用 inference trace 防止回放把预热误认为一次用户采样。
| 可验证契约 | 证据方式 | 预期结果 |
|---|---|---|
| 预热请求带 generate=false | 捕获首个 WS frame | 请求包含完整逻辑字段且不生成回答 |
| 预热 426 使首 Turn 直接 HTTP | fallback 集成测试 | 只有一次 WS 握手 |
| 预热失败不阻断 Turn | 让 warmup 失败后提供正常响应 | Turn 仍完成 |
Mini Codex 对照
Mini Codex 可先实现“仅握手”版本,但它不能声称支持预热 Response ID 复用。完整版本应返回同一个 Turn session,并用总 deadline 而不是第二个独立超时。
本节边界
预热已交给首 Turn。下一节说明何时可把完整请求压缩成 previous_response_id 加 Input delta。
评论
登录后即可评论