Все статьи
OpenAIRealtime APIWebSocketAI

Тестирование OpenAI Realtime API локально через туннель

OpenAI Realtime API соединяет клиентов по WebSocket или WebRTC. Для серверных соединений можно обращаться к OpenAI напрямую с любой машины с интернетом. Для клиентских соединений — а это большая часть того, что вы реально захотите построить, — браузеру нужен защищённый origin, а ваш бэкенд должен выпускать эфемерные токены. И то, и другое работает через туннель. Несколько деталей стоит знать.

Два способа подключения, две причины туннелировать

Realtime API поддерживает серверные соединения (ваш бэкенд открывает WebSocket к OpenAI) и клиентские (браузер открывает WebRTC-peer-соединение или WebSocket, используя эфемерный токен, выпущенный вашим бэкендом). Серверный путь не требует туннеля. Клиентский — почти всегда требует.

Почему клиентской стороне нужен HTTPS:

  • Разрешения микрофона в браузере требуют защищённого origin.
  • getUserMedia и обработка ICE в WebRTC лучше всего работают по HTTPS.
  • Service worker'ам (если они есть) это нужно.
  • Если вы вызываете эндпоинт /session бэкенда за эфемерным токеном, этот бэкенд тоже должен быть на HTTPS, если фронтенд на HTTPS.

Первый пункт можно обойти флагами браузера. Не надо. Возьмите туннель и живите в реальном мире.

Структура Realtime-приложения в разработке

Минимальное realtime-приложение состоит из трёх частей:

  1. Фронтенд, захватывающий вход микрофона и проигрывающий аудиовыход.
  2. Бэкенд-маршрут, выпускающий эфемерный токен обращением к эндпоинту OpenAI /v1/realtime/sessions с вашим настоящим API-ключом.
  3. Прямое WebRTC- или WebSocket-соединение из браузера к OpenAI с эфемерным токеном.

Туннель открывает фронтенд + бэкенд (в большинстве сетапов один домен). Сам realtime-трафик идёт браузер-к-OpenAI, а не через туннель — это соединение прямое по HTTPS/WSS.

Быстрая настройка с PortPreview

  1. Запустите dev-сервер (Next.js, Vite, что угодно) на порту 3000 или 5173.
  2. Выполните npx portpreview 3000.
  3. Откройте HTTPS-URL в браузере. Запросы разрешения микрофона работают как обычно.
  4. Вызовите эндпоинт выпуска токена, получите эфемерный токен, откройте realtime-соединение.
  5. Говорите, получайте потоковый ответ.

Если используете Vite, вам нужна конфигурация allowedHosts и HMR из Vite + туннель. На Next.js с edge runtime где-либо — следите за runtime-конфигом маршрутов, которым нужен Node-crypto.

WebSocket-upgrade через туннели

Realtime-соединения — это WebSocket (или WebRTC, который в основном минует туннель). Любой используемый туннель должен корректно пробрасывать HTTP-Upgrade-запрос. Большинство пробрасывает — PortPreview, Cloudflare quick tunnels, ngrok все обрабатывают WebSocket-upgrade. Если ваш не пробрасывает, соединение тихо падает в браузере с обобщённым WebSocket closed before connected без полезных деталей.

Проверьте upgrade с помощью wscat, если не уверены. Подключитесь к wss://your-tunnel.portpreview.dev/anything и наблюдайте за handshake.

Приёмы разработки, которые помогают

Изучите запрос выпуска токена

Ваш фронтенд вызывает бэкенд-маршрут, который вызывает OpenAI. Самый частый dev-баг здесь — неправильно сконфигурированный запрос к /v1/realtime/sessions: не то имя модели, не тот voice, не те modalities. Туннель захватывает запрос фронтенд-к-бэкенду, но не хоп бэкенд-к-OpenAI. Логируйте этот запрос на сервере или проксируйте через туннель, запустив оба слоя локально.

Несовпадения аудиоформата

Realtime API по умолчанию использует PCM16 с настраиваемой частотой дискретизации. Если вы подаёте аудио другого формата, модель либо отвергнет, либо начнёт галлюцинировать. Браузерный MediaRecorder обычно даёт Opus или WebM — вам нужно обрабатывать конвертацию или использовать путь WebRTC, который делает это за вас.

Истечение токена в долгих сессиях

Эфемерные токены недолговечны. Если тестируете сессию длиннее TTL токена, обновляйте по расписанию. У Realtime SDK есть хелперы для этого; делая вручную, следите за событием session.expired и выпускайте новый токен до смерти старого.

Как это выглядит в продакшене

Единственное реальное изменение от разработки к продакшену — URL: замените хостнейм туннеля на ваш настоящий домен. Эндпоинт выпуска токена остаётся на бэкенде. WebRTC/WebSocket-соединение браузер-к-OpenAI — тот же путь кода. Мы видели, как команды переусложняют это и пытаются проксировать realtime-трафик через бэкенд — не надо, это добавляет задержку и ломает модель, которую предполагает SDK OpenAI.

Про параллельное предложение Anthropic (которое ближе к циклу tool use, чем к стриминговому WebSocket) см. Anthropic tool use и вебхуки локально. Присоединяйтесь к листу ожидания PortPreview ради туннеля, который по умолчанию обрабатывает WebSocket-upgrade.

Часто задаваемые вопросы

Можно ли тестировать OpenAI Realtime API на localhost?
Серверные соединения не требуют туннеля. Клиентские соединения из браузера требуют HTTPS для разрешений микрофона и эндпоинтов эфемерных токенов. Используйте туннель, чтобы открыть dev-сервер по HTTPS, затем подключите браузер к OpenAI напрямую с эфемерным токеном.
Должен ли туннель поддерживать WebSocket для Realtime API?
Если используете транспорт WebSocket — да, туннель должен пробрасывать HTTP-upgrade-запросы. Большинство современных туннелей это делают, но стоит проверить с помощью wscat, прежде чем гоняться за фантомным багом соединения. WebRTC минует туннель для самого realtime-трафика.
Зачем нужны эфемерные токены для realtime-соединений из браузера?
Класть полный API-ключ в браузер — катастрофа безопасности. Ваш бэкенд выпускает недолговечный эфемерный токен, ограниченный одной realtime-сессией. Браузер использует этот токен для прямого подключения к OpenAI, никогда не видя ваш настоящий API-ключ.