所有文章
OpenAIRealtime APIWebSocketAI

通过隧道在本地测试 OpenAI Realtime API

OpenAI Realtime API 通过 WebSocket 或 WebRTC 连接客户端。对于服务器侧连接,你可以从任何有网络的机器直接访问 OpenAI。对于客户端侧连接——也就是你真正想用它构建的大部分东西——浏览器需要一个安全源,你的后端需要签发临时令牌。两者都能通过隧道工作。有些细节值得了解。

两种连接方式,两个穿隧道的理由

Realtime API 支持服务器侧连接(你的后端向 OpenAI 打开一个 WebSocket)和客户端侧连接(浏览器使用你后端签发的临时令牌打开一个 WebRTC 对等连接或 WebSocket)。服务器侧路径不需要隧道。客户端侧几乎总是需要。

为什么客户端侧需要 HTTPS:

  • 浏览器麦克风权限需要安全源。
  • WebRTC 的 getUserMedia 和 ICE 处理在 HTTPS 上效果最好。
  • Service Worker(如果有)需要它。
  • 如果你调用后端的 /session 端点来获取临时令牌,那么当你的前端是 HTTPS 时,那个后端也必须是 HTTPS。

第一点你可以用浏览器标志绕过。别这么做。用一个 隧道,活在真实世界里。

开发中的 Realtime 应用的形态

一个最小的 realtime 应用有三个部分:

  1. 一个捕获麦克风输入并渲染音频输出的前端。
  2. 一个后端路由,用你真正的 API key 调用 OpenAI 的 /v1/realtime/sessions 端点来签发临时令牌。
  3. 一个从浏览器到 OpenAI 的、使用临时令牌的直接 WebRTC 或 WebSocket 连接。

你的隧道暴露前端 + 后端(多数设置下同一个域名)。真正的 realtime 流量走浏览器到 OpenAI,而不经过你的隧道——那个连接是通过 HTTPS/WSS 直连的。

用 PortPreview 快速搭建

  1. 在 3000 或 5173 端口启动你的开发服务器(Next.js、Vite,随便什么)。
  2. 运行 npx portpreview 3000
  3. 在浏览器中打开 HTTPS URL。麦克风权限提示正常工作。
  4. 调用你的令牌签发端点,拿到临时令牌,打开 realtime 连接。
  5. 说话,收到流式响应。

如果你用 Vite,你会需要 Vite + 隧道 里的 allowedHosts 和 HMR 配置。如果你在 Next.js 的某处用了 edge runtime,要当心需要 Node crypto 的路由上的 runtime 配置。

WebSocket 升级穿过隧道

Realtime 连接是 WebSocket(或者 WebRTC,它大多绕过隧道)。你用的任何隧道都必须正确转发 HTTP 的 Upgrade 请求。大多数都会——PortPreview、Cloudflare quick tunnels、ngrok 都处理 WebSocket 升级。如果你的不会,连接会在浏览器里悄悄失败,只有一条通用的 WebSocket closed before connected 消息,没有有用的细节。

如果不确定,用 wscat 测试升级。连接到 wss://your-tunnel.portpreview.dev/anything,观察握手。

真正有用的开发技巧

检查令牌签发请求

你的前端调用一个调用 OpenAI 的后端路由。这里最常见的开发 bug 是发往 /v1/realtime/sessions 的请求配置错误——模型名错、voice 错、modalities 错。你的隧道捕获前端到后端的请求,但捕获不到后端到 OpenAI 这一跳。在服务器侧记录那个请求,或者把两层都跑在本地,通过隧道代理它。

音频格式不匹配

Realtime API 默认使用可配置采样率的 PCM16。如果你灌入另一种格式的音频,模型要么拒绝,要么产生幻觉。浏览器 MediaRecorder 通常给你 Opus 或 WebM——你需要处理转换,或者用替你处理它的 WebRTC 路径。

长会话中的令牌过期

临时令牌寿命很短。如果你测试的会话比令牌 TTL 长,就按计划刷新。Realtime SDK 有相应的辅助工具;自己实现意味着监听 session.expired 事件,并在旧令牌死掉之前签发一个新的。

这在生产中是什么样

从开发到生产唯一真正的改动是 URL:把隧道主机名换成你真正的域名。令牌签发端点留在你的后端。从浏览器到 OpenAI 的 WebRTC/WebSocket 连接是同一条代码路径。我们见过有团队把这个想复杂了,试图把 realtime 流量代理过他们的后端——别这么干,它会增加延迟,并破坏 OpenAI 的 SDK 所假定的模型。

关于 Anthropic 的并行产品(它更接近一个工具调用循环,而非流式 WebSocket),参见 在本地使用 Anthropic tool use 和 Webhook加入 PortPreview 等候名单,获得默认处理 WebSocket 升级的隧道。

常见问题

我能在 localhost 上测试 OpenAI Realtime API 吗?
服务器侧连接不需要隧道。来自浏览器的客户端侧连接需要 HTTPS 来获得麦克风权限和临时令牌端点。用隧道把你的开发服务器通过 HTTPS 暴露出来,然后用临时令牌让浏览器直接连接到 OpenAI。
我的隧道需要支持 WebSocket 才能用 Realtime API 吗?
如果你用 WebSocket 传输,需要——隧道必须转发 HTTP 升级请求。大多数现代隧道都会,但在追查一个幻影连接 bug 之前,值得用 wscat 测试一下。对于 realtime 流量本身,WebRTC 会绕过隧道。
为什么浏览器的 realtime 连接需要临时令牌?
把你的完整 API key 放进浏览器是一场安全灾难。你的后端签发一个限定于单个 realtime 会话的短寿命临时令牌。浏览器用这个令牌直接连接到 OpenAI,永远不会看到你真正的 API key。