diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b20302d..c59a723 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,5 +1,8 @@ # 🏗️ Архитектура calls24 +> На основе кейса Adict.ru: команда персон, а не один бот. +> Источник: "Как мы превратили чат-бот в команду из пяти ИИ-специалистов" (ЖК Авторский дом 12, Иркутск) + ## Система: от звонка до звонка ``` @@ -32,11 +35,25 @@ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Замкнутый цикл обучения │ │ │ │ │ │ -│ │ Робот звонит → Запись звонка → Анализ → Улучшение скрипта │ │ +│ │ Робот звонит → Запись → Анализ → «Не знаю» → Лид + KB │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` +## Персонализация: команда вместо одного бота + +На основе кейса Adict.ru — клиент не должен разговаривать с «ботом». Он должен выбирать специалиста: + +| Персона | Роль | Тон | Когда звонит | +|---------|------|-----|-------------| +| **Менеджер продаж** | Квалификация, предложение | Уверенный, деловой | Холодный звонок, входящий интерес | +| **Консультант** | Ответы на вопросы | Терпеливый, подробный | Сложные вопросы, сомнения | +| **Финансист** | Рассрочка, ипотека, цены | Точный, без воды | «Сколько стоит?», «Какие условия?» | +| **Куратор** | Постпродажное сопровождение | Заботливый, личный | Довольный клиент, referral | + +**Принцип:** каждая персона — отдельный промпт, separate state machine, separate база знаний. +Клиент выбирает или система маршрутизирует автоматически. + ## Компоненты ### 1. calls24-аналитика (voice-analyzer) @@ -64,28 +81,32 @@ voice-bot/ ├── main.py # FastAPI (порт 8461) ├── sip_proxy.py # WebSIP Proxy (SIP ←→ WebSocket) ├── realtime.py # Yandex Realtime WebSocket client -├── script.py # Управление скриптом (state machine) +├── router.py # Маршрутизация между персонами +├── persona.py # State Machine для каждой персоны ├── memory.py # Память контекста разговора (Redis) +├── fallback.py # Честный «не знаю» → лид + KB +├── voice_bridge.py # Короткий мостик при передаче роли └── .env ``` -**Функции:** -- Приём входящих / исходящие звонки -- Yandex Realtime API (STT→LLM→TTS в реальном времени) -- State Machine: приветствие → qualification → предложение → возражения → закрытие -- Контекстная память (текущий клиент, история, CRM-данные) -- Запись звонков для последующего анализа +**Критичные фичи голоса (из кейса Adict.ru):** +- **Прерывания:** клиент перебивает → система замолкает мгновенно +- **Пауза внутри мысли ≠ конец фразы:** ждём 1.5-2с тишины перед ответом +- **Мостик при передаче роли:** 300мс звуковой bridge, чтобы клиент не чувствовал разрыва +- **Защита ролей:** персоне нельзя уходить в чужую роль (финансист не даёт советы юриста) ### 3. calls24-ядро (core) ``` core/ ├── api.py # Общий API (REST + WebSocket) -├── models.py # Pydantic модели (Call, Script, Pattern) +├── models.py # Pydantic модели (Call, Script, Pattern, Persona) ├── db.py # PostgreSQL / Qdrant ├── scheduler.py # Расписание звонков, напоминания ├── billing.py # Оплата за лид/бронь ├── integrations.py # Bitrix24, AmoCRM, 1С -└── auth.py # Авторизация клиентов +├── auth.py # Авторизация клиентов +├── content_admin.py # Админка для контент-менеджера +└── search.py # Гибридный поиск: BM25 + эмбеддинги ``` ## Базы данных @@ -93,15 +114,17 @@ core/ ### PostgreSQL ``` 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) 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) +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 - call_id: string @@ -112,6 +135,11 @@ 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} ``` ## Поток данных @@ -123,13 +151,30 @@ collection: script_patterns запись в PG скрипт для робота ``` -### Звонки робота +### Звонки робота (с маршрутизацией) ``` SIP-линия → WebSIP → WebSocket → Yandex Realtime ↓ - STT → LLM → TTS → Аудио - ↓ - Context Memory (Redis) - ↓ - Запись → Анализ → Улучшение + STT → Маршрутизатор → Персона + ↓ + Контекст + База знаний → Ответ + ↓ + LLM → TTS → Аудио + ↓ + Context Memory (Redis) + ↓ + «Не знаю» → Лид-форма + KB запись +``` + +### Цикл «Не знаю» = рост базы знаний +``` +Персона не знает ответ + ↓ + Честный fallback: «Я передам вопрос специалисту, оставьте контакт» + ↓ + Запись в content_entries как «запрошенная тема» + ↓ + Контент-менеджер видит в админке: «Клиенты часто спрашивают X, ответ ещё не добавлен» + ↓ + Контент-менеджер добавляет ответ → персона становится умнее без релиза ```