Update: persona-based architecture, voice specifics, fallback=lead pipeline
This commit is contained in:
1 parent
b5e112c53f
commit
1af355838a
1 file changed
+61
-16
+61
-16
@@ -1,5 +1,8 @@
|
|||||||
# 🏗️ Архитектура calls24
|
# 🏗️ Архитектура calls24
|
||||||
|
|
||||||
|
> На основе кейса Adict.ru: команда персон, а не один бот.
|
||||||
|
> Источник: "Как мы превратили чат-бот в команду из пяти ИИ-специалистов" (ЖК Авторский дом 12, Иркутск)
|
||||||
|
|
||||||
## Система: от звонка до звонка
|
## Система: от звонка до звонка
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -32,11 +35,25 @@
|
|||||||
│ ┌──────────────────────────────────────────────────────────────┐ │
|
│ ┌──────────────────────────────────────────────────────────────┐ │
|
||||||
│ │ Замкнутый цикл обучения │ │
|
│ │ Замкнутый цикл обучения │ │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ │ Робот звонит → Запись звонка → Анализ → Улучшение скрипта │ │
|
│ │ Робот звонит → Запись → Анализ → «Не знаю» → Лид + KB │ │
|
||||||
│ └──────────────────────────────────────────────────────────────┘ │
|
│ └──────────────────────────────────────────────────────────────┘ │
|
||||||
└─────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Персонализация: команда вместо одного бота
|
||||||
|
|
||||||
|
На основе кейса Adict.ru — клиент не должен разговаривать с «ботом». Он должен выбирать специалиста:
|
||||||
|
|
||||||
|
| Персона | Роль | Тон | Когда звонит |
|
||||||
|
|---------|------|-----|-------------|
|
||||||
|
| **Менеджер продаж** | Квалификация, предложение | Уверенный, деловой | Холодный звонок, входящий интерес |
|
||||||
|
| **Консультант** | Ответы на вопросы | Терпеливый, подробный | Сложные вопросы, сомнения |
|
||||||
|
| **Финансист** | Рассрочка, ипотека, цены | Точный, без воды | «Сколько стоит?», «Какие условия?» |
|
||||||
|
| **Куратор** | Постпродажное сопровождение | Заботливый, личный | Довольный клиент, referral |
|
||||||
|
|
||||||
|
**Принцип:** каждая персона — отдельный промпт, separate state machine, separate база знаний.
|
||||||
|
Клиент выбирает или система маршрутизирует автоматически.
|
||||||
|
|
||||||
## Компоненты
|
## Компоненты
|
||||||
|
|
||||||
### 1. calls24-аналитика (voice-analyzer)
|
### 1. calls24-аналитика (voice-analyzer)
|
||||||
@@ -64,28 +81,32 @@ voice-bot/
|
|||||||
├── main.py # FastAPI (порт 8461)
|
├── main.py # FastAPI (порт 8461)
|
||||||
├── sip_proxy.py # WebSIP Proxy (SIP ←→ WebSocket)
|
├── sip_proxy.py # WebSIP Proxy (SIP ←→ WebSocket)
|
||||||
├── realtime.py # Yandex Realtime WebSocket client
|
├── realtime.py # Yandex Realtime WebSocket client
|
||||||
├── script.py # Управление скриптом (state machine)
|
├── router.py # Маршрутизация между персонами
|
||||||
|
├── persona.py # State Machine для каждой персоны
|
||||||
├── memory.py # Память контекста разговора (Redis)
|
├── memory.py # Память контекста разговора (Redis)
|
||||||
|
├── fallback.py # Честный «не знаю» → лид + KB
|
||||||
|
├── voice_bridge.py # Короткий мостик при передаче роли
|
||||||
└── .env
|
└── .env
|
||||||
```
|
```
|
||||||
|
|
||||||
**Функции:**
|
**Критичные фичи голоса (из кейса Adict.ru):**
|
||||||
- Приём входящих / исходящие звонки
|
- **Прерывания:** клиент перебивает → система замолкает мгновенно
|
||||||
- Yandex Realtime API (STT→LLM→TTS в реальном времени)
|
- **Пауза внутри мысли ≠ конец фразы:** ждём 1.5-2с тишины перед ответом
|
||||||
- State Machine: приветствие → qualification → предложение → возражения → закрытие
|
- **Мостик при передаче роли:** 300мс звуковой bridge, чтобы клиент не чувствовал разрыва
|
||||||
- Контекстная память (текущий клиент, история, CRM-данные)
|
- **Защита ролей:** персоне нельзя уходить в чужую роль (финансист не даёт советы юриста)
|
||||||
- Запись звонков для последующего анализа
|
|
||||||
|
|
||||||
### 3. calls24-ядро (core)
|
### 3. calls24-ядро (core)
|
||||||
```
|
```
|
||||||
core/
|
core/
|
||||||
├── api.py # Общий API (REST + WebSocket)
|
├── api.py # Общий API (REST + WebSocket)
|
||||||
├── models.py # Pydantic модели (Call, Script, Pattern)
|
├── models.py # Pydantic модели (Call, Script, Pattern, Persona)
|
||||||
├── db.py # PostgreSQL / Qdrant
|
├── db.py # PostgreSQL / Qdrant
|
||||||
├── scheduler.py # Расписание звонков, напоминания
|
├── scheduler.py # Расписание звонков, напоминания
|
||||||
├── billing.py # Оплата за лид/бронь
|
├── billing.py # Оплата за лид/бронь
|
||||||
├── integrations.py # Bitrix24, AmoCRM, 1С
|
├── integrations.py # Bitrix24, AmoCRM, 1С
|
||||||
└── auth.py # Авторизация клиентов
|
├── auth.py # Авторизация клиентов
|
||||||
|
├── content_admin.py # Админка для контент-менеджера
|
||||||
|
└── search.py # Гибридный поиск: BM25 + эмбеддинги
|
||||||
```
|
```
|
||||||
|
|
||||||
## Базы данных
|
## Базы данных
|
||||||
@@ -93,15 +114,17 @@ core/
|
|||||||
### PostgreSQL
|
### PostgreSQL
|
||||||
```
|
```
|
||||||
calls (id, customer_id, type, recording_url, status, created_at)
|
calls (id, customer_id, type, recording_url, status, created_at)
|
||||||
call_transcripts (call_id, role, text, start_time, end_time)
|
call_transcripts (call_id, role, text, start_time, end_time, persona)
|
||||||
call_analysis (call_id, score, script_issues, objections, conversion)
|
call_analysis (call_id, score, script_issues, objections, conversion)
|
||||||
scripts (id, name, version, state_machine_json, created_at)
|
scripts (id, name, version, state_machine_json, created_at)
|
||||||
patterns (id, script_id, type, text, win_rate, context)
|
patterns (id, script_id, type, text, win_rate, context)
|
||||||
customers (id, name, company, industry, phone, created_at)
|
customers (id, name, company, industry, phone, created_at)
|
||||||
leads (id, customer_id, call_id, status, revenue, 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 (векторный поиск)
|
### Qdrant (гибридный поиск: BM25 + эмбеддинги)
|
||||||
```
|
```
|
||||||
collection: call_embeddings
|
collection: call_embeddings
|
||||||
- call_id: string
|
- call_id: string
|
||||||
@@ -112,6 +135,11 @@ collection: script_patterns
|
|||||||
- pattern_id: string
|
- pattern_id: string
|
||||||
- embedding: float[768]
|
- embedding: float[768]
|
||||||
- payload: {type, text, win_rate, context}
|
- payload: {type, text, win_rate, context}
|
||||||
|
|
||||||
|
collection: content_kb
|
||||||
|
- entry_id: string
|
||||||
|
- embedding: float[768]
|
||||||
|
- payload: {topic, answer, source, quality_score}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Поток данных
|
## Поток данных
|
||||||
@@ -123,13 +151,30 @@ collection: script_patterns
|
|||||||
запись в PG скрипт для робота
|
запись в PG скрипт для робота
|
||||||
```
|
```
|
||||||
|
|
||||||
### Звонки робота
|
### Звонки робота (с маршрутизацией)
|
||||||
```
|
```
|
||||||
SIP-линия → WebSIP → WebSocket → Yandex Realtime
|
SIP-линия → WebSIP → WebSocket → Yandex Realtime
|
||||||
↓
|
↓
|
||||||
STT → LLM → TTS → Аудио
|
STT → Маршрутизатор → Персона
|
||||||
|
↓
|
||||||
|
Контекст + База знаний → Ответ
|
||||||
|
↓
|
||||||
|
LLM → TTS → Аудио
|
||||||
↓
|
↓
|
||||||
Context Memory (Redis)
|
Context Memory (Redis)
|
||||||
↓
|
↓
|
||||||
Запись → Анализ → Улучшение
|
«Не знаю» → Лид-форма + KB запись
|
||||||
|
```
|
||||||
|
|
||||||
|
### Цикл «Не знаю» = рост базы знаний
|
||||||
|
```
|
||||||
|
Персона не знает ответ
|
||||||
|
↓
|
||||||
|
Честный fallback: «Я передам вопрос специалисту, оставьте контакт»
|
||||||
|
↓
|
||||||
|
Запись в content_entries как «запрошенная тема»
|
||||||
|
↓
|
||||||
|
Контент-менеджер видит в админке: «Клиенты часто спрашивают X, ответ ещё не добавлен»
|
||||||
|
↓
|
||||||
|
Контент-менеджер добавляет ответ → персона становится умнее без релиза
|
||||||
```
|
```
|
||||||
Reference in new issue
Block a user