Урок 0018 · System Design мок: Voice / STT-агент

Голосовой канал банка: STT → тот же текстовый агент → TTS. Покажи, что не строишь «голосовую магию», а переиспользуешь ядро.

Сценарий «Банк хочет голосового ассистента: клиент звонит и спрашивает про комиссии, лимиты, блокировку карты. Есть готовый текстовый бот. Спроектируй голосовой канал.»

Фаза 1. Clarify (первые 4 минуты)

Что говорит кандидат:

«Ключевой вопрос: у нас уже есть текстовый бот? Тогда голос — это ДВА новых слоя вокруг того же ядра: STT (речь → текст) и TTS (текст → речь) + оркестрация диалога. Не отдельный бот. Уточню: какой язык и диалект (MX-ES?), какой канал — телефон (кодек, шум) или in-app? Есть ли авторизация по голосу или по DTMF/данным? И где данные — можно ли vendor STT или нужно локально из-за PII в разговорах?»

Почему это сильно: ты сразу свёл задачу к «два слоя вокруг ядра» — это правильный рефрейм. И поднял язык/кодек/шум и PII — голосовые данные это чувствительно.

Вопросы рекрутера

Вопрос: «Зачем вообще STT→текст? Почему не дать модели аудио напрямую?»

Ответ: «Мультимодальные модели умеют аудио, но: (1) текстовое ядро уже готово и оттестировано — RAG, тулы, политики, evals; (2) переиспользование = один источник правды для политик; (3) STT-ошибки легче логировать и мерить (WER), чем „аудио-галлюцинации". Текстовый и голосовой канал делят RAG и политики — это и есть архитектура».

Вопрос: «Ты же не делал voice?»

Ответ (честно): «Не делал. Но текстовый агент у меня есть, а голос = STT + TTS вокруг него. STT меряется WER на ваших звонках, TTS — субъективно и по латентности. Всё остальное — уже решённые задачи: RAG, router, тулы, HITL».

Фаза 2. Success-метрики (3 минуты)

Что говорит кандидат:

«К метрикам текстового бота (resolution, recontact, эскалация) добавляются: WER на реальных звонках MX-ES (не LibriSpeech!), точность интента после STT, latency: время до первого звука ответа (p95), полный цикл диалога. И доля диалогов, где STT-ошибка привела к неверному ответу — это связка STT → ядро».

Вопрос рекрутера

Вопрос: «Почему WER на ваших звонках, а не на бенчмарке?»

Ответ: «LibriSpeech — чистые англоязычные аудиокниги. У банка: испанский, телефонный кодек, шум улицы, имена, номера карт, суммы. WER на чужом бенчмарке не скажет ничего про то, как модель распознает „quinientos pesos" в шуме. Поэтому: сэмпл реальных звонков, разметка, WER + ошибки на критичных сущностях (номера, суммы) — отдельно. Плюс меня интересует не общий WER, а WER на сущностях, которые идут в тулы».

Фаза 3. Estimate (3 минуты)

Что говорит кандидат:

«50k звонков/мес, пик 10 одновременных разговоров (телефонные линии — узкое место, не GPU). Разговор: 5 минут = 300с аудио, STT реального времени (1× фактор), TTS — быстрее речи. Задержка: STT 200–500 мс на фразу, ядро — как текстовый бот, TTS 100–300 мс. Целевой p95 «слышу ответ» — 1–2 секунды. Трафик небольшой — начнём с API, GPU не окупается».

Фаза 4. Sketch (8 минут)

Что рисует кандидат:

Звонок → телефонный шлюз / WebRTC
→ STT (речь → текст, потоково)
→ [ВХОД В ТО ЖЕ ЯДРО, ЧТО И ТЕКСТОВЫЙ БОТ]
   input guard → router → RAG/тулы → generate → output guard
→ TTS (текст → речь)
→ лог: call_id, WER-фрагменты, latency, cost

Отдельно: авторизация (DTMF или данные), HITL — перевод на оператора
с передачей саммари диалога.

Ключевые решения:

Вопросы рекрутера

Вопрос: «Как обработаешь, если STT ошибся в номере карты?»

Ответ: «Номер карты — критичная сущность. Варианты: (1) подтверждение вслух перед действием („карта 5290…? да/нет"); (2) cross-check: если номер не совпал ни с одной картой клиента — переспросить, не выдумывать; (3) DTMF-ввод для критичных данных — телефонная клавиатура надёжнее голоса. Для блокировки — обязательно подтверждение, это action-тул с HITL».

Вопрос: «Латентность — как уложиться?»

Ответ: «Потоково: STT отдаёт частичные результаты, ядро может начать думать на первом фрагменте. TTS — начинаем говорить первым предложением, пока генерится второе. Целевая разбивка: STT 300 мс + ядро 400 мс + TTS 200 мс ≈ 1с до первого звука. Плюс кэш частых ответов (комиссия SPEI — точный кэш)».

Фаза 5. Deep dive: STT-eval и связка с ядром (15 минут)

Что говорит кандидат:

«Копну в связку STT → ядро. WER — прокси, но решает конечная метрика: интент распознан верно? Считаю: после STT прогоняю текст через router и сравниваю интент с gold-интентом звонка. Если STT испортил сущность (сумму, номер) — это ловится отдельной метрикой ошибок на сущностях. И data flywheel: звонки, где ядро ответило неверно из-за STT, идут в выборку для дообучения STT или в few-shot для ядра».

Вопрос рекрутера

Вопрос: «Что важнее: WER или точность интента?»

Ответ: «Точность интента. WER может быть 10%, но если ошибки на незначимых словах — ядро всё поняло. И наоборот: WER 3%, но номер карты распознан неверно — блокировка уйдёт не на ту карту. Поэтому две метрики: интент-точность после STT (сквозная) и WER на критичных сущностях. Сквозная — главная, WER — диагностическая».

Фаза 6. Failures (7 минут)

Что говорит кандидат:

«Шум/кодек → WER растёт → fallback: переспросить, повторить медленнее, или HITL. STT провайдер 500 → fallback на второго/локального. Клиент перебивает → barge-in, TTS стоп. Не распознал сущность → подтверждение, не догадка. PII в разговоре → маскировка в логах, записи по политике банка. Регрессия ядра → те же evals, что у текстового бота — голос не ломает ядро, он добавляет слой».

Фаза 7. Evolve (3 минуты)

Что говорит кандидат:

«v0: потоковый STT + существующее текстовое ядро + TTS + DTMF для критичных данных + HITL. v1: дообучение STT на звонках (если WER на сущностях не падает), биометрия голоса, больше языков. Сознательно не беру: отдельную „голосовую модель" вместо ядра, полную автоматизацию без подтверждений на деньги».

Финальный вопрос

Вопрос: «С чего начнёшь?»

Ответ: «Соберу 200 реальных звонков, размечу интенты и сущности (номера, суммы), прогоню 2 STT-модели, посчитаю интент-точность и WER на сущностях. Параллельно — подключу существующее ядро к STT через API и проверю сквозной путь. TTS выберу по латентности и качеству на испанском. Текстовый бот при этом не трогаю — голос добавляет слой».

Чек-лист: что оценивает рекрутер

КритерийТы показал
Рефрейм задачи«Два слоя вокруг существующего ядра», не новый бот
Честность про пробел«Voice не делал» + WER на их звонках
Голосовая спецификаПоток, barge-in, VAD, DTMF, подтверждение вслух
Сквозная метрикаИнтент после STT, WER на сущностях
БезопасностьPII звонков, HITL на action

Проверь себя (мок-вопросы)

  1. «Зачем STT→текст, а не аудио напрямую?»
  2. «Как обработаешь ошибку STT в номере карты?»
  3. «Что важнее: WER или точность интента?»
  4. «Как уложиться в латентность?»
  5. «С чего начнёшь?»
Первоисточник урока Методология — твоя таблица «честные пробелы» (AI-SD-TOPICS.md §10) + уроки 0007/0009. STT-специфика (WER, barge-in) — стандартная практика голосовых каналов.