Update: persona-based architecture, voice specifics, fallback=lead pipeline

This commit is contained in:
neo committed 2026-06-10 21:18:03 +05:00
1 parent b5e112c53f
commit 1af355838a
1 file changed
+61 -16
+61 -16
View File
@@ -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, ответ ещё не добавлен»
↓
Контент-менеджер добавляет ответ → персона становится умнее без релиза
``` ```