Как создать голосовой фитнес ассистент

В предыдущем уроке вы познакомились с голосовыми AI-агентами и интерфейсом Realtime API. Теперь вас ждёт практика.❗️Практическая часть курса предполагает использование облачных ресурсов, которые вы оплачиваете самостоятельно. Курс разработан так, чтобы расходы были минимальными, — часть из них покроет стартовый грант.Чтобы избежать лишних трат:— останавливайте ВМ в перерывах между практиками (это не снизит потребление до нуля, но заметно сократит расходы);— настройте бюджет и уведомления в разделе

Биллинг;— удаляйте ресурсы после завершения курса;— необязательно выполнять все практики — сосредоточьтесь на релевантных.💻 Вы разберёте ключевые части приложения и пошагово настроите голосового агента. Полный код находится в GitHub-репозитории. Вы можете скачать проект, запустить его и адаптировать под свои задачи.Чтобы выполнить практику, подготовьте пререквизиты:

  • аккаунт в Yandex Cloud
  • API-ключ YANDEX_CLOUD_API_KEY
  • ID каталога YANDEX_CLOUD_FOLDER_ID
  • сервисный аккаунт с ролью ai.models.user
  • Python 3.10+
  • Зависимости pip install yandex-ai-studio-sdk aiohttp Yandex AI Studio SDK содержит утилитные классы для работы с аудио, которых достаточно для быстрого прототипирования голосового ассистента без реализации низкоуровневой логики захвата и воспроизведения звука.

Что вы соберёте

С точки зрения реализации вы создадите приложение с такими функциями:

  • распознавание речи в реальном времени;
  • генерация ответа с помощью модели;
  • голосовое озвучивание ответа;
  • вызов функций calculate_calories, recommend_supplements и end_dialog;
  • использование встроенных инструментов file_search и web_search;
  • корректная обработка перебивания.

С точки зрения продукта — это голосовой фитнес-ассистент, который умеет:

  • рассчитывать калории calculate_calories;
  • рекомендовать спортивные добавки recommend_supplements;
  • отвечать на вопросы по базе знаний file_search;
  • искать актуальную информацию web_search;
  • реагировать на перебивания пользователя;
  • завершать диалог, если пользователь прощается end_dialog.

Шаг 1. Подготовка клиентской части

1️⃣ Импортируйте вспомогательные аудиоклассы из установленной Yandex AI Studio SDK:

from yandex_ai_studio_sdk._experimental.audio.microphone import AsyncMicrophone
from yandex_ai_studio_sdk._experimental.audio.out import AsyncAudioOut 

Эти классы берут на себя всю низкоуровневую работу с аудиоустройствами. Они обеспечивают корректный захват PCM-аудио, управление буфером и стабильное воспроизведение синтезированной речи.2️⃣ Подготовьте параметры подключения: сформируйте данные для установки WebSocket-соединения с Realtime API:

WSS_URL = (
    f"wss://ai.api.cloud.yandex.net/v1/realtime/"
    f"?model=gpt://{YANDEX_CLOUD_FOLDER_ID}/speech-realtime-250923"
) 

Здесь:

  • wss://ai.api.cloud.yandex.net/v1/realtime/ — эндпоинт Realtime API, реализует OpenAI-совместимый интерфейс взаимодействия;
  • параметр model= в URL сообщает серверу, какую модель использовать в этой сессии;
  • формат gpt://<YANDEX_CLOUD_FOLDER_ID>/<model_name> — стандартный способ обращения к моделям в AI Studio.

💻 Когда мы пишем этот урока, актуальна модель speech-realtime-250923. Она обеспечивает распознавание и синтез речи, генерацию ответа.3️⃣ Добавьте авторизационный заголовок. При подключении WebSocket-соединение должно пройти проверку по API-ключу:

HEADERS = {"Authorization": f"Api-Key {YANDEX_CLOUD_API_KEY}"} 

YANDEX_CLOUD_API_KEY — ваш API-ключ, который позволяет обращаться к модели внутри указанного каталога YANDEX_CLOUD_FOLDER_ID.

Шаг 2. Настройка сессии Realtime API

На этом этапе вы зададите правила поведения для модели, доступные инструменты, формат аудио и другие параметры. Все настройки передаются в Realtime API с помощью метода session.update.1️⃣ Задайте инструкции для ассистента:

"instructions": (
    """Ты — умный фитнес-ассистент. Помогаешь людям с тренировками, питанием и спортивными добавками. Отвечаешь кратко, по делу и дружелюбно. 
...
Твои возможности:
- Рассчитать калории и макронутриенты (функция calculate_calories)
- Порекомендовать спортивные добавки (recommend_supplements)
- Найти информацию в базе знаний о фитнесе (file_search)
- Найти актуальную информацию в интернете (web_search)"
...
"""
) 

Поле instructions в конфигурации Realtime API выполняет роль системного промпта. Модель учитывает его , когда взаимодействует с пользователем. В этой инструкции вы определяете, как должен вести себя ассистент: какую роль он выполняет, как отвечает пользователю, когда обращается к функциям и каких правил придерживается в диалоге.2️⃣ В блоке output_modalities задайте тип “audio”. Так вы явно говорите модели, что она должна озвучивать полученный результат:

"output_modalities": ["audio"] 

Если нужно, замените значение на "text", чтобы получать текстовый ответ без озвучивания синтезом.3️⃣ Задайте форматы входного и выходного аудио. Код входа и выхода один и тот же — сырые PCM-данные:

 "type": "audio/pcm" 

4️⃣ Настройте Voice Activity Detection (VAD):

"turn_detection": {
    "type": "server_vad",
    "threshold": 0.5,
    "silence_duration_ms": 400,
} 

Что означают параметры:

  • type — тип детекции речи. Когда мы пишем этот урок, поддерживается только значение server_vad — определение начала и конца речи происходит на стороне сервера.
  • threshold — порог чувствительности детекции речи. Чем ниже значение, тем легче считается, что пользователь начал говорить. Чем выше — тем больше уверенность, что это именно речь, а не шум.
  • silence_duration_ms — длительность тишины (в миллисекундах), после которой фраза считается завершённой. В примере указано значение 400 мс: если пользователь замолчал на это время, ассистент начинает обработку.

С такими настройками ассистент поймёт, когда клиент начал или закончил говорить, чтобы вовремя переключаться между состояниями «говорю» и «слушаю».5️⃣ Укажите голос и скорость для синтеза речи:

"voice": VOICE,  # например, "dasha"
"speed": 1.2, 

📚 Можно использовать любой голос Yandex SpeechKit: из списка доступных или построенный по технологии Yandex Brand Voice.6️⃣ Опишите инструменты tools, доступные ассистенту. В вашем случае в конфигурации сессии есть пять инструментов:

 "tools": [
                # Функция расчёта калорий
                {
                    "type": "function",
                    "name": "calculate_calories",
                    "description": "Рассчитывает базовый метаболизм и рекомендуемое потребление калорий на основе параметров пользователя",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "weight": {
                                "type": "number",
                                "description": "Вес в килограммах"
                            },
                            "height": {
                                "type": "number",
                                "description": "Рост в сантиметрах"
                            },
                           ....
                        },
                        "required": ["weight", "height", "age", "gender", "activity_level"],
                        "additionalProperties": False
                    }
                },
                # Функция рекомендаций по добавкам
                {
                    "type": "function",
                    "name": "recommend_supplements",
                    "description": "Рекомендует спортивные добавки в зависимости от цели тренировок и уровня опыта",
                    ....
                },
                # Встроенная функция для поиска в интернете
                {
                    "type": "function",
                    "name": "web_search",
                    "description": "Поиск в интернете актуальной информации о фитнесе, тренировках и питании",
                    "parameters": {}"
                },
                # Встроенная функция для поиска по базе знаний
                {
                    "type": "function",
                    "name": "file_search",
                    "description": VECTOR_STORE_ID, # ID индекса с базой знаний о фитнесе
                    "parameters": {}
                },
                 # Функция для завершения диалога при прощании
                {
                    "type": "function",
                    "name": "end_dialog",
                    "description": "Завершает диалог. Вызывается когда пользователь прощается (говорит 'до свидания', 'пока', 'всего доброго' и т.п.). ",
                    "parameters": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": False
                    }
                }
            ] 

Здесь вы перечисляете пользовательские функции и встроенные инструменты:

  • пользовательские функции —calculate_calories, recommend_supplements, end_dialog;
  • встроенные инструменты — web_search, file_search.

Пользовательские функции нужно реализовать на стороне клиента. Встроенные инструменты начинают работать сразу после того, как вы объявите их в конфигурации агента. Когда модель вызывает функцию, сервер отправляет событие response.output_item.done. В нем указаны тип события function_call, название функции и её аргументы:

def process_function_call(item) -> dict:
    """Обработка вызовов функций."""
    call_id = item.get("call_id")
    function_name = item.get("name")
    args_text = item.get("arguments") or "{}"
    ... 

7️⃣ Выполните функцию и верните результат модели:



...
return {
        "type": "conversation.item.create",
        "item": {
            "type": "function_call_output",
            "call_id": call_id,
            "output": result_json
        }
    } 

Для end_dialog есть отдельная логика завершения. Когда функция возвращает результат, клиент запрашивает финальную реплику, а затем закрывает сессию.💡Самостоятельно включите поиск по базе знанийДля этого передайте в file_search ID поискового индекса — также, как для текстового ассистента. За основу для индекса возьмите файлы из GitHub-репозитория текстового ассистента.

Шаг 3. Установка соединения и применение настроек

1️⃣ Создайте WebSocket-соединение и передайте конфигурацию:

await setup_session(ws) 

Функция setup_session(ws) полностью задаёт поведение ассистента: устанавливает системные инструкции, регистрирует инструменты и конфигурирует VAD.Можно запускать отправку и приём аудио.

Шаг 4. Отправка аудио (uplink)

Передача аудио с микрофона на сервер происходит внутри функции uplink(ws) — она запускается параллельно с приёмом ответов. Основной цикл:

async for pcm in mic:
    await ws.send_json({
        "type": "input_audio_buffer.append",
        "audio": b64_encode(pcm)
    }) 

Каждый PCM-чанк берётся из AsyncMicrophone, кодируется в base64 и отправляется как JSON-событие. Таким образом ассистент начинает слышать клиента в реальном времени.

Шаг 5. Приём событий от сервера (downlink)

После того как вы настроили микрофон и начали передавать аудиопоток на сервер, Realtime API начинает отвечать цепочкой событий разных типов.На этом этапе начинается взаимодействие с готовым ассистентом: модель слушает, распознаёт речь, генерирует текст, синтезирует голос, вызывает инструменты и сообщает об этом через WebSocket.Теперь нужно подключить вторую половину диалога: обработку всех событий, которые сервер присылает в ответ на вашу речь и действия ассистента. Функция downlink(ws, audio_out) принимает эти события и управляет работой ассистента:

  • отслеживает, когда пользователь закончил говорить;
  • получает распознанный текст и фрагменты ответа;
  • передаёт аудио на воспроизведение;
  • прерывает ассистента при необходимости;
  • обрабатывает вызовы функций модели.

❗️ Эта часть критична: без обработки событий модель не сможет полноценно вести диалог — вы будете только отправлять аудио.

Ключевые события сервера

Событие о распознанной речи пользователя. Сигнализирует, что VAD определил конец фразы:

case "conversation.item.input_audio_transcription.completed":
    transcript = message.get("transcript") 

Частичная генерация текста. Во время ответа модель отправляет текст по частям. Каждый такой фрагмент называется дельтой — это изменение по сравнению с предыдущим состоянием. Дельты помогают отображать текст постепенно, в реальном времени:

case "response.output_text.delta":
    delta = message.get("delta") 

Дельта аудиоответа. Сервер присылает звук частями, а вы их декодируете и проигрываете:

case "response.output_audio.delta":
    decoded = b64_decode(message["delta"])
    await audio_out.write(decoded) 

Событие начала речи. Когда пользователь начинает говорить во время синтеза, сервер присылает это событие:

case "input_audio_buffer.speech_started":
    play_epoch += 1
    await audio_out.clear() 

Здесь используется счетчик play_epoch, который отделяет актуальный ответ от устаревшего — в случаях, когда пользователь перебивает ассистента. Когда пользователь начинает говорить, нужно увеличить play_epoch и очистить буфер audio_out. После этого старые аудиофрагменты больше не воспроизводятся.Вызов рукописной функции

case "response.output_item.done":
    if item.get("type") == 'function_call':
        payload_item = process_function_call(item)
        await ws.send_json(payload_item)
        await ws.send_json({ "type": "response.create" }) 

Работа идёт по такой схеме:

  1. Модель вызывает функцию и отправляет JSON.
  2. Вы выполняете нужную Python-функцию.
  3. Отправляете результат обратно на сервер.
  4. Отправляете событие response.create, чтобы модель продолжила ответ.

Шаг 6. Запуск главного цикла приложения

1️⃣ Объедините uplink и downlink в одном асинхронном цикле:

async with session.ws_connect(...) as ws:
    await setup_session(ws)
    async with AsyncAudioOut(...) as audio_out:
        await asyncio.gather(
            uplink(ws),
            downlink(ws, audio_out),
        ) 

Здесь одновременно запускаются два аудиопотока:

  • uplink — от микрофона в сервер;
  • downlink — от сервера сервер в динамик.

После этого ассистент начинает работать в реальном времени: распознаёт речь, понимает запрос, вызывает функции, умеет перебивать и поддерживать диалог.

Итоги урока

Прототип голосового ассистента на базе Realtime API можно собрать без большого инфраструктурного кода. Ассистент поддерживает потоковое распознавание речи, синтез, обработку интентов через функции, доступ к базе знаний и перебивания в диалоге.Фитнес-ассистент из практики — готовая архитектурная схема для любых голосовых агентов: клиентской поддержки, helpdesk-сценариев, образовательно-спортивных приложений и персональных помощников.

Realtime API берёт на себя всю сложность аудиовзаимодействия и оркестрации модели. Вы описываете только логику продукта. Удобно!Благодаря этому не нужно реализовывать низкоуровневую работу с аудио: обработку событий Realtime API и сценарную логику агента можно задать прямо в коде. Вы фокусируетесь на сценариях, функциях, инструментах и качестве взаимодействия.

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

В следующем уроке вы разберёте low-code-подход. Узнаете, как быстро создавать агентов и встраивать их в бизнес-процессы в визуальном конструкторе Workflows.❗Не забудьте остановить ресурсы, чтобы избежать лишних трат.

Источник: https://practicum.yandex.ru/trainer/yc-ml-aiagents/lesson/91e7e5e9-5797-49ba-8c3d-9b76466c0ff9/

Рубрики: Uncategorized

0 комментариев

Добавить комментарий

Заполнитель аватара

Ваш адрес email не будет опубликован.