Голосовой агент должен не просто генерировать хороший ответ. Он должен понимать, что сказал собеседник, принимать решение о дальнейших действиях, вызывать необходимые инструменты и начинать говорить до того, как пауза станет неловкой.
В этом руководстве мы создадим такой полный цикл на Python. Наш пример — агент для бронирования столиков в ресторане, который расшифровывает речь звонящего, проверяет наличие свободных мест с помощью инструментов и преобразует ответ обратно в речь. Преобразование речи в текст, LLM и преобразование текста в речь работают через один ключ API OpenRouter, и мы передаем каждое завершенное предложение в TTS потоком, вместо того чтобы ждать всего ответа целиком.
За все 12 итераций в трех тестовых диалогах медианное время на стороне сервера до появления первого аудио составило 1,9 секунды, а стоимость диалога из четырех итераций составила около $0,013 за минуту обработанной речи по акционным ценам, доступным во время нашего теста 8 октября.
Кратко (TL;DR)
- Преобразование текста в речь составило примерно 90% от измеренной стоимости модели, что делает длину голосового ответа важным фактором стоимости для этого агента.
Преобразование текста в речь составило примерно 90% от измеренной стоимости модели, что делает длину голосового ответа важным фактором стоимости для этого агента.
- Время на стороне сервера до появления первого аудио составило примерно 1,4 секунды для обычных итераций и 2,4 секунды для итераций с использованием инструментов в нашем тесте, при расчете одного запроса к LLM на итерацию. Пример кода выполняет дополнительные запросы к LLM, а сеть и воспроизведение добавляют время.
Время на стороне сервера до появления первого аудио составило примерно 1,4 секунды для обычных итераций и 2,4 секунды для итераций с использованием инструментов в нашем тесте, при расчете одного запроса к LLM на итерацию. Пример кода выполняет дополнительные запросы к LLM, а сеть и воспроизведение добавляют время.
- Имена было сложнее расшифровать, чем номера телефонов. Попросите звонящих подтвердить важные детали перед выполнением действий.
Имена было сложнее расшифровать, чем номера телефонов. Попросите звонящих подтвердить важные детали перед выполнением действий.
- Отправка завершенных предложений в систему преобразования текста в речь (TTS) может сократить время ожидания голосового вывода, но воспроизведение в реальном времени и прерывания требуют дополнительной оркестрации.
Отправка завершенных предложений в систему преобразования текста в речь (TTS) может сократить время ожидания голосового вывода, но воспроизведение в реальном времени и прерывания требуют дополнительной оркестрации.
Как работает итерация голосового ИИ-агента
Голосовой агент принимает речь звонящего, преобразует ее в текст, передает в LLM для принятия решения о действиях и преобразует ответ обратно в речь. Вот как работает этот процесс:
Например, когда кто-то звонит в наш ресторан, чтобы забронировать столик, LLM может потребоваться вызвать check_availability перед ответом. Ваше приложение выполняет функцию, отправляет доступное время обратно модели и ждет, пока она сгенерирует ответ. Этот дополнительный цикл увеличивает время ожидания звонящего.
Чтобы сократить это ожидание, мы можем начать генерировать речь до того, как LLM завершит весь ответ. Вместо ожидания полного текста мы будем передавать ответ потоком, разбивать его на предложения и отправлять каждое завершенное предложение в TTS, пока модель продолжает генерировать остальное.
Для этой сборки мы будем использовать наш API преобразования речи в текст для расшифровки звонящего, Chat Completions с вызовом инструментов для обработки диалога и бронирований, а также наш API преобразования текста в речь для генерации голосового ответа.
API транскрипции возвращает текст в формате JSON, а API речи возвращает аудиобайты. Наш пример на Python сохранит сгенерированное аудио в виде WAV-файлов, а позже мы будем использовать LiveKit для обработки живого аудио и прерываний.
Создание голосового агента на Python
Давайте создадим агента для бронирования в ресторане, используя три модели: elevenlabs/scribe-v2 для транскрипции, openai/gpt-6-luna для диалога и вызовов инструментов, и elevenlabs/eleven-flash-v2.5 для генерации речи.
Вам потребуется Python 3.10 или новее и ключ API OpenRouter. Установите библиотеку requests и установите свой ключ API в качестве переменной окружения:
Чтобы пример было легко воспроизвести, мы будем использовать второй голос TTS для имитации четырех итераций звонящего вместо подключения микрофона. Мы также будем использовать фиктивные данные бронирования, чтобы агент мог проверять наличие мест и возвращать детали бронирования без реальной системы бронирования.
Сохраните следующий код как voice_agent.py:
Скрипт соединяет три API через run_turn(), который расшифровывает каждое сообщение звонящего, передает транскрипт в LLM и обрабатывает ответ. Если LLM запрашивает инструмент, функция выполняет его, добавляет результат в историю диалога и делает еще один запрос, чтобы модель могла продолжить.
Посмотрите, как stream_reply() обрабатывает вызовы инструментов. Модель передает имена функций и аргументы фрагментами, поэтому мы собираем их перед выполнением инструмента. Для голосовых ответов мы отправляем завершенные предложения в TTS через пул потоков, позволяя генерации речи перекрываться с оставшимся выводом LLM.
Затем мы объединяем аудио в порядке предложений и сохраняем его как WAV-файл. Мы обработаем фактическое воспроизведение и прерывания, когда внедрим LiveKit.
Вы можете запустить скрипт с помощью этой команды:
Он должен создать четыре аудиофайла, от agent_1.wav до agent_4.wav, и вывести диалог. Вот отрывок из одного из наших тестовых прогонов. Строки звонящего показывают расшифрованное аудио, поэтому цифры могут отличаться от того, как они были произнесены.
Пример показывает, как агент проверяет наличие мест перед тем, как предложить другое время, а затем вызывает book_table после того, как звонящий соглашается. Он также отказывается обещать текстовое подтверждение, потому что мы не предоставили инструмент для его отправки.
Почему этот дизайн работает и что его ломает
Ответ может выглядеть совершенно нормально в окне чата, но звучать странно при чтении вслух. Время, номера телефонов и разметка — хорошие примеры. Вот почему наш системный промпт просит LLM делать ответы короткими, избегать форматирования и записывать время словами, например «восемь пятнадцать» вместо 8:15.
Та же проблема может возникнуть в обратном порядке. В нашем тесте преобразование речи в текст превратило «восемь пятнадцать» в 815, но LLM правильно поняла ответ звонящего, потому что у нее был контекст предыдущего диалога. Мы сохраняем эту историю в сообщениях и отправляем ее с каждым запросом, так как Chat Completions не сохраняет предыдущие итерации автоматически. В результате промпт вырос примерно с 290 токенов на первой итерации до 490 на четвертой.
Еще одно важное соображение — убедиться, что агент подтверждает только те действия, которые действительно произошли. В более ранней версии без book_table агент мог сказать звонящим, что их бронирование подтверждено, хотя приложение его не создало.
Вот почему инструмент бронирования должен делать больше, чем просто возвращать ответ. При подключении к реальной системе бронирования он должен проверять наличие мест, сохранять бронирование и возвращать подтверждение только тогда, когда операция прошла успешно.
Насколько быстр голосовой ИИ-агент?
За все 12 итераций медианное время на стороне сервера до появления первого аудио составило 1,9 секунды. По типу итерации медиана составила 1,4 секунды без инструментов и 2,4 секунды, когда агенту нужно было вызвать инструмент.
Мы измерили три полных диалога, состоящих из 12 реплик, используя наши метаданные генерации для оценки серверной задержки на каждом этапе. Это позволило нам отделить время обработки моделью от дополнительных сетевых накладных расходов в нашей тестовой среде.
Вот как соотносятся результаты:
Дополнительный запрос к LLM обуславливает большую часть разницы. Когда агенту необходимо проверить доступность, он должен дождаться результатов работы инструмента, прежде чем формировать ответ.
Эти показатели отражают серверную обработку, а не полное время, которое ощущает вызывающий абонент. Сетевая доставка, определение момента завершения речи абонента и воспроизведение аудио вносят дополнительные задержки. Медианные значения для отдельных этапов также не обязательно суммируются в общую медиану. Кроме того, оценки учитывают один запрос LLM за реплику. Пример кода ниже делает два запроса на каждой реплике: не потоковый запрос для проверки вызовов инструментов и затем потоковый запрос для ответа, а реплики с инструментами делают еще один запрос после выполнения инструмента, поэтому ожидайте, что это займет больше времени, чем данные цифры.
Сравнения моделей ниже используют отдельные тестовые прогоны и входные данные, поэтому их заявленная задержка отличается от измерений полных диалогов, представленных здесь.
Сколько стоит голосовой ИИ-агент?
По результатам пяти прогонов стоимость нашего четырехшагового диалога в ресторане составила от 0,0069 до 0,0087 долл. США. Каждый вызов содержал примерно 38 секунд речи, что дает нам ориентировочную стоимость 0,013 долл. США за минуту обработанной речи по ценам, действовавшим 8 октября 2026 года.
Большая часть этой стоимости пришлась на генерацию голоса агента.
Указанные выше цены ElevenLabs включали 50-процентную скидку при запуске, которая действовала до 19 октября 2026 года. По стандартным прейскурантным расценкам Eleven Flash v2.5 стоит 40 долларов США за миллион символов, в то время как Scribe v2 стоит примерно 0,22 доллара США за час аудио. При том же объеме использования наш разговор обойдется примерно в 0,025 доллара США за минуту обработанной речи. Это расчет, основанный на наших измерениях от 8 октября, а не отдельный тест выставления счетов.
Детализация затрат по-прежнему полезна. В этом диалоге на TTS пришлось около 90% наших расходов, поэтому сохранение устных ответов агента короткими оказало бы большее влияние на стоимость, чем небольшое сокращение использования токенов LLM.
Вы также можете отслеживать реальную стоимость отдельных запросов. Ответы транскрипции включают usage.cost, в то время как ответы синтеза речи предоставляют заголовок X-Generation-Id, который можно использовать для получения стоимости через наш API метаданных генерации.
Какую модель распознавания речи следует использовать?
Для агента по бронированию в ресторане точность транскрипции имеет наибольшее значение, когда абонент упоминает детали, на которые агент должен отреагировать, такие как имена, даты, номера телефонов и время бронирования.
Чтобы сравнить модели, мы сгенерировали девять реплик абонента, используя три синтетических голоса, а затем создали чистые версии каждой записи и версии с качеством телефонного звонка. В результате мы получили 50 аудиоклипов с оценкой 90 фактов на модель за время теста.
Мы оценили десять моделей STT. В таблице ниже показаны пять из них, демонстрирующие диапазон точности и задержки, которые мы наблюдали.
MAI-Transcribe 2 сохранила больше всего фактов, но Scribe v2 оказалась значительно быстрее, уступив всего по одному факту. Whisper Large V3 совпала по оценке со Scribe, но отвечала дольше. Для нашего агента по бронированию Scribe v2 предложила хороший баланс точности и скорости, поэтому мы выбрали ее для реализации на Python.
Каждый распознаватель совершал ошибки в необычных именных собственных, даже если номер телефона сохранялся правильно. Например, имя «Siobhan Okafor» появилось в стенограммах как «Shioban Okafor», «Siobhan O’Keefe» и «Siobhan Akhefer».
Вместо того чтобы полагаться на то, что расшифрованное имя указано верно, заставьте агента подтвердить его у абонента или попросить его по буквам перед завершением бронирования.
Имейте в виду, что эти результаты получены на основе синтетических английских записей, а не реальных звонков клиентов с разными акцентами и в различных условиях. Вы можете изучить доступные модели транскрипции, но стоит протестировать отобранные модели на аудиозаписях, отражающих ваш собственный сценарий использования.
Какую модель LLM и преобразования текста в речь следует использовать?
Что касается LLM, мы оценили точность вызова инструментов, время ответа и то, насколько естественно звучал бы сгенерированный текст.
Каждая LLM в нашем сравнении запросила ожидаемый инструмент бронирования во всех пяти прогонах. Различия свелись к скорости ответа и форматированию ответа.
Одно из различий заключалось в том, как модели обрабатывали произносимое время. Claude Haiku 5.5 в каждом прогоне записывала 7:30 вместо запрошенной устной формы, а в одной из конфигураций она также включала свой расчет даты в видимый ответ. Оба этих поведения имеют значение, когда ответ отправляется напрямую в TTS.
Эти результаты получены в результате отдельного сравнения моделей из пяти прогонов, а не измерений полного диалога, приведенных выше. Они измеряют время до появления первого токена ответа при тестируемых настройках модели.
Рассуждения также повлияли на задержку. В нашем сравнении GPT-6 Luna отключение рассуждений сократило время до появления первого токена ответа с 2,3 секунды до 1,6 секунды для тестируемого вызова инструмента. Это полезно для относительно ограниченной задачи бронирования, при условии, что модель продолжает делать правильные вызовы инструментов.
Выбор модели преобразования текста в речь
Для TTS мы сосредоточились на том, как быстро каждая модель начинала возвращать аудио. Мы отправили один и тот же ответ из 101 символа двенадцати моделям, повторяя запрос пять раз для каждой модели.
Ниже приведены шесть репрезентативных результатов:
Ценообразование Gemini использует другую единицу выставления счетов, поэтому мы исключили ее из сравнения стоимости за символ, вместо того чтобы рассматривать расчетную конверсию как прейскурантную ставку.
Grok Voice и Kokoro возвращали свои первые аудиобайты быстрее всего по результатам измерений на стороне сервера, в то время как Eleven Flash v2.5 также показала хорошие результаты.
Однако время, сообщаемое сервером, не всегда совпадало с тем, что испытывало наше приложение. У Kokoro медианная задержка сервера составляла менее 100 миллисекунд, но ее аудио поступало в нашу тестовую среду от трех до восьми секунд.
Именно поэтому вам следует измерять задержку в собственном приложении, особенно при создании чего-то интерактивного. Вам также захочется прослушать сгенерированную речь и проверить произношение, прежде чем выбирать модель только на основе скорости.
Для этой реализации мы использовали Eleven Flash v2.5. Вы можете просмотреть доступные голосовые модели и заменить ее другим вариантом, используя слаг модели.
Запуск того же агента с LiveKit Agents
Наш скрипт на Python обрабатывает транскрипцию, вызовы инструментов и генерацию речи, но он не поддерживает живой диалог с агентом. Для этого нам также нужно обрабатывать ввод с микрофона, определять момент завершения речи абонента и управлять прерываниями.
Для этого мы можем использовать LiveKit Agents. Этот инструмент управляет аудиосоединением в реальном времени и ходом диалога, позволяя нам продолжать использовать те же три модели через OpenRouter.
Сначала установите LiveKit Agents с плагином OpenAI:
Вам также понадобятся LIVEKIT_URL, LIVEKIT_API_KEY и LIVEKIT_API_SECRET из вашего проекта LiveKit, а также OPENROUTER_API_KEY, который мы настроили ранее. Следуйте инструкциям из краткого руководства LiveKit, если вы еще не настроили проект.
Сохраните следующий код в файл live_agent.py рядом с voice_agent.py. Мы повторно используем инструкции для ресторана и функции бронирования из предыдущего примера.
AgentSession связывает три модели воедино, а модуль определения активности речи (VAD) Silero помогает понять, когда звонящий закончил говорить, чтобы LiveKit мог отправить аудио на транскрипцию. LiveKit также управляет воспроизведением речи и прерываниями.
Обратите внимание, что функции бронирования не изменились. Декоратор @function_tool от LiveKit делает их доступными для LLM, и каждая функция передает данные звонящего в ту же тестовую службу бронирования.
Вы можете протестировать агента локально с помощью микрофона:
Чтобы подключить его к своему проекту LiveKit для тестирования через консоль агента, выполните:
Попробуйте запросить столик на шестерых на семь тридцать, а затем согласиться на восемь пятнадцать. В нашем предыдущем текстовом тесте LiveKit это привело к следующим вызовам инструментов:
Эта настройка связывает инструменты бронирования с аудиосеансом LiveKit, поэтому вы можете протестировать тот же диалог с помощью микрофона. Вы также можете использовать наше руководство по интеграции LiveKit, чтобы изучить резервные модели и маршрутизацию провайдеров.
Ошибки, с которыми вы, скорее всего, столкнетесь
В процессе тестирования мы столкнулись с несколькими ошибками, вызванными отсутствием параметров или неподдерживаемыми настройками моделей. Все три вернули ответы HTTP 400:
Наш API преобразования речи в текст ожидает байты аудио, закодированные в формате base64 в поле input_audio.data, без префикса data:audio/…;base64,. Вы также должны указать формат аудио, например wav или mp3.
Имена голосов также различаются в зависимости от провайдера. Например, голос OpenAI, такой как alloy, не будет автоматически работать с ElevenLabs. Вы можете проверить поддерживаемые голоса каждой модели в нашей документации по преобразонию текста в речь или через API моделей.
Еще одна проблема, с которой мы столкнулись, заключалась в том, что пустой ввод TTS возвращал короткий аудиоклип. Перед отправкой запросов на синтез речи стоит отфильтровывать пустые строки.
Нужна ли вам модель speech-to-speech?
Не для этого примера. Созданный нами раздельный конвейер распознавания речи, LLM и синтеза речи вполне справляется с нашим рабочим процессом бронирования столиков в ресторане.
Мы также протестировали отправку аудио звонящего напрямую четырем LLM с поддержкой аудио: Gemini 3.8 Flash, Qwen3.8 Omni Flash, MiMo V2.6 Flash и GPT Audio Mini. Они выбрали ожидаемые инструменты бронирования во всех 12 тестовых заходах.
Это показывает, что эти модели могут справиться с задачей вызова инструментов в нашем примере без отдельного запроса транскрипции. Тем не менее, мы не измеряли полноценный разговор в режиме speech-to-speech, поэтому эти результаты не дают ответа на вопрос, будет ли такой подход работать быстрее или выдавать более качественные устные ответы.
При использовании трехэтапного подхода мы можем изучить транскрипцию, определить, где возникают ошибки, и независимо изменять транскрипцию, язык или речевую модель. Модель, которая работает с аудиовходом и выходом напрямую, может упростить конвейер, но перед выбором стоит сравнить общее время отклика, качество звука и обработку прерываний.
Заключение
Наш пример на Python — это отправная точка. Прежде чем подключать агента к реальным абонентам, замените функции фиктивного бронирования собственным бэкендом и протестируйте его на реальной речи. Только системный промпт заставляет агента ждать согласия звонящего, прежде чем вызывать book_table, поэтому ваш бэкенд должен подтвердить бронирование до того, как записать его. Измеряйте полное время отклика, включая доставку по сети и воспроизведение, а не полагайтесь только на задержку на стороне сервера.
Если вам нужен живой звук и обработка прерываний, используйте LiveKit, сохраняя при этом те же модели через OpenRouter.
Часто задаваемые вопросы
Как подключить голосового ИИ-агента к реальному номеру телефона?
Вы можете подключить голосового ИИ-агента к номеру телефона с помощью телефонии LiveKit. LiveKit поддерживает входящие вызовы через службу телефонных номеров или SIP-провайдера. Настройте необходимый транк и правило распределения для маршрутизации входящих вызовов в комнату LiveKit, где ваш агент сможет присоединиться к беседе. Инструкции по настройке см. в документации по телефонии LiveKit.
Может ли голосовой ИИ-агент обрабатывать прерывания?
Да. Такой фреймворк, как LiveKit, может обнаруживать, когда кто-то начинает говорить во время ответа агента, приостанавливать речь агента и продолжать диалог с учетом нового ввода.
Имейте в виду, что прерывание речи не приводит к автоматической отмене уже запущенного инструмента. Для таких операций, как бронирование или платежи, ваше приложение должно тщательно обрабатывать отмену и подтверждение.
Могу ли я использовать собственный голос для ИИ-агента?
Да, если вы выберете модель преобразования текста в речь, поддерживающую клонирование голоса. Некоторые модели на OpenRouter принимают эталонное аудио через параметр input_references и генерируют речь с этим голосом без необходимости отдельного процесса обучения голоса.
Поддержка клонирования голоса зависит от модели и эндпоинта провайдера, поэтому перед выбором модели ознакомьтесь с документацией по TTS. Используйте только те записи, на воспроизведение которых у вас есть разрешение.
Могу ли я подключить голосового агента к реальной системе бронирования или другим API?
Да. Функции check_availability и book_table в нашем примере используют тестовые данные, но вы можете заменить их реализацию запросами к вашему API бронирования или базе данных.
LLM по-прежнему определяет, когда вызывать каждую функцию, в то время как ваше приложение обрабатывает саму операцию и возвращает результат. Для таких действий, как бронирование столика или отправка подтверждения, убедитесь, что операция прошла успешно, прежде чем сообщать звонящему о ее завершении.









