В эпоху, когда искусственный интеллект перестает быть просто текстовым чат-ботом и начинает говорить, понимание архитектуры голосовых агентов становится критически важным навыком для разработчиков. Представьте себе сценарий: клиент звонит в ресторан, и вместо того чтобы слушать бесконечное меню опций IVR, он общается с естественным, умным ассистентом, который понимает контекст, проверяет наличие столиков в реальном времени и подтверждает бронь. За этим простым, на первый взгляд, сценарием скрывается сложная инженерная работа: обработка речи, управление состоянием, безопасность ответов и оптимизация задержек.
В этой статье мы подробно разберем, как построить такой голосовой агент, используя Patter SDK. Мы не просто напишем код — мы создадим полноценный рабочий процесс, который симулирует реальный телефонный звонок. Вы узнаете, как внедрить динамические переменные, зарегистрировать инструменты (tools), настроить guardrails (защитные механизмы) для безопасности ответов, а также как измерять и оптимизировать метрики, такие как задержка (latency) и стоимость запросов. Это руководство предназначено для тех, кто хочет перейти от простых диалоговых ботов к robust-решениям, готовым к продакшену.
01Настройка окружения и интеграция с Patter SDK
Первый шаг в создании любого AI-агента — это правильная настройка среды. В нашем случае мы используем Python-скрипт, который автоматически управляет зависимостями. Код начинается с импорта стандартных библиотек, таких как subprocess, importlib и inspect, которые необходимы для динамической установки и проверки модулей. Ключевая функция _try_install пытается установить пакет getpatter через pip, если он еще не установлен. Это делает скрипт самодостаточным: вы можете запустить его в любой среде (например, Google Colab или локальном сервере), и он сам позаботится о наличии нужной библиотеки.
Важным аспектом является функция _load_patter. Она пытается импортировать модуль patter или getpatter. Если импорт успешен, скрипт выводит информацию об установленной версии и доступных методах API. Это критически важно, так как SDK для AI-агентов часто обновляются, и проверка актуального API помогает избежать ошибок совместимости. Если модуль не найден, скрипт продолжает работу в режиме симуляции, что позволяет тестировать логику даже без подключения к внешним сервисам.
Параллельно с настройкой SDK мы создаем «бэкенд» ресторана. Поскольку у нас нет доступа к реальной базе данных ресторана в рамках демо, мы используем in-memory структуры данных. Классы dataclass и словари _OPEN_TABLES и _RES_DB имитируют базу данных доступных столиков и подтвержденных бронирований. Функция _reset_backend гарантирует, что каждый симулируемый звонок начинается с чистого листа, что необходимо для детерминированного тестирования и регрессионных проверок.
02Реестр инструментов (Tools) и логика бронирования
Сила агента заключается в его способности выполнять действия. В Patter SDK инструменты регистрируются через декоратор @tool. Мы определяем пять ключевых функций, которые имитируют работу ресторана:
- check_availability: Проверяет, есть ли свободные места на нужную дату, время и количество гостей. Возвращает строку с статусом «AVAILABLE» или «FULL».
- book_table: Создает бронь, уменьшает количество доступных мест и генерирует уникальный код подтверждения (например, AC8842).
- get_hours: Возвращает часы работы ресторана в зависимости от дня недели (будни/выходные).
- lookup_reservation: Ищет существующее бронирование по коду подтверждения.
- transfer_to_human: Имитирует передачу звонка живому оператору, если агент не может решить проблему.

Каждый инструмент принимает аргументы, которые агент извлекает из речи пользователя. Например, book_table требует имя, дату, слот (lunch/dinner/late) и размер группы. Логика этих функций проста, но она формирует основу для принятия решений агентом. Важно отметить, что в реальном проекте эти функции будут обращаться к SQL-базе данных или внешним API, но для демонстрации архитектуры in-memory подход полностью оправдан.
03Guardrails: Безопасность и качество ответов
Одной из самых больших проблем голосовых AI-агентов является риск генерации некорректных, оскорбительных или конфиденциальных данных. Именно здесь вступают в игру Guardrails (защитные механизмы). В нашем коде определен класс GuardrailBlock и набор функций-фильтров, которые применяются к каждому ответу агента перед тем, как он будет преобразован в речь (TTS).
Мы используем регулярные выражения для выявления и маскировки чувствительной информации:
- PII (Personally Identifiable Information): Функция
gr_redact_piiзаменяет email-адреса и номера телефонов на заглушки[email hidden]и[number hidden]. Это критически важно для соблюдения GDPR и других норм конфиденциальности. - Внутренние идентификаторы: Функция
gr_hide_internal_idsскрывает технические коды клиентов (например, CUST-1234), заменяя их на нейтральные фразы, чтобы пользователь не видел внутренней кухни системы. - Нецензурная лексика:
gr_profanityфильтрует грубые слова, заменяя их на дефисы. - Выход за рамки компетенции:
gr_scopeпроверяет, не пытается ли пользователь получить юридическую или медицинскую консультацию. Если да, агент вежливо отказывает, ссылаясь на свою специализацию (бронирование столиков). - Краткость:
gr_conciseобрезает ответы, чтобы они не были слишком длинными для телефонного разговора. В голосовом интерфейсе длинные монологи раздражают пользователей.
Функция apply_guardrails последовательно применяет все эти фильтры к тексту, сгенерированному агентом. Если какой-то фильтр выбрасывает исключение GuardrailBlock, система подставляет безопасный ответ по умолчанию. Это обеспечивает стабильность диалога даже в нештатных ситуациях.
04Симуляция речи: STT и TTS
В голосовом агенте текст не просто появляется на экране — он произносится и записывается. Чтобы протестировать логику без подключения к реальным сервисам распознавания (STT) и синтеза речи (TTS), мы создаем имитаторы fake_stt и fake_tts.

Функция fake_stt принимает текст пользователя, удаляет слова-паразиты (uh, um, you know), которые часто встречаются в живой речи, и рассчитывает задержку. Задержка моделируется на основе длины текста и случайной вариации, что позволяет оценить, как агент будет вести себя в условиях реального сетевого шума. Аналогично, fake_tts рассчитывает время синтеза речи. Эти метрики накапливаются в объектах Turn, что позволяет нам строить дашборды производительности.
05Мозг агента (Agent Brain) и управление состоянием
Центральная часть системы — функция agent_brain. Это конечный автомат, который определяет, что делать дальше, основываясь на текущем вводе пользователя и истории диалога. Она использует контекстный словарь ctx, который хранит состояние: имя клиента, уровень лояльности, текущий этап бронирования (собран ли размер группы, дата, время).
Логика работы агента выглядит следующим образом:
- Распознавание намерения: Агент ищет ключевые слова (book, hours, human, reservation code).
- Извлечение сущностей: Если пользователь хочет забронировать столик, агент использует функции
parse_party,parse_date,parse_slotиparse_nameдля извлечения структурированных данных из неструктурированного текста. Например, фраза «хочу столик на двоих завтра вечером» будет преобразована вparty_size=2,date=tomorrow,slot=evening. - Вызов инструментов: Если данных достаточно, агент вызывает соответствующий инструмент (например,
check_availability). Если данных не хватает, он задает уточняющий вопрос (например, «А на какое имя оформить?»). - Обработка результата: Функция
fold_tool_resultпреобразует сырой ответ от инструмента (например, «BOOKED: code AC1234») в естественную человеческую фразу («Отлично, ваш код подтверждения AC1234»).
Этот подход позволяет агенту вести многошаговый диалог, не теряя нити разговора. Он помнит, что уже спросил про дату, и не будет спрашивать об этом снова, если пользователь уже предоставил эту информацию.
agent_brain часто используется LLM (Large Language Model) с функциями (Function Calling). Однако в данном примере мы используем детерминированную логику на Python для демонстрации контроля над процессом. Это позволяет полностью избежать галлюцинаций модели и гарантирует, что агент никогда не предложит несуществующее время или не нарушит бизнес-логику.06Симуляция звонка и сбор метрик
Функция run_call запускает полный цикл симуляции. Она принимает список реплик пользователя (сценарий звонка) и переменные контекста. Внутри цикла происходит следующее:

- Реплика пользователя преобразуется в текст (STT) с измерением задержки.
- Агент обрабатывает текст и генерирует ответ (LLM/Brain) с измерением задержки.
- Если вызывается инструмент, измеряется время его выполнения.
- Ответ проходит через Guardrails.
- Ответ преобразуется в речь (TTS) с измерением задержки.
Все эти данные сохраняются в объекте CallResult, который содержит транскрипт всего разговора и список Turns (реплик) с подробными метриками времени. Это позволяет нам не только увидеть, *что* сказал агент, но и *как быстро* он это сделал.
07Визуализация и оценка (Evals)
После запуска симуляции мы можем вывести красивый транскрипт звонка с помощью функции print_transcript. Она форматирует диалог, разделяя реплики агента и пользователя, и показывает, кто что сказал. Но главное — это возможность проанализировать задержки. Суммируя stt_ms, llm_ms, tool_ms и tts_ms для каждого хода, мы получаем общую задержку ответа.
В голосовом интерфейсе задержка более 1-2 секунд заметна пользователю и может создать ощущение «тупика». Поэтому оптимизация каждого этапа критична. Например, если tool_ms слишком велик, нужно кэшировать данные или оптимизировать запросы к базе. Если llm_ms высок, возможно, стоит использовать более быструю модель или оптимизировать промпт.
08Что это значит на практике
Разбор архитектуры Patter SDK через призму задачи бронирования ресторана демонстрирует, что создание голосового AI-агента — это не просто вызов API нейросети. Это комплексная инженерная задача, требующая:
- Четкого разделения ответственности: Логика диалога, безопасность ответов, работа с данными и обработка речи должны быть модульными.
- Учета человеческого фактора: Guardrails и краткость ответов делают общение естественным и безопасным.
- Мониторинга производительности: Без измерения задержек на каждом этапе невозможно оптимизировать пользовательский опыт.
- Симуляции перед запуском: Возможность протестировать сценарии без реальных звонков экономит время и деньги.
Для разработчиков в России это означает, что можно адаптировать данный подход под локальные сервисы. Например, заменить fake_stt на интеграцию с Yandex SpeechKit или SberSpeech, а fake_tts — на голосовые движки от российских провайдеров. Логика агента, guardrails и управление состоянием останутся неизменными, что делает архитектуру универсальной и гибкой. Изучение таких SDK позволяет создавать конкурентоспособные AI-решения, которые не уступают зарубежным аналогам по качеству и надежности, но при этом полностью соответствуют локальным требованиям и инфраструктуре.
Источник: MarkTechPost ↗
