跳到主要内容
版本:Dev

Realtime API

AISIX AI 网关在 GET /v1/realtime 通过 WebSocket 转发 OpenAI Realtime API。网关会在接受连接前完成客户端认证、模型别名解析、访问控制和限流策略检查,然后在客户端与服务提供方之间双向转发事件。

本指南将演示如何通过网关连接 Realtime 客户端,并说明该端点的关键会话行为。

前提条件​

开始前请准备:

  • 一个可处理代理请求的 AISIX 网关。
  • 一个可访问目标模型别名的调用方 API Key。
  • 一个由支持 OpenAI Realtime 协议的服务提供方支持的模型别名。

导出服务器端示例使用的网关连接和请求值:

# AISIX_PROXY 使用 http 或 https,且不含尾部斜杠或端点路径。
# 本地快速入门使用 http://127.0.0.1:3000。
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="realtime-prod"

目前支持兼容 OpenAI 的服务提供方(适配器为 openai,包括自定义 api_base 部署)和 Azure OpenAI(适配器为 azure-openai,使用 /openai/realtime 和 api-key 认证)。Gemini Live 和 Bedrock 使用不同的实时事件协议,不通过该端点提供。

连接客户端​

通过 model 查询参数选择模型。服务端客户端使用标准请求头认证:

import WebSocket from "ws";

const realtimeUrl = new URL("/v1/realtime", process.env.AISIX_PROXY);
realtimeUrl.protocol = realtimeUrl.protocol === "https:" ? "wss:" : "ws:";
realtimeUrl.searchParams.set("model", process.env.AISIX_MODEL);

const ws = new WebSocket(realtimeUrl, {
headers: { Authorization: `Bearer ${process.env.AISIX_API_KEY}` },
});

浏览器客户端无法设置 WebSocket 请求头。可以像 OpenAI 浏览器示例一样,把调用方 API Key 作为子协议项传入。网关会回显 realtime 子协议:

// 使用不含端点路径的绝对 HTTP(S) 网关 URL,例如 https://gateway.example.com
const aisixProxy = "YOUR_AISIX_GATEWAY_URL";
const aisixApiKey = "YOUR_CALLER_API_KEY";
const aisixModel = "realtime-prod";

const realtimeUrl = new URL("/v1/realtime", aisixProxy);
realtimeUrl.protocol = realtimeUrl.protocol === "https:" ? "wss:" : "ws:";
realtimeUrl.searchParams.set("model", aisixModel);

const ws = new WebSocket(realtimeUrl, [
"realtime",
`openai-insecure-api-key.${aisixApiKey}`,
]);

连接建立后,可以像直接连接服务提供方一样收发 Realtime 事件。AISIX 转发 session.update、音频缓冲区、response.create 和服务端事件等事件时不会改变其结构。

AISIX 唯一会改写的值是会话对象中的模型名称。session.created 和 session.updated 事件中的模型名称是客户端连接时使用的模型别名,而不是服务提供方自身的模型 ID。客户端把该别名通过 session.update 发回时,会在转发到上游前被转换回服务提供方的模型 ID,因此客户端可以直接回传收到的会话对象。

认证与策略​

认证、模型访问检查、客户端 IP 限制和限流会在 WebSocket 升级完成前执行。AISIX Cloud 预算检查也在此时执行。任何一项检查失败都会在 HTTP 握手阶段被拒绝(401、403 或 429),客户端会看到连接建立失败。

会话期间,已配置的安全护栏会扫描双向文本事件。被阻断的事件会产生 OpenAI 风格的 error 事件,随后连接关闭。

用量跟踪​

网关会从服务提供方的 response.done 事件中提取用量信息;转录会话还会从转录完成事件中提取用量。每个会话会记录一个聚合用量事件,包括缓存 Token 数。会话总 Token 会计入基于 Token 的限流。

会话限制​

AISIX 会对两个方向的事件间隔应用空闲上限。系统依次从直接模型的 stream_timeout、该模型的 timeout,以及部署级 upstream.stream_timeout_ms 或 upstream.timeout_ms 默认值解析此上限。部署默认上限为 6000 秒。静默时间超过解析后截止时间的会话将以代码 1001 和原因 idle timeout 关闭。

要让某个模型不受部署级兜底值影响,请设置 timeout: 0,并确保该模型未设置非零 stream_timeout。部署运维人员也可以将两个上游超时默认值均设置为 0。有关完整优先级规则,请参阅超时之间的关系。上游连接失败会以代码 1011 关闭会话;模型开启冷却后,这类失败会计入模型冷却。打开该上游连接本身也有时间预算:upstream.connect_timeout_ms(默认 5 秒)限制整个拨号过程,其中包括 WebSocket 升级握手,因此始终不回应的上游会在此处失败,而不会让会话一直挂着。

连接关闭​

AISIX 会在两个方向上完成 WebSocket 关闭握手:

  • 客户端关闭会话时,客户端会收到自己发送的关闭代码和原因,上游也会收到同样的代码和原因。
  • 上游关闭会话时,客户端会收到上游的关闭代码和原因。原因按上游发送的原样转发,截断为 123 字节。
  • 无法在 Close 帧中发送的关闭代码,例如缺少状态码或 1006,会以 1011 送达另一方。恰好为 1002、原因为 Protocol violation 的 Close 帧也会变为 1011,因为 AISIX 无法把它与 WebSocket 库替换无效代码后生成的帧区分开。原因不同的 1002 会照常转发。
  • 除正常关闭(1000)外,任何结束之前都会先发送一个类型为 server_error 的 Realtime error 事件,说明发生了什么:上游的关闭代码和原因、AISIX 无法转发的 Close 帧、不带状态码的关闭、上游连接失败及其原因,或者没有 Close 帧就结束的连接。

关闭过程中到达的用量仍会计入。会话在访问日志中的状态不取决于关闭代码。

网关关闭时,会像对待流式响应一样,等待打开的 Realtime 会话关闭后再退出,以便记录其用量。请按预期最长的会话时长设置网关的终止宽限期。

通过代理访问上游​

对于 wss:// 服务提供方,AISIX 通过 HTTPS_PROXY 打开上游连接;对于 ws:// 服务提供方,则通过 HTTP_PROXY,两者都回退到 ALL_PROXY,除非 NO_PROXY 覆盖该主机。代理必须是支持 CONNECT 的 HTTP 代理。不支持 SOCKS 代理:会话会以一个 error 事件和关闭代码 1011 失败,访问日志记录 502。1.6.x 及更早版本的网关始终直接连接上游。

下一步​

你已经通过网关连接了 Realtime 客户端。接下来可阅读语音与音频,了解非 Realtime 音频端点。