- Дата публикации
Как OpenAI ускорила голосовой ИИ для 900+ млн пользователей: внутренняя кухня WebRTC
Что нового
OpenAI перестроила инфраструктуру для голосовых продуктов — ChatGPT Voice и Realtime API — чтобы голосовой ИИ работал с минимальной задержкой при огромной нагрузке.
Ключевые изменения:
- Масштаб: архитектура рассчитана на более чем 900 млн еженедельно активных пользователей.
- Новая схема WebRTC: вместо классической схемы "один порт на сессию" OpenAI использует связку relay + transceiver.
- Малый публичный UDP‑футпринт: несколько стабильных IP:портов для всего глобального трафика WebRTC вместо десятков тысяч портов.
- Глобальная сеть входных узлов (Global Relay): медиа‑трафик заходит в сеть OpenAI через ближайший географический и сетевой узел, что снижает задержку и джиттер.
- Поддержка Kubernetes без хака с портами: WebRTC‑нагрузка теперь нормально уживается с автоскейлингом и пересозданием подов.
- Сохранён стандартный WebRTC на клиенте: браузеры и мобильные SDK не требуют кастомных патчей — всё строится на ICE, DTLS, SRTP и стандартных кодеках.
Цифр по миллисекундам задержки или процентам ускорения OpenAI не приводит, но все инженерные решения направлены на три конкретные цели:
- Быстрый старт сессии: пользователь может начать говорить сразу после установления соединения.
- Низкий и стабильный медиарундтрип, минимальный джиттер и потери пакетов.
- Глобальный охват с коротким первым сетевым хопом.
Как это работает
Почему WebRTC
OpenAI использует WebRTC как базу для реального времени. Причина проста: WebRTC уже решает за клиента и сервер тяжёлые задачи:
- ICE — установление соединения и обход NAT.
- DTLS + SRTP — шифрование транспорта.
- Negotiation кодеков — сжатие и декодирование аудио.
- RTCP — контроль качества.
- Клиентские функции — эхоподавление, jitter buffer и т.д.
Для ИИ это критично: аудио идёт потоком, а не файлом. Модель может распознавать речь, рассуждать, вызывать инструменты и генерировать ответ, пока пользователь ещё говорит. Это превращает общение из "нажал — сказал — подождал" в живой диалог.
OpenAI опирается на существующую экосистему WebRTC и open‑source:
- Pion (от Sean DuBois) как основа Go‑реализации.
- Опыт одного из архитекторов WebRTC Justin Uberti.
Оба сейчас работают в OpenAI и помогают сшивать WebRTC и голосовой ИИ.
Трансивер вместо SFU
У WebRTC‑систем обычно два пути:
- SFU (Selective Forwarding Unit): сервер принимает один поток от каждого участника и раздаёт другим. Удобно для групповых звонков, классов, митингов.
- Трансивер (client → сервер): сервер завершает WebRTC‑сессию и конвертирует медиа во внутренние протоколы.
Многие компании выбирают SFU даже для client→AI‑сценариев, потому что можно переиспользовать готовую систему: сигналинг, запись, политику, handoff к человеку и т.д.
OpenAI выбрала трансиверную модель, потому что её трафик другой:
- Почти все сессии — 1:1: один пользователь ↔ один ИИ‑агент.
- Каждая реплика чувствительна к задержке.
Схема:
- Transceiver‑сервис на краю завершает WebRTC: ICE, DTLS, SRTP, SDP.
- Дальше он превращает медиа и события во внутренние протоколы: инференс, транскрипция, генерация речи, вызов инструментов, оркестрация.
Вся сессионная логика WebRTC живёт в одном сервисе:
- ICE‑проверки, DTLS‑рукопожатие, ключи SRTP.
- Жизненный цикл сессии и ICE‑рестарты.
Бэкенды для инференса не притворяются WebRTC‑пирами и масштабируются как обычные микросервисы.
Конфликт WebRTC и Kubernetes
Первая реализация OpenAI — один Go‑сервис на базе Pion, который занимался и сигналингом, и медиатрафиком. Он уже обслуживает:
- голос ChatGPT,
- WebRTC‑эндпоинт Realtime API,
- несколько исследовательских проектов.
Дальше начались проблемы инфраструктуры.
Проблема №1: один порт на сессию
Классический WebRTC‑подход — выделять отдельный UDP‑порт под каждую сессию. На большом числе одновременных звонков это означает огромные диапазоны портов.
Почему это плохо для Kubernetes и облака:
- Облачные балансировщики и Kubernetes‑сервисы не рассчитаны на десятки тысяч публичных UDP‑портов на один сервис.
- Каждый новый диапазон — усложнение конфигурации балансировщика, health‑check’ов, firewall’ов и выкатываний.
- Большие диапазоны портов сложнее защищать и аудировать.
- Автоскейлинг Kubernetes ломается: поды постоянно создаются и умирают, а им нужно резервировать и объявлять стабильные диапазоны портов.
Поэтому многие WebRTC‑системы переходят к одному UDP‑порту на сервер с демультиплексированием на уровне приложения.
Проблема №2: "липкое" состояние
Если перейти на один порт на сервер, появляется другая задача: каждый пакет должен попадать в тот же процесс, который создал сессию.
ICE и DTLS — сессионные протоколы:
- Тот же процесс должен видеть все пакеты сессии, чтобы завершить DTLS‑рукопожатие, проверять ICE‑пакеты, расшифровывать SRTP и обрабатывать ICE‑рестарты.
- Если пакеты прилетают в другой процесс, сессия ломается.
Цель OpenAI:
- Оставить малый фиксированный UDP‑футпринт наружу.
- И при этом гарантировать, что каждый пакет попадёт в "свой" трансивер.
Как OpenAI выбирала архитектуру
Команда рассмотрела несколько вариантов.
1. Уникальный IP:порт на сессию (native direct UDP)
Плюсы:
- Прямой путь клиент → сервер, без лишнего хопа.
Минусы:
- Требуется один публичный UDP‑порт на каждую сессию.
- Гигантские портовые диапазоны тяжело пробрасывать и защищать.
- Плохо сходится с Kubernetes и облачными балансировщиками.
2. Уникальный IP:порт на сервер
Плюсы:
- Публичный UDP‑футпринт сильно меньше.
- Один сокет может обслуживать много сессий.
Минусы:
- Хорошо работает на одной машине, но не в балансируемом флоте.
- Балансировщик всё равно может отправить первый пакет не туда, где живёт сессия.
3. TURN‑relay с терминацией протокола
Плюсы:
- Клиенту нужен только адрес TURN‑сервера.
- Политики можно централизовать на краю.
Минусы:
- TURN‑аллокейшены добавляют лишние RTT при установке соединения.
- Перенос и восстановление аллокейшенов между TURN‑серверами сложен.
4. Stateless‑форвардер + stateful‑терминатор (relay + transceiver от OpenAI)
Плюсы:
- Малый публичный UDP‑футпринт.
- Трансивер полностью владеет WebRTC‑сессией.
Минусы:
- Появляется один дополнительный хоп до трансивера.
- Нужна своя координация между relay и transceiver.
OpenAI выбрала последний вариант.
Архитектура relay + transceiver
Схема работы:
- Сигналинг (HTTP/WebSocket, SDP‑обмен) идёт напрямую в трансивер.
- Медиа (STUN/DTLS/RTP/RTCP) сначала попадает в relay.
- Relay — лёгкий UDP‑форвардер с небольшим публичным IP:порт‑футпринтом.
- Transceiver — stateful WebRTC‑эндпоинт за relay.
Relay не:
- расшифровывает медиа,
- не крутит ICE‑машину состояний,
- не участвует в переговоре кодеков.
Он читает минимум метаданных и решает, куда переслать пакет. Для клиента всё выглядит как обычный WebRTC‑сеанс.
Маршрутизация по ICE‑ufrag
Главная задача — правильно направить первый пакет. На пути ещё нет сессионного состояния, и relay не может ждать внешнего запроса в базу.
WebRTC уже даёт встроенный "маркер маршрута" — ICE username fragment (ufrag):
- Короткий идентификатор, который участники обменивают в SDP.
- Клиент повторяет его в STUN‑пакетах при проверке связности.
OpenAI генерирует серверный ufrag так, чтобы в нём было достаточно маршрутизирующей информации:
- какая целевая кластерная зона,
- какой трансивер владеет сессией.
Поток выглядит так:
- Трансивер во время сигналинга создаёт состояние сессии.
- В SDP‑answer он отдаёт:
- общий VIP и UDP‑порт relay, например
203.0.113.10:3478; - свой ufrag с зашитой маршрутизацией.
- общий VIP и UDP‑порт relay, например
- Клиент отправляет первый медиа‑пакет — обычно это STUN Binding Request.
- Relay парсит только заголовок STUN, достаёт server ufrag, декодирует маршрутизирующий хинт и пересылает пакет на нужный трансивер.
- Каждый трансивер слушает один общий внутренний UDP‑сокет (IP:порт), а не порт на сессию.
- Relay создаёт у себя минимальное сессионное состояние: привязка
<client IP:port → transceiver IP:port>. - Все следующие DTLS/RTP/RTCP‑пакеты идут внутри этой сессии без повторного чтения ufrag.
Состояние на relay осознанно минимально:
- только in‑memory‑карта для форвардинга и мониторинга,
- таймеры для истечения и очистки сессий.
Если relay перезапускается и теряет память:
- следующий STUN‑пакет восстановит маршрут через ufrag;
- чтобы не ждать STUN, OpenAI также кладёт маппинг
<client IP + port, transceiver IP + port>в Redis, что позволяет восстановить маршрут раньше.
Global Relay и геостирование сигналинга
После того как OpenAI сократила публичный UDP‑футпринт до нескольких стабильных адресов и портов, стало возможным развернуть relay по всему миру.
Global Relay — это флот географически распределённых входных узлов, все они работают по одной логике форвардинга.
Плюсы:
- Первый хоп клиент → OpenAI становится короче.
- Пакет входит в сеть OpenAI через ближайший relay — географически и по топологии сети.
- Снижаются задержка, джиттер и всплески потерь до попадания трафика в бэконбон.
Сигналинг OpenAI направляет через Cloudflare geo и proximity steering:
- Первый HTTP/WebSocket‑запрос попадает в ближайший кластер трансиверов.
- Контекст запроса определяет, где будет жить сессия и какой узел Global Relay отдать клиенту.
- В SDP‑answer трансивер возвращает адрес Global Relay.
- В ufrag зашиты данные, по которым Global Relay отправит медиа в нужный кластер, а конкретный relay — в нужный трансивер.
Итог:
- И сигналинг, и медиа идут по ближайшему пути.
- Время установки соединения и первый ICE‑roundtrip сокращаются.
Реализация relay и производительность
Relay написан на Go. OpenAI сознательно оставила реализацию узкой:
- Linux‑ядро принимает UDP‑пакеты и доставляет их в сокет.
- Процесс на Go читает заголовки, обновляет немного состояния и пересылает пакеты.
- Никаких фреймворков обхода ядра (kernel bypass) — они усложняют эксплуатацию, а текущей нагрузки хватило без них.
Ключевые решения:
- Без терминации протокола: relay парсит только STUN/ufrag, остальные пакеты (DTLS/RTP/RTCP) остаются "чёрным ящиком".
- Эфемерное состояние: маленькая in‑memory‑карта для потоков и метрик с короткими таймаутами.
- Горизонтальное масштабирование: несколько relay‑инстансов за балансировщиком, никакого жёсткого WebRTC‑состояния — перезапуски дают минимум потерь и быструю реконструкцию потоков.
Оптимизации эффективности:
- SO_REUSEPORT — несколько воркеров relay на одной машине могут слушать один и тот же UDP‑порт. Ядро само распределяет пакеты, избегая узкого места в одном read‑loop.
- runtime.LockOSThread — каждая горутина чтения UDP закреплена за конкретным OS‑потоком. В связке с SO_REUSEPORT это держит пакеты одного потока на одном ядре, улучшая cache‑locality и снижая переключения контекста.
- Предвыделенные буферы и минимум копирований — чтобы уменьшить нагрузку на сборщик мусора Go.
По словам OpenAI, такая реализация справляется с глобальным медиатрафиком при относительно небольшом флоте relay‑инстансов, поэтому переход на kernel bypass не потребовался.
Что это значит для вас
Для разработчиков голосовых продуктов
Если вы строите голосовые интерфейсы на ChatGPT Voice или Realtime API, новая архитектура даёт несколько практических эффектов:
- Быстрый старт сессии: пользователь может начать говорить почти сразу после установления соединения.
- Более естественный диалог: меньше пауз, обрывов и задержек при перебивании собеседника (barge‑in).
- Стабильность при нагрузке: инфраструктура рассчитана на сотни миллионов пользователей в неделю.
Где это полезно:
- Голосовые ассистенты в приложениях и на сайтах.
- Поддержка клиентов с живым диалогом, а не по кнопке.
- Реальные "агенты" с цепочками действий, которые должны реагировать по ходу речи.
Что важно понимать:
- Вы по‑прежнему используете стандартный WebRTC‑клиент — браузер или мобильный SDK.
- Никаких нестандартных патчей WebRTC на клиенте не требуется.
Для продуктовых команд
Новая архитектура меняет не только скорость, но и надёжность:
- Меньший публичный UDP‑футпринт проще защищать и мониторить.
- WebRTC‑состояние сосредоточено в одном сервисе (transceiver), а не размазано по множеству бэкендов.
- Relay остаётся "тупым" форвардером — его проще масштабировать и перезапускать без сложных миграций состояния.
Это снижает риск того, что голосовой продукт начнёт вести себя странно под нагрузкой или при сбоях в одной из зон.
Ограничения и подводные камни
- Архитектура оптимизирована под 1:1‑сессии. Для сложных многопользовательских сценариев (большие конференции) придётся строить поверх неё или использовать отдельные SFU‑решения.
- В России доступ к продуктам OpenAI может потребовать VPN и обхода региональных ограничений. Это нужно учитывать при планировании пользовательских сценариев и юридических рисков.
- Если вы хотите глубоко вмешиваться в медиапайплайн на стороне сервера (свои кодеки, нестандартные RTP‑потоки), вам всё равно придётся работать через стандартный WebRTC‑слой, который завершает трансивер.
Когда это не ваш вариант
- Если вам нужен простой офлайн‑транскрипт аудио без требований к реальному времени, WebRTC и такая архитектура будут избыточны — достаточно загрузки файла.
- Если ваш продукт строго работает в изолированном контуре без выхода в интернет, вы не сможете использовать Global Relay и инфраструктуру OpenAI напрямую.
Место на рынке
Архитектура, которую описывает OpenAI, относится к уровню инфраструктуры, а не к самим моделям типа GPT‑5.
Сравнивать её напрямую с другими ИИ‑моделями нет смысла: она решает другую задачу — как доставить голосовой трафик до ИИ‑модели с минимальной задержкой и потерями.
По подходу OpenAI ближе к крупным системам реального времени, которые тоже строят свои WebRTC‑слои:
- Discord, который обслуживает миллионы одновременных голосовых пользователей.
- Медиа‑шлюзы уровня LiveKit, mediasoup, специализированные WebRTC‑шлюзы под Kubernetes.
Отличительные черты подхода OpenAI:
- Ставка на SFU‑less‑архитектуру для AI‑сценариев 1:1.
- Чёткое разделение:
- relay — минимальный stateless‑форвардер на UDP;
- transceiver — единственный владелец ICE/DTLS/SRTP‑состояния.
- Использование ICE ufrag как встроенного маршрутизирующего ключа, без внешних lookup‑сервисов на горячем пути.
- Ориентация на работу в Kubernetes с автоскейлингом и частыми пересозданиями подов.
Если вы строите свой стек реального времени для ИИ, подход OpenAI можно рассматривать как референсную архитектуру для трафика "клиент ↔ ИИ‑агент" без тяжёлого SFU.
Выводы
OpenAI показала, как можно:
- оставить клиентам чистый WebRTC,
- спрятать сложность маршрутизации в тонком relay‑слое,
- держать всё сессионное состояние в одном сервисе,
- и при этом запустить голосовой ИИ на аудиторию свыше 900 млн пользователей в неделю.
Если вы работаете с голосом и реальным временем, этот кейс полезен как практическая схема того, как ужить WebRTC, глобальный трафик и Kubernetes без цирка с портами и нестабильным состоянием.