Stone — Saqta Insurance Voice Router
Голосовой агент вымышленной страховой компании.
О проекте
Команда: Stone
Кейс HackAlem.ai: Коммуникации — Halyk Bank · кейс 2
Стадия: Доведённый продукт
Задача кейса: «Voice Router»: голосовой AI, маршрутизирующий звонки в контакт-центре страховой компании
Суть
Голосовой агент вымышленной страховой компании. Распознаёт русскую, казахскую и смешанную речь, LLM маршрутизирует запрос в один из 40 сценариев или 3 системных намерений и извлекает слоты. Затем выполняются мок-действия с подтверждением, ответ озвучивается.
Как устроено
Streamlit пишет звук с микрофона → gpt-4o-transcribe (язык не фиксируется, чтобы не терять смешанную речь) → предварительное определение языка и нормализация телефона → роутер gpt-4o-mini возвращает JSON со сценариями, уверенностью и слотами. Каталог сценариев и RU/KK-примеры передаются в промпт. decision_policy применяет пороги 0,75/0,45. executor проверяет идентификацию и слоты и требует подтверждения перед необратимыми действиями. actions_mock работает с синтетическим бэкендом. Ответ озвучивает gpt-4o-mini-tts, trace-панель показывает тайминги STT/router/TTS.
Ключевые решения
- LLM intent routing
- slot filling
- пороги уверенности
- multi-intent
- few-shot примеры в промпте
- confirmation flow
- определение языка RU/KK/mixed
Метрики
Dev-набор (104 реплики, официальный evaluate.py): точность основного сценария 99,0% (103/104), полное совпадение списка 97,1%, полнота интентов в многоцелевых запросах 92,3%
Особенности
Оценка сделана официальным evaluate.py, а ручные правила, переписывавшие выбор модели, удалены. Язык ответа выбирается по преобладающему языку клиента. Необратимые действия (create_policy) ждут подтверждения в статусе pending.
Стек
Python · Streamlit · OpenAI API · python-dotenv · unittest
Модели
gpt-4o-transcribe · gpt-4o-mini · gpt-4o-mini-tts
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-8c2ebcfc-stone.
README
README.mdStone — Saqta Insurance Voice Router
Описание решения и назначение
Веб-демо голосового агента вымышленной страховой компании Saqta Insurance. LLM выбирает сценарии из 40 бизнес-сценариев и трёх системных намерений, извлекает слоты, а приложение выполняет мок-действия над синтетическим датасетом. Основной ввод — микрофон, ответ озвучивается; текст доступен как дополнение. Данные и цены не относятся к реальной страховой компании.
Архитектура
app.py записывает микрофон → backend.speech распознаёт RU/KK/mixed через gpt-4o-transcribe → backend.language предварительно определяет язык, backend.triage нормализует телефон → backend.router через OpenAI API возвращает JSON с выбранными сценариями, уверенностью и слотами → backend.decision_policy применяет пороги 0,75/0,45 → backend.executor проверяет идентификацию и слоты, показывает предварительный результат и запрашивает подтверждение перед необратимыми действиями → backend.actions_mock обращается к синтетическим данным. Язык из LLM-ответа определяет язык реплики бота; для смешанной речи выбирается преобладающий язык клиента. Каталожные вопросы уже двуязычные, динамические данные переводит отдельный слой представления, не выбирающий сценарии. gpt-4o-mini-tts озвучивает ответ. Справа показаны транскрипт, язык входа и ответа, сценарии и времена STT/router/dialog/reply/TTS/total.
Маршрутизация сценариев выполняется LLM. После ответа модели код только проверяет допустимость ID и уверенности, убирает дубли и ставит срочные сценарии первыми согласно ТЗ. Лексические правила не подменяют выбранный моделью сценарий. Обученный encoder-классификатор намерений в проекте не используется.
Используемые технологии
Python 3.11+, Streamlit, OpenAI API, python-dotenv; JSON-файлы из data/case_2/voice_router_dataset служат каталогом сценариев, мок-бэкендом и базой знаний. Данные читаются локально, внешняя база данных не нужна.
Установка
Из корня репозитория:
python -m venv .venv
# Windows PowerShell: .venv\Scripts\Activate.ps1
# macOS/Linux: source .venv/bin/activate
python -m pip install -r requirements.txt
Запуск
Создайте .env в корне репозитория, задайте OPENAI_API_KEY, затем:
python -m streamlit run app.py
Откройте локальный адрес, который выведет Streamlit. Для демо нужен доступ к OpenAI API; личный аккаунт эксперта в приложении не требуется. Разрешите браузеру доступ к микрофону, нажмите запись, произнесите фразу и остановите запись. Ответ появляется текстом и в аудиоплеере; если браузер блокирует автозапуск, нажмите Play. Для телефона нужен HTTPS-адрес приложения (или локальный localhost на том же устройстве), а не HTTP-адрес ноутбука. Поле чата служит запасным вводом.
Зависимости
Зависимости перечислены в requirements.txt. Датасет уже включён в репозиторий. При запуске роутер отправляет реплику и каталог сценариев в OpenAI API; без доступного ключа маршрутизация не работает.
Переменные окружения
| Переменная | Обязательна | Назначение |
|---|---|---|
OPENAI_API_KEY | Да | Ключ OpenAI API для роутера, STT, TTS и локализации |
ROUTER_MODEL | Нет | Модель роутера; по умолчанию gpt-4o-mini |
STT_MODEL | Нет | Распознавание; gpt-4o-transcribe |
TTS_MODEL | Нет | Озвучка с инструкциями языка; gpt-4o-mini-tts |
TTS_VOICE | Нет | Голос; alloy |
REPLY_MODEL | Нет | Перевод динамических данных; gpt-4o-mini |
.env исключён из Git. Не помещайте ключ в коммиты и скриншоты.
Развёрнутая версия
Публичное демо (без установки): https://examined-sandwich-rocky-screensavers.trycloudflare.com — временный туннель на локально запущенный app.py, доступен, пока запущен процесс на машине команды. Для гарантированной проверки используйте локальный запуск по инструкции выше.
Порядок проверки основного сценария
- Запустите приложение и введите: «Сколько стоит ОГПО для легковой машины в Алматы?». Панель трассировки должна показать SC01; бот запросит недостающие слоты.
- Введите ИИН водителя из
data/case_2/voice_router_dataset/mock_backend.jsonи остальные запрошенные данные. Проверьте расчёт стоимости и действия в панели трассировки. - Для проверки подтверждения запросите покупку ОГПО (SC02), предоставьте запрошенные номер автомобиля, ИИН и телефон синтетического клиента. До ответа «да» действие
create_policyдолжно оставаться в режимеpending. - Для проверки системного намерения введите запрос о кредите: ожидается
SYS_OUT_OF_SCOPE.
Датасет и полное описание кейса: data/case_2/voice_router_dataset/README.ru.md. Оценка на размеченных репликах:
python predictions.py
python data/case_2/voice_router_dataset/evaluate.py predictions.json data/case_2/voice_router_dataset/dev_utterances.json
Проверка текущего роутера после удаления трёх функций, вручную переписывавших выбор сценария, и добавления каталоговых RU/KK примеров в промпт: 104 реплики dev_utterances.json через OpenAI API и официальный evaluate.py (23.09.2026). Точность основного сценария — 99,0% (103/104); полное совпадение списка — 97,1% (101/104); полнота интентов в многоцелевых запросах — 92,3%. Остались три несовпадения: U034 (SC30 вместо SC17), U086 (пропущен SC31), U093 (пропущен SC33). Это открытая выборка разработки, не независимая итоговая оценка; повторный вызов API может дать другой результат. Веса LLM не дообучались: дополнительные примеры из scenarios.json передаются в контексте запроса.
Переиспользованные компоненты
backend.triage.detect_language() первоначально переиспользован из предыдущего проекта команды AI Firewall; теперь заменён на RU/KK/mixed fallback в backend.language, основной язык полной реплики возвращает LLM. Это вспомогательное определение языка, не классификатор намерений и не основная часть решения. Обученная модель DistilBERT для классификации намерений из того проекта здесь не используется.
Проверка голосового демо
Произнесите последовательно русскую, казахскую и смешанную фразы о страховании. В Trace panel проверьте transcript, language (ru, kk, mixed) и response_language (ru или kk), затем прослушайте ответ. Для KK и смешанной речи с преобладанием казахского вопросы и голос должны быть казахскими; при преобладании русского — русскими. Номер телефона или ИИН сам по себе не меняет язык диалога. Новая русская реплика переключает ответ обратно на русский.
Ошибки распознавания и озвучки видны в интерфейсе; кнопки повтора не выполняют страховую операцию заново. При неточной транскрипции введите исправленную фразу в чат. Автоматическое тестирование без API:
python -m unittest discover -s tests -v
STT API: язык в запросе не фиксируется, чтобы сохранить смешанную речь. Для gpt-4o-transcribe используется JSON; verbose_json/языковые сегменты этой моделью не поддерживаются. TTS API принимает текст ответа и инструкции произношения. Текущая реализация ждёт полный MP3: поле tts означает полное время синтеза, а total включает STT; это не замер времени до первого аудиофрагмента и не подтверждение секундного бюджета ТЗ.
Авторы коммитов
История коммитов
- 2026-09-23 17:59Merge pull request #9 from BAITC-Hacks/codex/remove-hardcode-evaldariyaska
- 2026-09-23 17:56Resolve main integration preserving LLM-only routingbefru
- 2026-09-23 17:56Merge remote-tracking branch 'origin/main' into codex/fix-reply-languagedariyaska
- 2026-09-23 17:55hour 5: larger bannerdariyaska
- 2026-09-23 17:55Merge pull request #8 from BAITC-Hacks/codex/fix-reply-languagedariyaska
- 2026-09-23 17:53Fix reply language for clearly Russian and Kazakh requestsdariyaska
- 2026-09-23 17:51hour 5: localize top-level UI labels to demo language toggledariyaska
- 2026-09-23 17:49merge: resolve PR #6 conflicts — remove hardcode, adopt multi-slot promptsdariyaska
Все коммиты (48)
- 2026-09-23 17:47hour 5: add public demo link to READMEdariyaska
- 2026-09-23 17:43Improve LLM prompt examples and record final dev scorebefru
- 2026-09-23 17:42Merge pull request #7 from BAITC-Hacks/codex/voice-ru-kk-mixeddariyaska
- 2026-09-23 17:41hour 4: russian reason field, demo language toggledariyaska
- 2026-09-23 17:40Fix Russian and Kazakh voice interactiondariyaska
- 2026-09-23 17:26Remove hardcoded scenario overrides and record fresh evalbefru
- 2026-09-23 17:22hour 4: remove duplicate junk filesdariyaska
- 2026-09-23 17:20hour 4: polish UI — branded header, readable trace panel with confidence badgesdariyaska
- 2026-09-23 17:01Merge PR #3: fix Saqta Voice Router review findingsbefru1
- 2026-09-23 17:00Merge latest main and preserve router validation retrybefru
- 2026-09-23 16:55Merge pull request #5 from BAITC-Hacks/codex/router-final-boundariesdariyaska
- 2026-09-23 16:53Improve router boundary handlingdariyaska
- 2026-09-23 16:52Allow topic changes during identification and localize promptsbefru
- 2026-09-23 16:36Retain bilingual catalog examples after main mergebefru
- 2026-09-23 16:35Merge latest main and retain slot type guidancebefru
- 2026-09-23 16:32Merge remote-tracking branch 'origin/codex/integration-readme-audit'dariyaska
- 2026-09-23 16:31Handle malformed live router replies and localize system flowbefru
- 2026-09-23 16:28Merge current main and resolve router prompt conflictbefru
- 2026-09-23 16:27Normalize live router slots and preserve queued intentsbefru
- 2026-09-23 16:17Merge pull request #4 from BAITC-Hacks/codex/router-boundary-fixesdariyaska
- 2026-09-23 16:15Fix PR review findings across dialog flow and mock actionsbefru
- 2026-09-23 16:12improve router boundary handlingDariya
- 2026-09-23 15:40defer SMS until confirmationbefru
- 2026-09-23 15:37treat empty required slots as missingbefru
- 2026-09-23 15:32fix router prompt for numeric enum slotsbefru
- 2026-09-23 15:27hour 3: document setup and harden scenario integrationbefru
- 2026-09-23 15:13Merge pull request #1 from BAITC-Hacks/codex/router-intent-qualitydariyaska
- 2026-09-23 15:07hour 2: guard route() call against router validation errorsdariyaska
- 2026-09-23 14:44Improve bilingual router context and multi-intent handlingDariya
- 2026-09-23 14:28TEAM_GUIDE WITH CONTEXTdariyaska
- 2026-09-23 14:24hour 1: router working — 92% full match, 94% primary accuracy on dev setdariyaska
- 2026-09-23 13:58strturedariyaska
- 2026-09-23 13:52Add backend scaffoldDariya
- 2026-09-23 15:07hour 2: actions_mock (31/31 actions), executor confirmation flow, app.py identification/confirmation/slot-mergebefru1
- 2026-09-23 14:46merge: resolve .gitignore conflict after pullbefru1
- 2026-09-23 00:42hour 0: env template + finance-track depsdariyaska
- 2026-09-23 00:41hour 0: db + vectordb skeletonsdariyaska
- 2026-09-23 00:32hour 0: pin base dependenciesdariyaska
- 2026-09-23 00:14hour 0: add gitignoredariyaska
- 2026-09-23 00:13hour 0: project skeleton + READMEdariyaska
Структура репозитория (45 файлов)
.env.example .gitignore .streamlit/config.toml README.md TEAM_GUIDE.md app.py backend/__init__.py backend/actions_mock.py backend/confirmation.py backend/data_loader.py backend/decision_policy.py backend/executor.py backend/language.py backend/reply_language.py backend/router.py backend/slot_normalization.py backend/speech.py backend/state.py backend/triage.py data/case_2/voice_router_dataset/README.kz.md data/case_2/voice_router_dataset/README.md data/case_2/voice_router_dataset/README.ru.md data/case_2/voice_router_dataset/actions.json data/case_2/voice_router_dataset/dev_utterances.json data/case_2/voice_router_dataset/dialogs_sample.json data/case_2/voice_router_dataset/evaluate.py data/case_2/voice_router_dataset/knowledge_base.json data/case_2/voice_router_dataset/mock_backend.json data/case_2/voice_router_dataset/scenarios.json data/case_2/voice_router_dataset/slots.json docs/customer-materials.md docs/router-quality.md docs/router-validation.md docs/voice-validation.md predictions.py requirements.txt tests/router_boundaries.json tests/test_app_review.py tests/test_decision_policy.py tests/test_language.py tests/test_reply_language.py tests/test_review_fixes.py tests/test_router.py tests/test_voice.py tests/test_voice_app.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.