Голосовой агент в реальном времени с OpenAI Realtime 2 API и Whisper v4 | AiManual
AiManual Logo Ai / Manual.
14 Июн 2026 Гайд

Голосовой агент за вечер: OpenAI Realtime 2 API + Whisper v4 — как склеить разговор в реальном времени и не выпить лишнего валидола

Пошаговый гайд по созданию голосового агента с субсекундной задержкой: стриминг аудио, перевод в реальном времени, tool calling. Примеры кода, ошибки и нюансы.

Реклама
partv2

Вы когда‑нибудь пытались собрать голосового ассистента, который отвечает быстрее, чем раздражённый собеседник успевает бросить трубку? Я — да. И каждый раз это был ад. Whisper на локальном GPU, отдельный LLM, TTS, куча трубопроводов, задержки по 3–4 секунды... А потом OpenAI выкатили Realtime 2 API — и всё перевернули.

Теперь у нас есть единый эндпоинт, который принимает аудио, транскрибирует его Whisper (последняя v4), гоняет через GPT-5 с поддержкой tool calling, переводит на любой из 50+ языков (да, перевод в реальном времени больше не сказка) и синтезирует речь — всё в одном потоке. Задержка «конец речи → ответ» укладывается в 500–800 мс. Живой разговор, а не переписка с роботом.

В этой статье я покажу, как за вечер собрать такого агента с нуля. Без тонн кода, без танцев с бубном вокруг локальных моделей. Только Python, микрофон, колонки и пара сотен строк.

Почему Realtime 2 — это не просто «ещё одно API»

Первая версия Realtime API была... ну, странной. Она требовала WebSocket, бинарные фреймы, свой протокол. Работало, но каждый раз, когда нужно было что‑то кастомизировать — голос, скорость, инструменты — приходилось лезть в документацию с фонариком.

Realtime 2 API (вышел в ноябре 2025) — это REST + Server-Sent Events (или WebSocket для полного дуплекса). Главные плюсы:

  • Встроенный Whisper v4 — не нужно отдельно транскрибировать. Модель дообучена на шумных звонках, акцентах, речи с перебиваниями. WER (Word Error Rate) на русском — около 4%.
  • Перевод в реальном времени — передаёте параметр target_language, и ответ приходит сразу на нужном языке. Никаких промежуточных этапов.
  • Tool calling без боли — можно объявить функцию (бронирование столика, поиск по базе), и Realtime сам решит, когда её вызвать. Агент получает результат и синтезирует голосовой ответ.
  • Мгновенные прерывания — если пользователь перебивает, API автоматически останавливает синтез и начинает слушать заново. Без костылей с VAD.

Кстати, если вы когда‑нибудь собирали голосового ассистента на своём сервере с субсекундной задержкой — вы оцените, насколько Realtime 2 упрощает жизнь.

Что нам понадобится

  • Python 3.11+
  • OpenAI API ключ с доступом к Realtime 2 (нужна платная подписка — около $0.06 за минуту аудио).
  • Микрофон и колонки/наушники (желательно с хорошим шумоподавлением, но встроенный тоже сойдёт).
  • Библиотеки: openai>=1.60.0, sounddevice, numpy, asyncio.

Весь код будет работать на любой версии ОС — Linux, macOS, Windows. Разве что на Windows pyaudio иногда глючит, я использую sounddevice — не подводит.

Архитектура: как это работает под капотом

Клиент захватывает аудио с микрофона маленькими пачками (каждые 100 мс) и отправляет их на сервер через WebSocket. Сервер (OpenAI) параллельно транскрибирует, обрабатывает LLM и начинает синтезировать ответ — кусочками по 50 мс. Клиент получает эти аудиочанки и сразу воспроизводит.

Всё это — в одном соединении. Никаких трёх разных HTTP‑запросов. Задержка складывается только из времени обработки на сервере + сеть. При хорошем пинге (~30 мс) получаем 500–700 мс до первого звука ответа.

Важно: Realtime 2 использует GPT-5 по умолчанию. Если вам нужно что‑то легче или дешевле — можно указать model='gpt-4o-realtime-2025-11-20'. Но GPT-5 даёт лучшее понимание контекста и меньше галлюцинаций.

Пошаговый план: от тишины до первого диалога

1Установка зависимостей

python -m venv venv
source venv/bin/activate
pip install openai sounddevice numpy

Версии на 14.06.2026: openai 1.68.0, sounddevice 0.5.1. Работает без конфликтов.

2Получаем API ключ

Заходите в OpenAI Platform, создаёте ключ с правами на realtime. Кладёте в переменную окружения OPENAI_API_KEY.

3Пишем клиент на Python

Ниже — полный код асинхронного голосового агента. Он открывает WebSocket, в цикле читает микрофон, отправляет аудио, получает и воспроизводит ответ.

import asyncio
import numpy as np
import sounddevice as sd
from openai import AsyncOpenAI

MODEL = "gpt-5-realtime-2026-04-15"  # последняя на момент статьи
SAMPLE_RATE = 24000  # Realtime 2 ожидает 24 кГц
CHUNK_DURATION = 0.1  # 100 мс

client = AsyncOpenAI()

async def audio_stream():
    # Подключаемся к Realtime 2
    async with client.beta.realtime.connect(
        model=MODEL,
        voice="alloy",         # один из: alloy, echo, fable, nova, shimmer
        instructions="Вы — дружелюбный помощник. Отвечайте кратко.",
        input_audio_transcription_enabled=True  # встроенный Whisper
    ) as connection:
        # Поток для захвата микрофона
        microphone_stream = sd.InputStream(
            samplerate=SAMPLE_RATE,
            channels=1,
            blocksize=int(SAMPLE_RATE * CHUNK_DURATION)
        )
        with microphone_stream:
            while True:
                # Читаем 100 мс аудио с микрофона
                chunk, _ = microphone_stream.read(microphone_stream.blocksize)
                # Отправляем на сервер
                await connection.send_audio(chunk.tobytes())
                # Параллельно получаем ответные аудиочанки
                async for event in connection.events():
                    if event.type == "response.audio.delta":
                        audio_bytes = event.delta
                        # Преобразуем в numpy и воспроизводим
                        audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
                        sd.play(audio_np, samplerate=SAMPLE_RATE)
                    elif event.type == "response.text.done":
                        print(f"Транскрипция: {event.text}")
                    elif event.type == "error":
                        print(f"Ошибка: {event.error}")

if __name__ == "__main__":
    asyncio.run(audio_stream())

💡
Обратите внимание: мы не вызываем input_audio_transcription сами — API автоматически транскрибирует речь через встроенный Whisper v4. Если хотите получать текст, слушайте событие response.text.done.

Запускаете скрипт, говорите в микрофон — через секунду слышите ответ. Без бубна.

Как добавить перевод в реальном времени

Одна из киллер-фич Realtime 2 — возможность переводить ответ на другой язык на лету. Например, вы говорите по‑русски, а ассистент отвечает по‑английски. В коде для этого нужно указать параметр target_language при подключении:

async with client.beta.realtime.connect(
    model=MODEL,
    target_language="en",  # перевод на английский
    voice="nova",
    instructions="..."
) as connection:

API сам распознаёт язык пользователя (Whisper v4 определяет 99+ языков) и синтезирует ответ на целевом. Задержка не увеличивается — модель переводит на уровне text generation, без дополнительного NMT.

Это можно использовать для создания синхронного переводчика в звонках. Если интересно, я раньше писал, как собрать такое на коленке с NLLB-200 — сейчас всё в разы проще.

Tool calling: агенту можно дать инструменты

Допустим, ваш голосовой агент должен бронировать столики в ресторане. Без Realtime вы бы транскрибировали запрос, отправляли в LLM, парсили ответ, вызывали функцию, снова ждали... С Realtime 2 всё автоматизировано.

Вы передаёте схему функции в параметре tools, и когда пользователь говорит что‑то вроде «Забронируй столик на двоих на сегодня в 20:00», модель сама решает вызвать инструмент. Агент делает запрос к вашему API, получает результат и генерирует голосовой ответ.

async with client.beta.realtime.connect(
    model=MODEL,
    tools=[
        {
            "type": "function",
            "function": {
                "name": "book_table",
                "description": "Бронирует столик в ресторане",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "guests": {"type": "integer"},
                        "time": {"type": "string"}
                    },
                    "required": ["guests", "time"]
                }
            }
        }
    ],
    ...
) as connection:

Когда Realtime вызывает функцию, вы слушаете событие response.function_call_arguments.done, выполняете логику и отправляете результат обратно через connection.send_function_call_output(). Всё в реальном времени — пользователь даже не заметит паузы.

Типичные ошибки и их решение

  • „Audio format not supported“ — убедитесь, что отправляете PCM 16-bit, 24 кГц, mono. Не используйте MP3 или WAV с другой частотой.
  • Задержка больше 2 секунд — проверьте пинг до api.openai.com. Если >100 мс, подумайте о ближайшем регионе (US/EU/Asia). Также не ставьте слишком большой CHUNK_DURATION — 100 мс оптимально.
  • Прерывания не работают — в Realtime 2 встроенный VAD (Voice Activity Detection). Если пользователь начинает говорить, пока агент отвечает, сервер автоматически останавливает вывод. Не нужно ничего настраивать. Но если вам нужно отключить — параметр interruption_detection=false.
  • Голос звучит неестественно — попробуйте голос nova (он самый новый, 2026 года). alloy и shimmer тоже неплохи, но nova имеет более широкий диапазон интонаций.

Когда всё же стоит использовать локальный стек?

Realtime 2 — это облако. Если у вас:

  • требования к конфиденциальности (медицина, финансы),
  • нужен полный контроль над моделью,
  • трафик такой, что платить за минуты дороже, чем своё железо,

...тогда локальный стек — ваш выбор. Я писал об этом в статьях про сборку локального ASR и LangChain + Ollama. Но для MVP, хакатона или стартапа — Realtime 2 закрывает 90% потребностей за вечер.

Кстати, если вы когда‑нибудь захотите объединить облачный Realtime 2 с локальным TTS или наоборот — читайте мою статью про архитектуру гибридных агентов.

Теперь дело за вами. Регистрируйте ключ, вставляйте код, говорите. Через полчаса у вас будет работающий голосовой агент. А если что‑то пойдёт не так — пишите в комментариях, я помогу.

Подписаться на канал