02. Архитектура системы
Версия 1.0 от 2026-10-02. Ключевая архитектурная развилка уже решена самим входным форматом: стерео с разделением каналов → спикеры известны физически, нейросетевая диаризация не нужна. Это дешевле, точнее и быстрее любых решений «диаризация + ASR» для моно-записей.
1. Общая схема
flowchart LR
subgraph SRC["Контур заказчика"]
A["АТС / система записи<br/>стерео-файлы + метаданные"]
end
subgraph ING["Слой приёма"]
B["Ingest-адаптер<br/>REST / S3 / SFTP / вебхук"]
C["Планировщик задач<br/>Redis Streams → Kafka*"]
D["Оригиналы<br/>S3 / MinIO"]
end
subgraph PREP["Предобработка — CPU"]
E["ffmpeg: разделение каналов,<br/>16 кГц моно, нормализация громкости"]
F["VAD Silero + аудио-фичи:<br/>тишина, бипы, DTMF, музыка"]
end
subgraph ASR["Распознавание — GPU"]
G["ASR-воркеры<br/>faster-whisper / WhisperX<br/>батчинг, int8_float16"]
end
subgraph POST["Постобработка"]
H["Слияние каналов по таймкодам<br/>реплики клиент/оператор"]
I["Метрики: talk ratio,<br/>перебивания, паузы"]
J["Правила: стоп-слова, фразы скрипта,<br/>regex, нечёткий поиск"]
K["LLM-классификатор<br/>vLLM + Qwen, JSON-schema"]
end
subgraph STORE["Хранение"]
L[("S3/MinIO: аудио, транскрипты JSON")]
M[("PostgreSQL: звонки, таксономия, пользователи")]
N[("ClickHouse: метрики, сегменты, теги")]
end
subgraph BI["Аналитика и доступ"]
O["Дашборды Superset"]
P["Карточка звонка:<br/>плеер + транскрипт + теги"]
Q["Экспорт и рассылка отчётов"]
R["API для систем заказчика"]
end
S["Очередь ручного контроля<br/>human-in-the-loop"]
T["Prometheus + Grafana<br/>алерты, SLA-мониторинг"]
A --> B --> C
B --> D
C --> E --> F --> G --> H --> I
H --> J --> K
K -->|низкая уверенность| S
I --> L & M & N
K --> L & M & N
N & M --> O & P & Q & R
C & E & G & K -.телеметрия.-> T
\* Redis Streams достаточно до ~50 тыс. задач/час; миграция на Kafka — если объёмы/ретеншн очередей потребуют (решение зафиксируем после замеров в PoC).
2. Поток обработки одного звонка
- Обнаружение. Ingest-адаптер по расписанию (каждые 1–5 мин) опрашивает API заказчика о новых
записях либо принимает вебхук. Задача (call_id, пути, метаданные) — в очередь с приоритетом live; бэклог-выгрузка кладётся в очередь backfill с низким приоритетом.
- Предобработка (CPU, ffmpeg). Разделение каналов → ресемпл 16 кГц моно → нормализация громкости
(loudnorm) → VAD (Silero): выкидываем тишину, считаем долю речи по каналам, детектируем бипы/DTMF. Звонки, где второй канал пуст (типично для автоответчиков), распознаются только по «говорящему» каналу.
- ASR (GPU). Каждый канал независимо, батчами (faster-whisper/CTranslate2, int8_float16).
Выравнивание до слов — forced alignment (WhisperX / wav2vec2). Пунктуация — из самой Whisper; для альтернативных моделей добавляется отдельная модель пунктуации.
- Слияние. Сегменты двух каналов сортируются по
start→ единая хронология реплик с меткой
спикера. Пересечения сегментов = перебивания; паузы = промежутки без речи.
- Классификация. Каскад: (а) детерминированные правила и аудио-фичи (доля речи по каналам,
длительность, наличие бипов/музыки, словари «оставьте сообщение», стоп-слова, фразы скрипта через нечёткий поиск); (б) LLM со строгой JSON-схемой — финальные метки: тип соединения, результат, соблюдение скрипта, конфликтность, теги; (в) низкая уверенность → очередь ручного контроля.
- Индексация. Транскрипт — S3 (JSON + текст), метаданные и вердикты — PostgreSQL, метрики и
сегменты — ClickHouse. Звонок виден в дашбордах и карточке.
- Идемпотентность. Все стадии пишет результат по ключу
call_id + stage; повторный запуск
стадии не создаёт дубликатов; перезапуск возможен с любой стадии (ASR не повторяется при смене таксономии — только классификация, FR-41).
3. Компоненты и стек
| Слой | Выбор | Альтернатива / комментарий |
|---|---|---|
| Приём | Кастомный ingest-адаптер (Python) | Адаптер изолирует специфику API заказчика; новые источники — новые адаптеры |
| Очередь | Redis Streams + consumer groups | Kafka — при росте; Temporal — если нужны долгие SLA-процессы |
| Предобработка | ffmpeg, Silero VAD | CPU-нода(ы), масштабируется ядрами |
| ASR | faster-whisper (CTranslate2) / WhisperX | Модель выбирается в PoC (см. 03-models): Whisper large-v3-turbo — базовый кандидат |
| Выравнивание слов | WhisperX forced alignment (wav2vec2 ru) | Нужно для перебиваний и перемотки по репликам |
| Классификация | Правила (Python, rapidfuzz) + LLM через vLLM (structured output) | LLM: Qwen3-14B/32B локально; облако — только если разрешит анкета E |
| Объектное хранилище | MinIO (S3-совместимое) | Или S3-совместимое СХД заказчика |
| Метаданные | PostgreSQL | Звонки, статусы, таксономия, RBAC, аудит |
| Аналитика | ClickHouse | Сегменты/теги/метрики, агрегации по 6+ млн звонков |
| BI | Apache Superset | Встраиваемые дашборды, XLSX/PDF-экспорт; Metabase — проще, но менее гибок |
| Карточка звонка | Веб-приложение (FastAPI + фронтенд) | Плеер (wavesurfer.js) с синхронной подсветкой транскрипта |
| Поиск по текстам | ClickHouse full-text (токены) | OpenSearch — если нужен полноценный поисковый движок (фаза 5) |
| Мониторинг | Prometheus + Grafana + Alertmanager | SLA-дашборд: отставание очереди, DLQ, GPU-утилизация, WER-дрейф |
4. Режимы работы
- Live: новые звонки, приоритетная очередь. SLA ≤ 24 ч с огромным запасом (ожидаемое E2E — минуты).
При пиковом поступлении воркеры backfill временно переключаются на live.
- Backfill: 450 тыс. часов, низкий приоритет, пакетами; устойчивость к прерываниям и перезапускам
(чекпоинт по call_id). Прогресс и ETA бэклога — отдельный дашборд.
- Переклассификация: при изменении таксономии/промптов — повторный прогон стадии классификации
по транскриптам из S3 без ASR (дёшево; SLA переклассификации всего архива — часы, не дни).
5. Безопасность
- Всё внутри контура РФ; TLS на всех передачах; шифрование СХД (опция); оригиналы не размножаются —
кэш с TTL, основное хранение транскриптов.
- Маскирование номеров телефонов/сумм в транскриптах — флаг обработки (анкета E2); de-маскирование
только через RBAC.
- Доступ к карточкам/выгрузкам — по ролям; аудит выгрузок; водяные знаки в PDF-отчётах (опция).
- Развертываемо on-prem у заказчика без изменений архитектуры (k8s/docker-compose).
6. Развёртывание
- Docker Compose для PoC; Kubernetes (или Nomad) для прода.
- GPU-ноды: ASR-воркеры по количеству карт (по 1 процессу на GPU, батчинг внутри), LLM — vLLM
с отдельными картами.
- CPU-ноды: ingest, предобработка, слияние, правила, индексация.
- СУБД и S3 — на CPU-нодах/СХД с бэкапами; стенд 1:1 воспроизводится IaC (ansible/terraform).
7. Риски и как они закрыты
| # | Риск | Вероятн. | Влияние | Митигация |
|---|---|---|---|---|
| R1 | Телефонное аудио (8 кГц, шум, сленг) даёт WER заметно выше публичных бенчмарков | высокая | среднее | PoC на реальных данных до закупки; сравнение 3–4 моделей; выбор по фактам; затравочные словари (имена, продукты) в постобработке |
| R2 | Лицензия GigaAM (SOTA для ru) некоммерческая | высокая | низкое | Базовый план — Whisper (MIT); GigaAM — только при договоре со Сбером (см. 03) |
| R3 | API заказчика: лимиты/нестабильность на выгрузке бэклога | средняя | среднее | Ранний замер скорости выгрузки; физическая отгрузка дисков (анкета A4) |
| R4 | Классификация «спец-ответов» не формализована бизнесом | высокая | среднее | Воркшоп по таксономии в фазе PoC; очередь ручного контроля как страховка; правила правятся без релиза |
| R5 | Объём LLM-классификации на бэклоге (до ~70 тыс. звонков/сут) | средняя | низкое | Каскад: правила отсекают очевидное; локальная LLM на vLLM — копейки/GPU-час; при нехватке — вторая карта |
| R6 | ПДн/152-ФЗ: ограничения на размещение | средняя | высокое | Анкета E до подписания; вариант полного on-prem в контуре заказчика; маскирование |
| R7 | Рост объёма новых звонков (×2–3 за год) | средняя | низкое | Горизонтальное масштабирование: +GPU-карта = +~800 ч/сутки пропускной способности |
| R8 | Дрейф качества (новые кампании, смена скриптов) | средняя | среднее | Регресс-набор размеченных звонков; мониторинг WER-выборки ежемесячно; дообучение словарей |