高级 API 用法
WebSocket 模式
Responses API 可以通过一个持久的 WebSocket 连接到 /v1/responses 来驱动,而不是为每个轮次都打开一个新的 HTTP 请求。在第一次响应之后,后续轮次只需要发送新的输入项以及一个 previous_response_id — 服务器会在开放的套接字中将先前状态保存在内存中。
这适用于零数据保留(ZDR)和 store=false,因为关于续期的内容不需要接触持久存储。
适用场景
WebSocket 模式针对具有许多连续工具调用的代理工作负载 — 编码代理、编排循环、任何与模型来回交互数十次的场景。
每个轮次都跳过连接设置,只发送新的输入而不是完整的对话内容,这在长期运行中会累积优势。在我们对具有大量工具调用的代理工作负载的内部基准测试中,与使用相同 previous_response_id 链接的重复 HTTP 请求相比,我们测量到端到端延迟降低了约 20%。
打开连接并发送第一轮
WebSocket 升级成功后,每个轮次都由客户端发送 response.create 消息来启动。正文形状与 Responses 创建请求正文 相同,但不包括仅传输相关的字段,如 stream 和 background(响应始终作为套接字上的事件流式返回)。
import json
import os
from websocket import create_connection
ws = create_connection(
"wss://api.x.ai/v1/responses",
header=[
f"Authorization: Bearer {os.environ['XAI_API_KEY']}",
],
)
ws.send(
json.dumps(
{
"type": "response.create",
"model": "grok-4.5",
"store": False,
"input": [
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "Find fizz_buzz()"}],
}
],
"tools": [],
}
)
)import WebSocket from "ws";
const ws = new WebSocket("wss://api.x.ai/v1/responses", {
headers: {
Authorization: \`Bearer \${process.env.XAI_API_KEY}\`,
},
});
ws.on("open", () => {
ws.send(
JSON.stringify({
type: "response.create",
model: "grok-4.5",
store: false,
input: [
{
type: "message",
role: "user",
content: [{ type: "input_text", text: "Find fizz_buzz()" }],
},
],
tools: [],
})
);
});
ws.on("message", (data) => {
console.log(JSON.parse(data.toString()));
});使用 generate: false 进行预热
如果您已经知道下一轮所需的工具、指令或系统消息,可以通过发送带有 generate: false 的 response.create 来预先连接。服务器准备请求状态但不运行模型 — 不返回任何输出。预热仍然会发出一个响应 ID,您可以通过 previous_response_id 从该 ID 链接后续内容,这样实际的生成轮次可以更快开始。
继续运行
对于每个后续轮次,发送一个新的 response.create 并包含:
previous_response_id— 此链上最后一个响应的 ID。input— 仅此轮的新内容(通常是工具输出加上下一个用户消息)。不要重新发送先前历史;服务器已有这些内容。
ws.send(
json.dumps(
{
"type": "response.create",
"model": "grok-4.5",
"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": [],
}
)
)ws.send(
JSON.stringify({
type: "response.create",
model: "grok-4.5",
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: [],
})
);链接在套接字上的工作方式
previous_response_id 的行为方式与在 HTTP 上相同,但 WebSocket 路径有一个额外的内存快捷方式。每个开放的连接在其每连接缓存中保存其最新响应的状态。从该响应继续运行完全不需要访问存储,这就是为什么 WebSocket 模式可以安全地与 store=false 和 ZDR 一起使用。
如果您引用一个不再在连接缓存中的旧 previous_response_id:
- 使用
store=true时,服务器可能会从持久状态中重新加载它,但您会失去内存延迟优势。 - 使用
store=false或在 ZDR 下,没有可回退的存储可读取,轮次会因previous_response_not_found而失败。
失败的轮次(4xx 或 5xx)会将其 previous_response_id 从连接缓存中驱逐,这样重试不会从损坏的状态继续。
连接限制和行为
- 事件类型和顺序与现有的 Responses 流式传输格式相同。
- 一个连接按顺序处理轮次 — 在一个轮次进行中发送第二个
response.create将排队,而不是多路复用。 - 需要并行轮次?打开多个连接。
- 单个连接可以保持开启状态最多 25 分钟。之后,服务器会关闭它,您需要重新连接。
重新连接
当套接字断开(网络波动、部署、达到 25 分钟上限)时,打开一个新连接并选择适用的恢复路径:
- 如果您使用了
store=true并且仍然有有效的响应 ID,只需在新套接字上使用previous_response_id和新的输入项继续。 - 否则(例如
store=false或遇到previous_response_not_found),完全删除previous_response_id并通过发送下一轮的完整输入上下文开始一个新链。
错误
一些错误响应特定于 WebSocket 模式,值得明确处理。
previous_response_not_found
当请求的 previous_response_id 不在连接缓存中且无法从存储中重新加载时返回(例如 ZDR、store=false 或先前失败被驱逐)。
{
"type": "error",
"status": 400,
"error": {
"code": "previous_response_not_found",
"message": "Previous response with id 'resp_abc' not found.",
"param": "previous_response_id"
}
}websocket_connection_limit_reached
在服务器关闭已达到最大 25 分钟的连接之前发送。打开一个新的 WebSocket 并使用上述模式之一重新连接。
{
"type": "error",
"status": 400,
"error": {
"type": "invalid_request_error",
"code": "websocket_connection_limit_reached",
"message": "Responses websocket connection limit reached (25 minutes). Create a new websocket connection to continue."
}
}