Реальное распознавание речи в Amazon SageMaker AI и vLLM: как собрать голосовое приложение со стримингом — ИИ для бизнеса

Реальное распознавание речи в Amazon SageMaker AI и vLLM: как собрать голосовое приложение со стримингом

Прослушать статью

Голосовые агенты, сервисы живых субтитров, аналитика контакт-центров и инструменты доступности зависят от распознавания речи в реальном времени: приложение непрерывно отправляет аудио и одновременно получает обратно текст транскрипции по одному постоянному соединению. Обычный подход request-response здесь не подходит, потому что распознавание не может начаться, пока не получена вся аудиозапись, а это добавляет задержку и ломает ощущение работы в реальном времени.

Начиная с ноября 2025 года можно непрерывно передавать данные в обоих направлениях между клиентами и контейнерами с моделями с помощью двунаправленного стриминга Amazon SageMaker AI для real-time inference. vLLM теперь позволяет распознавать аудио в реальном времени через Realtime API, где для двунаправленного стриминга между клиентом и сервером используются WebSocket.

В этом материале мы объединяем эти две возможности. Показано, как развернуть Voxtral-Mini-4B-Realtime-2602, компактную модель Mistral AI для распознавания речи в реальном времени, на конечной точке SageMaker AI с использованием контейнера vLLM и двунаправленного стриминга. В результате получается полностью управляемый сервис speech-to-text, в котором аудио поступает внутрь, а транскрипция возвращается обратно в реальном времени. Пример можно повторить по материалам из GitHub-репозитория.

Ключевые возможности, необходимые для голосовых AI-приложений

Построение production-решения для голосового AI — будь то голосовой агент, сервис живых субтитров или pipeline аналитики контакт-центра — требует набора инфраструктурных компонентов, которые работают вместе в условиях жестких ограничений по задержке. Amazon SageMaker AI и vLLM закрывают разные части этого стека, а вместе дают end-to-end решение, которое убирает лишнюю инженерную работу. Ниже перечислено, что нужно таким приложениям и как это реализуют отдельные компоненты:

  • Модель распознавания речи в реальном времени с эффективным GPU-serving. В основе любого голосового AI-приложения лежит speech-to-text (ASR) модель, которая обрабатывает аудио инкрементально и выдает токены транскрипции по мере поступления звука, а не после завершения записи. vLLM обслуживает такие модели через Realtime API — нативную конечную точку WebSocket по адресу /v1/realtime, которая поддерживает несколько speech-моделей, а также использует piecewise CUDA graph execution, чтобы снижать накладные расходы на запуск GPU-ядeр и тем самым уменьшать задержку на токен во время потокового распознавания. Поскольку vLLM — open source, вы сохраняете полный контроль над конфигурацией модели, quantization и настройками compilation без vendor lock-in на слое обслуживания.
  • Инфраструктура двунаправленного стриминга. Обычные request-response API заставляют клиента сначала выгрузить весь аудиофайл, и только потом сервер начинает обработку. Голосовым приложениям нужен постоянный full-duplex-канал, по которому клиент стримит аудио, а сервер одновременно возвращает транскрипцию. SageMaker AI решает это с помощью нативного двунаправленного стриминга HTTP/2 на порту 8443, автоматически выполняя bridge между HTTP/2 event stream-протоколом на стороне клиента и WebSocket на стороне контейнера. Вам не нужно строить или обслуживать этот слой перевода протоколов — SageMaker AI делает это прозрачно.
  • Обработка и кодирование аудио. Сырые аудиоданные с микрофонов или телеком-систем приходят в разных форматах и с разными sample rate. До попадания в модель их нужно пересэмплировать (обычно до 16 kHz mono PCM16), разбить на подходящие по размеру фрагменты и закодировать в base64 для передачи. Эту конвертацию выполняет клиентский pipeline, а протокол задает Realtime API vLLM: base64 PCM16-фрагменты поступают по WebSocket, а токены транскрипции возвращаются обратно, при этом двунаправленный поток SageMaker AI переносит оба направления одновременно.
  • Управление соединением и отказоустойчивость. SageMaker AI поддерживает WebSocket-соединения с ping/pong keepalive-кадрами, проверяет здоровье контейнера и дает мониторинг на уровне endpoint через Amazon CloudWatch. Это обеспечивает production-наблюдаемость и устойчивость соединения без собственной инструментации.

Иными словами, vLLM дает высокопроизводительное open-source обслуживание моделей с нативным WebSocket-стримингом, а SageMaker AI оборачивает это в managed-инфраструктуру с bridge протоколов, health monitoring и operational tooling. Вместе они позволяют перейти от speech-модели на Hugging Face к production-ready сервису распознавания речи в реальном времени без создания собственной streaming-инфраструктуры и без управления GPU-серверами.

Обзор решения

К концу этого walkthrough у вас будет:

  • Пользовательский Docker-контейнер на базе SageMaker AI vLLM Deep Learning Container с включенным двунаправленным стримингом.
  • Конечная точка SageMaker AI, на которой запущена Voxtral-Mini-4B-Realtime-2602.
  • Python-клиент, который отправляет аудиофайлы на endpoint и получает транскрипцию в реальном времени с помощью SageMaker AI bidirectional streaming SDK.
  • Живой демо-режим на базе Gradio, который распознает речь прямо во время разговора.

Решение соединяет три уровня:

Architecture diagram showing the three-layer connection flow from client through SageMaker AI to the Docker container running vLLM

Client to SageMaker AI: ваше приложение подключается к runtime endpoint SageMaker AI на порту 8443 по HTTP/2, который поддерживает мультиплексированный двунаправленный стриминг. Каждое JSON-сообщение в протоколе vLLM Realtime, например input_audio_buffer.append или transcription.delta, отправляется внутри RequestPayloadPart с DataType, установленным в «UTF8». Это сообщает SageMaker AI, что данные нужно передавать как WebSocket text frame. Ответные сообщения приходят как события ResponsePayloadPart.

SageMaker AI to Docker Container: SageMaker AI автоматически выполняет bridge между HTTP/2 event stream и WebSocket-протоколами. Он устанавливает WebSocket-соединение с контейнером по адресу ws://localhost:8080/invocations-bidirectional-stream — именно этот путь SageMaker AI ожидает для двунаправленного стриминга — и передает data frames в обоих направлениях. Когда в клиенте задано DataType="UTF8", bridge отправляет WebSocket text frames в контейнер.

Docker Container: внутри контейнера легкий FastAPI-bridge (app.py) слушает порт 8080 по пути /invocations-bidirectional-stream. Когда он получает WebSocket-соединение от SageMaker AI, он открывает второе WebSocket-соединение к Realtime API vLLM по адресу ws://localhost:8081/v1/realtime и пересылает сообщения в обоих направлениях. Bridge выполняет преобразование маршрута между ожидаемым путем SageMaker AI и нативной конечной точкой vLLM, а text frames проходят без изменений. Сервер vLLM работает на порту 8081 и предоставляет Realtime API по стандартной WebSocket-окончании /v1/realtime без необходимости патчить исходный код. Bridge также проксирует health-check /ping к health endpoint vLLM, удовлетворяя hosting contract SageMaker AI.

Протокол Realtime API

Realtime API предоставляет потоковую передачу аудио и распознавание речи через WebSocket, позволяя выполнять real-time speech-to-text по мере записи звука. Перед отправкой аудио нужно закодировать его как base64 PCM16 с sample rate 16 kHz и mono-каналом. Последовательность сообщений в протоколе выглядит так:

  1. Клиент подключается к ws://host/v1/realtime.
  2. Сервер отправляет событие session.created.
  3. Клиент при необходимости отправляет session.update с моделью и параметрами.
  4. Клиент отправляет input_audio_buffer.commit, когда готов передать аудио.
  5. Клиент отправляет события input_audio_buffer.append с фрагментами base64 PCM16.
  6. Сервер отправляет события transcription.delta с инкрементальным текстом.
  7. Сервер отправляет transcription.done с финальной транскрипцией и статистикой использования.
  8. Повторять с шага 5 для следующей реплики.
Sequence diagram showing the Realtime API message flow between client and server for streaming audio transcription

Модель начинает распознавание, как только получает достаточно аудиоконтекста, и отправляет токены transcription.delta обратно клиенту, пока клиент продолжает посылать аудиофрагменты. Не нужно ждать, пока будет отправлено все аудио, чтобы начать получать результаты. При необходимости клиент может отправить input_audio_buffer.commit с final=True, чтобы сигнализировать о завершении ввода аудио; это полезно при потоковой передаче аудиофайлов.

Предварительные требования

Сборка пользовательского контейнера vLLM

Мы начинаем с SageMaker AI vLLM Deep Learning Container и добавляем три вещи: Docker-label для двунаправленного стриминга, WebSocket-bridge, который переводит между ожидаемыми маршрутами SageMaker AI и нативными путями API vLLM, а также entrypoint, запускающий оба процесса.

Dockerfile

Формулы и расчет
FROM public.ecr.aws/deep-learning-containers/vllm:0.17.1-gpu-py312-cu129-ubuntu22.04-sagemaker-v1.0-soci

# Сообщаем SageMaker AI, что контейнер поддерживает двунаправленный стриминг
LABEL com.amazonaws.sagemaker.capabilities.bidirectional-streaming=true
WORKDIR /opt/ml/code

# Устанавливаем зависимости bridge
COPY requirements.txt .
RUN pip install --upgrade --no-cache-dir -r requirements.txt

# WebSocket-bridge: маршрутизирует /invocations-bidirectional-stream  /v1/realtime
COPY app.py .
COPY sagemaker-entrypoint.sh entrypoint.sh
RUN chmod +x entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]

HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
 CMD curl -f http://localhost:8080/ping || exit 1

Docker-label com.amazonaws.sagemaker.capabilities.bidirectional-streaming=true сообщает SageMaker AI, что контейнер поддерживает двунаправленный стриминг. Без этого label SageMaker AI не будет устанавливать WebSocket-соединения с контейнером.

Bridge (app.py) — это небольшое приложение FastAPI, которое слушает порт 8080 на стороне SageMaker AI и перенаправляет WebSocket-соединения к /v1/realtime vLLM на внутреннем порту 8081. Оно также проксирует health-check /ping к /health vLLM.

Формулы и расчет
VLLM_WS_URL = "ws://localhost:8081/v1/realtime"
@app.websocket("/invocations-bidirectional-stream")
async def websocket_bridge(sm_ws: WebSocket):
 await sm_ws.accept()
 async with websockets.connect(VLLM_WS_URL) as vllm_ws:

 async def sm_to_vllm():
 """Передача SageMaker AI → vLLM."""
 while True:
 message = await sm_ws.receive()
 if "text" in message and message["text"]:
 await vllm_ws.send(message["text"])
 elif "bytes" in message and message["bytes"]:
 # Резервный вариант для клиентов не в UTF8
 await vllm_ws.send(message["bytes"].decode("utf-8"))

 async def vllm_to_sm():
 """Передача vLLM → SageMaker AI."""
 async for msg in vllm_ws:
 if isinstance(msg, str):
 await sm_ws.send_text(msg)
 elif isinstance(msg, bytes):
 await sm_ws.send_bytes(msg)

 await asyncio.gather(sm_to_vllm(), vllm_to_sm())

Поскольку клиент задает DataType="UTF8", SageMaker AI передает в bridge text frames, а тот отправляет их напрямую в vLLM по адресу /v1/realtime, без преобразования типа фрейма. Декодирование bytes в sm_to_vllm — это запасной путь для клиентов, которые не задают DataType.

Развертывание на конечной точке SageMaker AI

Мы развертываем решение на real-time endpoint SageMaker AI, который будет обслуживать запросы.

SageMaker AI endpoint deployment workflow showing model creation, endpoint configuration, and endpoint creation steps

Настройка окружения модели и развертывание модели

Переменные окружения SM_VLLM_* задают параметры сервера vLLM:

Формулы и расчет
vllm_env = {
    "SM_VLLM_MAX_MODEL_LEN": "45000",
    "SM_VLLM_COMPILATION_CONFIG": '{"cudagraph_mode": "PIECEWISE"}'
}

Voxtral-Mini-4B поддерживает до 262 144 токенов контекста. Здесь мы задаем MAX_MODEL_LEN=45000, чего достаточно, чтобы в live-режиме записывать примерно один час аудио (3600 секунд / 0,08 секунды на токен). Это значение нужно подбирать под ожидаемую длительность аудио. Параметр COMPILATION_CONFIG с cudagraph_mode: PIECEWISE дает CUDA graph-оптимизацию и повышает пропускную способность inference.

Следующий фрагмент кода создает endpoint SageMaker AI:

Формулы и расчет
# Создаем модель
voxtral_model = Model.create(
 model_name=model_name,
 primary_container=ContainerDefinition(
 image=inference_image,
 model_data_source=ModelDataSource(
 s3_data_source=S3ModelDataSource(
 s3_uri=f"{model_artifact}/",
 s3_data_type="S3Prefix",
 compression_type="None",
 )
 ),
 environment=vllm_env
 ),
 execution_role_arn=role,
)

# Создаем конфигурацию endpoint
endpoint_config = EndpointConfig.create(
 endpoint_config_name=endpoint_config_name,
 production_variants=[
 ProductionVariant(
 variant_name="AllTraffic",
 model_name=model_name,
 initial_variant_weight=1.0,
 instance_type=instance_type,
 initial_instance_count=1,
 model_data_download_timeout_in_seconds=health_check_timeout,
 )
 ]
)

# Создаем endpoint
endpoint = Endpoint.create(
 endpoint_name=endpoint_name,
 endpoint_config_name=endpoint_config_name
)

endpoint.wait_for_status("InService")

Тестирование с двунаправленным стримингом

Когда endpoint запущен, мы вызываем его с помощью Python SDK aws-sdk-sagemaker-runtime-http2. Этот SDK общается через HTTP/2 event streams на порту 8443 runtime endpoint SageMaker AI.

Потоковая передача аудио и получение транскрипции

Репозиторий включает полный клиент sagemaker_bidi_client.py, который оборачивает bidirectional streaming SDK в класс SageMakerRealtimeClient. Когда запускается transcribe_audio(), он сначала отправляет событие session.update для выбора модели, а затем передает аудиофайл кусками PCM16 по 4 KB. Receive loop работает как фоновая asyncio.Task, а основная coroutine отправляет аудиофрагменты так, чтобы оба направления HTTP/2-потока были активны одновременно.

Ключевая деталь, делающая это перекрытие заметным, — await asyncio.sleep(chunk_duration) после каждой отправки. Эта пауза синхронизирует передачу с воспроизведением в реальном времени (~128 мс на кусок 4 KB при 16 kHz) и отдает управление event loop, чтобы receive task успевал обрабатывать события transcription.delta, пока новые аудиоданные еще передаются. Без этого уступа chunks отправлялись бы быстрее, чем модель успевает генерировать вывод, и взаимодействие выглядело бы последовательным, хотя underlying stream остается двунаправленным. На стороне приема цикл разворачивается по типу события: обычные события ResponseStreamEventPayloadPart несут JSON-сообщения (session.created, transcription.delta, transcription.done), а ResponseStreamEventModelStreamError и ResponseStreamEventInternalStreamFailure обрабатываются отдельно, чтобы ошибки уровня модели и платформы выводились с понятной диагностикой, а не терялись в пути payload.

Запуск клиента

python sagemaker_bidi_client.py ./audio.wav \
 --region us-east-1

На выходе транскрипция появляется в реальном времени по мере отправки аудио. Delta-токены выводятся посимвольно, пока аудиофрагменты продолжают передаваться в фоне.

Демо с микрофоном в Gradio

Клиент на основе файла удобен для тестирования, но самая низкая задержка при двунаправленном стриминге достигается на живом аудио. В репозитории есть микрофонный клиент на базе Gradio (sagemaker_bidi_microphone_client.py), который захватывает звук с микрофона и передает его в SageMaker AI в реальном времени:

python sagemaker_bidi_microphone_client.py \
 --endpoint-name \
 --region us-east-1

Микрофонный клиент использует те же настройки DataType="UTF8" и тот же протокол vLLM Realtime API, что и файловый клиент. Он захватывает аудио из браузера через потоковый audio input Gradio, пересэмплирует его до 16 kHz PCM16, кодирует каждый фрагмент в base64 и отправляет через двунаправленный поток SageMaker AI. Текст транскрипции обновляется в интерфейсе по мере речи, не дожидаясь окончания фразы.

Ограничения и рекомендации

Realtime API vLLM ожидает аудио в виде base64-кодированного PCM16 с частотой 16 kHz и mono. Если исходное аудио имеет другой формат или sample rate, его нужно преобразовать до отправки. Voxtral-Mini-4B-Realtime-2602 — модель на 4B параметров, она помещается на одном GPU, поэтому для размещения достаточно инстанса ml.g6.4xlarge (1x NVIDIA L4).

SageMaker AI поддерживает WebSocket-соединение с помощью ping/pong-кадров каждые 60 секунд, и соединение закрывается, если 5 последовательных ping остаются без ответа. Для длительных сессий клиент должен уметь переподключаться, а не исходить из того, что поток будет открыт бесконечно. Размер чанка и темп передачи также стоит подбирать под ваш сценарий. В этом примере используются аудиочанки по 4 KB, что соответствует примерно 128 мс аудио при 16 kHz PCM16. Меньшие чанки снижают задержку, но увеличивают накладные расходы на сообщение; более крупные чанки улучшают throughput ценой дополнительной задержки. Подходящее значение зависит от требований вашего приложения к latency.

Очистка ресурсов

Чтобы избежать постоянных затрат, удалите ресурсы, созданные в ходе этого walkthrough, когда завершите тестирование. Endpoint SageMaker AI тарифицируется по underlying instance все время, пока он находится в service, поэтому его удаление — самый важный шаг. В сопровождающем notebook есть ячейка очистки, которая удаляет endpoint, endpoint configuration и model. Если вам больше не нужен пользовательский образ контейнера в Amazon Elastic Container Registry (Amazon ECR) или артефакты модели, загруженные в Amazon Simple Storage Service (Amazon S3), удалите эти ресурсы отдельно, чтобы прекратить расходы на хранение.

Заключение

В этой статье мы показали, как развернуть Voxtral-Mini-4B-Realtime-2602 от Mistral AI для распознавания речи в реальном времени на Amazon SageMaker AI, объединив Realtime WebSocket API vLLM с возможностью двунаправленного стриминга SageMaker AI.

Инфраструктура двунаправленного стриминга SageMaker AI выступает прозрачным bridge между HTTP/2 event stream на стороне клиента и WebSocket на стороне контейнера. С таким bridge серверы моделей, которые поддерживают WebSocket-based text-frame API, например Realtime API vLLM, можно размещать за managed-инфраструктурой SageMaker AI с минимальной адаптацией. Все, что нужно, — это Docker-label, переназначение маршрута и стандартный hosting contract SageMaker AI.

Этот подход выходит далеко за рамки speech-to-text. Сценарии, которым нужна непрерывная двусторонняя коммуникация, например voice agents, перевод в реальном времени, интерактивная генерация аудио или многоходовой streaming dialogue, могут использовать ту же архитектуру. Мы показали это и на файловом клиенте для тестирования, и на живом микрофонном клиенте на базе Gradio для интерактивного использования.

Следующие шаги

Разверните собственную модель, совместимую с Realtime API, на endpoint SageMaker AI с двунаправленным стримингом через vLLM. Полный notebook, файловый клиент и демо с микрофоном доступны на GitHub, чтобы помочь вам начать. Дальше можно развивать решение по нескольким направлениям:

Расширьте демо на Gradio до полноценного приложения. Используйте живой микрофонный клиент как основу и добавьте, например, экспорт транскрипта или последующее резюмирование, передавая output распознавания в text LLM.

Настройте endpoint под ваши цели по задержке и стоимости. Экспериментируйте с типами инстансов, размером чанков и настройками compilation vLLM, чтобы найти баланс для своей нагрузки.

Разверните другую real-time модель. Замените Voxtral-Mini-4B-Realtime-2602 на другую модель, поддерживаемую Realtime API vLLM, обновив model artifact и идентификатор модели, передаваемый в клиентах sagemaker_bidi_client.py и sagemaker_bidi_microphone_client.py.

Узнайте больше о двунаправленном стриминге SageMaker AI. Изучите документацию, чтобы понять полный contract HTTP/2 event stream и применить его к сценариям вроде voice agents или интерактивной генерации аудио.


Материал — перевод статьи с английского.

Оригинал: Build real-time voice applications with Amazon SageMaker AI and vLLM