181 lines
11 KiB
Markdown
181 lines
11 KiB
Markdown
# 🏗️ Архитектура calls24
|
||
|
||
> На основе кейса Adict.ru: команда персон, а не один бот.
|
||
> Источник: "Как мы превратили чат-бот в команду из пяти ИИ-специалистов" (ЖК Авторский дом 12, Иркутск)
|
||
|
||
## Система: от звонка до звонка
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ КЛИЕНТ (бизнес) │
|
||
│ Звонки операторов (WAV/MP3) → SIP-линии → CRM (Bitrix24) │
|
||
└────────┬──────────────────────────────┬──────────────────┬──────────┘
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────────────┐ ┌────────────────────┐ ┌──────────────────┐
|
||
│ calls24-аналитика │ │ SIP-коннектор │ │ calls24-робот │
|
||
│ (FastAPI + LLM) │ │ (WebSIP Proxy) │ │ (Yandex Realtime│
|
||
│ │ │ │ │ WebSocket) │
|
||
│ • STT (распозн.) │ │ SIP ←→ WebSocket │ │ │
|
||
│ • LLM-анализ │ │ RTP ↔ Media │ │ • STT→LLM→TTS │
|
||
│ • Паттерны продаж │ │ (аудио микшир.) │ │ (задержка <1с) │
|
||
│ • Рекомендации │ │ │ │ • Brand Voice │
|
||
└────────┬────────────┘ └────────┬───────────┘ └────────┬─────────┘
|
||
│ │ │
|
||
▼ │ │
|
||
┌─────────────────────────────────────────────────────────────────────┐
|
||
│ calls24-ядро (FastAPI) │
|
||
│ │
|
||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
|
||
│ │ PostgreSQL│ │ Qdrant │ │ Redis │ │ Yandex AI API │ │
|
||
│ │(звонки, │ │(векторы │ │(очереди, │ │ (speech-realtime│ │
|
||
│ │ скрипты) │ │ звонков) │ │ кэш) │ │ -250923) │ │
|
||
│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||
│ │ Замкнутый цикл обучения │ │
|
||
│ │ │ │
|
||
│ │ Робот звонит → Запись → Анализ → «Не знаю» → Лид + KB │ │
|
||
│ └──────────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## Персонализация: команда вместо одного бота
|
||
|
||
На основе кейса Adict.ru — клиент не должен разговаривать с «ботом». Он должен выбирать специалиста:
|
||
|
||
| Персона | Роль | Тон | Когда звонит |
|
||
|---------|------|-----|-------------|
|
||
| **Менеджер продаж** | Квалификация, предложение | Уверенный, деловой | Холодный звонок, входящий интерес |
|
||
| **Консультант** | Ответы на вопросы | Терпеливый, подробный | Сложные вопросы, сомнения |
|
||
| **Финансист** | Рассрочка, ипотека, цены | Точный, без воды | «Сколько стоит?», «Какие условия?» |
|
||
| **Куратор** | Постпродажное сопровождение | Заботливый, личный | Довольный клиент, referral |
|
||
|
||
**Принцип:** каждая персона — отдельный промпт, separate state machine, separate база знаний.
|
||
Клиент выбирает или система маршрутизирует автоматически.
|
||
|
||
## Компоненты
|
||
|
||
### 1. calls24-аналитика (voice-analyzer)
|
||
```
|
||
voice-analyzer/
|
||
├── main.py # FastAPI (порт 8460)
|
||
├── stt.py # Yandex STT (locazli) / Yandex Speech
|
||
├── analyzer.py # LLM-анализ звонков (Qwen35B / Yandex GPT)
|
||
├── pattern.py # Выявление паттернов продаж
|
||
├── report.py # Генерация отчёта (HTML/PDF)
|
||
└── .env # API ключи
|
||
```
|
||
|
||
**Функции:**
|
||
- Приём аудиофайлов (WAV/MP3, до 100МБ)
|
||
- Распознавание речи (Yandex STT / Whisper)
|
||
- Анализ текста: скрипт, тайминги, возражения, конверсия
|
||
- Сравнение операторов: кто лучше, почему
|
||
- Генерация отчёта: «что нужно исправить»
|
||
- Экспорт паттернов для генерации скрипта
|
||
|
||
### 2. calls24-робот (voice-bot)
|
||
```
|
||
voice-bot/
|
||
├── main.py # FastAPI (порт 8461)
|
||
├── sip_proxy.py # WebSIP Proxy (SIP ←→ WebSocket)
|
||
├── realtime.py # Yandex Realtime WebSocket client
|
||
├── router.py # Маршрутизация между персонами
|
||
├── persona.py # State Machine для каждой персоны
|
||
├── memory.py # Память контекста разговора (Redis)
|
||
├── fallback.py # Честный «не знаю» → лид + KB
|
||
├── voice_bridge.py # Короткий мостик при передаче роли
|
||
└── .env
|
||
```
|
||
|
||
**Критичные фичи голоса (из кейса Adict.ru):**
|
||
- **Прерывания:** клиент перебивает → система замолкает мгновенно
|
||
- **Пауза внутри мысли ≠ конец фразы:** ждём 1.5-2с тишины перед ответом
|
||
- **Мостик при передаче роли:** 300мс звуковой bridge, чтобы клиент не чувствовал разрыва
|
||
- **Защита ролей:** персоне нельзя уходить в чужую роль (финансист не даёт советы юриста)
|
||
|
||
### 3. calls24-ядро (core)
|
||
```
|
||
core/
|
||
├── api.py # Общий API (REST + WebSocket)
|
||
├── models.py # Pydantic модели (Call, Script, Pattern, Persona)
|
||
├── db.py # PostgreSQL / Qdrant
|
||
├── scheduler.py # Расписание звонков, напоминания
|
||
├── billing.py # Оплата за лид/бронь
|
||
├── integrations.py # Bitrix24, AmoCRM, 1С
|
||
├── auth.py # Авторизация клиентов
|
||
├── content_admin.py # Админка для контент-менеджера
|
||
└── search.py # Гибридный поиск: BM25 + эмбеддинги
|
||
```
|
||
|
||
## Базы данных
|
||
|
||
### PostgreSQL
|
||
```
|
||
calls (id, customer_id, type, recording_url, status, created_at)
|
||
call_transcripts (call_id, role, text, start_time, end_time, persona)
|
||
call_analysis (call_id, score, script_issues, objections, conversion)
|
||
scripts (id, name, version, state_machine_json, created_at)
|
||
patterns (id, script_id, type, text, win_rate, context)
|
||
customers (id, name, company, industry, phone, created_at)
|
||
leads (id, customer_id, call_id, status, revenue, created_at, fallback_reason)
|
||
personas (id, name, role, tone, state_machine_id, knowledge_base_id)
|
||
content_entries (id, topic, answer, source, quality_score, updated_at)
|
||
```
|
||
|
||
### Qdrant (гибридный поиск: BM25 + эмбеддинги)
|
||
```
|
||
collection: call_embeddings
|
||
- call_id: string
|
||
- embedding: float[768] (text-embedding-3-large)
|
||
- payload: {customer_id, type, score, script_issues}
|
||
|
||
collection: script_patterns
|
||
- pattern_id: string
|
||
- embedding: float[768]
|
||
- payload: {type, text, win_rate, context}
|
||
|
||
collection: content_kb
|
||
- entry_id: string
|
||
- embedding: float[768]
|
||
- payload: {topic, answer, source, quality_score}
|
||
```
|
||
|
||
## Поток данных
|
||
|
||
### Анализ звонка
|
||
```
|
||
Аудиофайл → STT → Текст → LLM-анализ → Паттерны → Отчёт
|
||
↓ ↓
|
||
запись в PG скрипт для робота
|
||
```
|
||
|
||
### Звонки робота (с маршрутизацией)
|
||
```
|
||
SIP-линия → WebSIP → WebSocket → Yandex Realtime
|
||
↓
|
||
STT → Маршрутизатор → Персона
|
||
↓
|
||
Контекст + База знаний → Ответ
|
||
↓
|
||
LLM → TTS → Аудио
|
||
↓
|
||
Context Memory (Redis)
|
||
↓
|
||
«Не знаю» → Лид-форма + KB запись
|
||
```
|
||
|
||
### Цикл «Не знаю» = рост базы знаний
|
||
```
|
||
Персона не знает ответ
|
||
↓
|
||
Честный fallback: «Я передам вопрос специалисту, оставьте контакт»
|
||
↓
|
||
Запись в content_entries как «запрошенная тема»
|
||
↓
|
||
Контент-менеджер видит в админке: «Клиенты часто спрашивают X, ответ ещё не добавлен»
|
||
↓
|
||
Контент-менеджер добавляет ответ → персона становится умнее без релиза
|
||
```
|