Initial: архитектура Pleep24 AI Sales Agent

This commit is contained in:
neo committed 2026-07-05 01:32:04 +05:00
commit 4ffc815e30
3 files changed
+870

No files matched your search

+766
View File
@@ -0,0 +1,766 @@
# Pleep24 — Архитектура AI Sales Agent
> Аналог [Pleep.app](https://pleep.app/) — мультиканальный AI-агент продаж на стеке FastAPI + DeepSeek + Twenty CRM.
## Оглавление
1. [Обзор системы](#обзор-системы)
2. [Архитектура микросервисов](#архитектура-микросервисов)
3. [Twenty CRM — модель данных и интеграция](#twenty-crm--модель-данных-и-интеграция)
4. [Message Router — маршрутизация сообщений](#message-router--маршрутизация-сообщений)
5. [AI Agent — мозг системы](#ai-agent--мозг-системы)
6. [Twenty Gateway — API-прослойка CRM](#twenty-gateway--api-прослойка-crm)
7. [LLM Prompt Strategy](#llm-prompt-strategy)
8. [Knowledge Base (RAG)](#knowledge-base-rag)
9. [Web Widget](#web-widget)
10. [Voice Integration (calls24)](#voice-integration-calls24)
11. [Каналы связи](#каналы-связи)
12. [База данных](#база-данных)
13. [Деплоймент (Coolify + Docker)](#деплоймент-coolify--docker)
14. [Roadmap](#roadmap)
---
## Обзор системы
Pleep24 — self-hosted мультиканальный AI-агент продаж. Закрывает полный цикл сделки: от первого сообщения до оплаты.
### Каналы связи
| Канал | Статус | Интеграция |
|-------|--------|-----------|
| Telegram | ✅ Есть | MAX Messenger Bot API (nik_bot) |
| WhatsApp | 🔜 План | WhatsApp Business API / Baileys |
| Instagram | 🔜 План | Instagram Messaging API |
| Web Widget | 🔜 План | WebSocket + JS виджет |
| Voice (телефон) | ✅ Есть | calls24 + Yandex AI Realtime API |
### Ключевые возможности
- **Единый inbox** — все каналы → одна лента переписки, контекст сохраняется при переходе между каналами
- **AI-агент** — квалифицирует лиды, отвечает на вопросы, обрабатывает возражения, назначает встречи
- **Twenty CRM** — все лиды автоматически создаются/обновляются в CRM, AI сам двигает сделки по воронке
- **RAG** — база знаний (Qdrant): каталог, FAQ, скрипты — AI использует их при ответе
- **Голос** — исходящие звонки через calls24, логирование в Twenty
- **Оплата** — счёт прямо в чате (YooKassa / CloudPayments)
- **Dashboard** — админка: настройка агента, просмотр диалогов, аналитика
### Что НЕ делаем (в отличие от Pleep)
- **Свой CRM** — используем Twenty (open source, self-hosted, уже работает)
- **Свой voice engine** — используем calls24 (Yandex Realtime API)
- **Свой payment gateway** — интеграция через YooKassa
- **Своё хранилище файлов** — Twenty уже хранит вложения
---
## Архитектура микросервисов
```
┌──────────────────────┐
Telegram ────────────→│ │
WhatsApp ────────────→│ Message Router │──→ Redis (сессии)
Instagram ───────────→│ FastAPI :8100 │──→ Postgres (логи)
Web Widget ──────────→│ │
└──────────┬───────────┘
│ Internal HTTP
┌──────────▼───────────┐
│ AI Brain │
│ FastAPI :8101 │──→ Qdrant (RAG)
│ LLM + Tools │──→ DeepSeek / Ollama
└──────────┬───────────┘
│ Internal HTTP
┌──────────▼───────────┐
│ Twenty Gateway │
│ FastAPI :8102 │──→ Twenty CRM REST API
│ │──→ YooKassa (платежи)
└──────────────────────┘
calls24 (голос) ──→ Twenty Gateway (Notes / Activities)
```
### Разделение на сервисы — почему три, а не один
| Сервис | Ответственность | Меняется когда |
|--------|----------------|---------------|
| **Message Router** | Приём/отправка сообщений, сессии | Новый канал |
| **AI Brain** | LLM-логика, промпты, принятие решений | Меняем модель/логику |
| **Twenty Gateway** | API Twenty, маппинг полей, платежи | Меняем CRM |
Разделение позволяет:
- Менять LLM-модель, не трогая каналы
- Добавлять каналы, не трогая логику агента
- Мигрировать на другую CRM заменой только Gateway
---
## Twenty CRM — модель данных и интеграция
### Объекты Twenty, которые использует агент
```
Person (контакт)
├─ firstName, lastName
├─ email, phone
├─ city (из Telegram/чата)
├─ position (должность)
└─ avatarUrl
Company (компания)
├─ name
├─ domainName
└─ address
Deal / Opportunity (сделка)
├─ name, amount, closeDate
├─ stage (этап воронки)
├─ pipeline (какая воронка)
└─ personId, companyId
Note (заметка)
├─ title, body
└─ personId, companyId, opportunityId
Activity (активность)
├─ title, body, type (Call, Meeting, Email, Task)
├─ dueAt, completedAt
└─ personId, companyId, opportunityId
Task (задача)
├─ title, body, status
└─ assigneeId, dueAt
```
### Воронка продаж (Pipeline)
```
New Lead → Contacted → Qualified → Meeting Scheduled →
Proposal Sent → Negotiation → Won / Lost
```
AI-агент сам определяет стадию по контексту диалога и двигает Deal через POST/PATCH.
### REST API Twenty (ключевые эндпоинты)
Twenty auto-generates REST API из схемы воркспейса. Standard base: `http://192.168.1.230/rest/`
```bash
# Auth
Authorization: Bearer YOUR_API_KEY
# Поиск/создание Person по телефону
GET /rest/people?filter=phone[eq]{phone}&limit=1
POST /rest/people
# Компании
POST /rest/companies
GET /rest/companies?filter=name[ilike]%{query}%
# Сделки
POST /rest/opportunities
PATCH /rest/opportunities/{id} # смена stage
GET /rest/opportunities?filter=personId[eq]{id}
# Заметки
POST /rest/notes
# Активности
POST /rest/activities
# Batch (до 60 записей)
POST /rest/batch
```
**Лимиты:** 100 RPM, batch до 60 записей.
### Стадия "New Lead" → Person создаётся
При первом сообщении:
1. Ищем Person по phone/email/telegram_id
2. Если нет → создаём Person + Note "Первое сообщение из {channel}"
3. Если есть → получаем связанные Notes, Deals, Activities
4. Передаём контекст в AI Brain
---
## Message Router — маршрутизация сообщений
### Назначение
Единая точка входа для всех каналов. Принимает сообщение, определяет сессию, маршрутизирует в AI Brain, возвращает ответ в канал.
### API эндпоинты
```
POST /api/messages — принять сообщение (общий)
POST /api/webhooks/telegram — Telegram webhook
POST /api/webhooks/whatsapp — WhatsApp webhook
POST /api/webhooks/instagram — Instagram webhook
GET /api/conversations/{id} — история диалога
GET /api/conversations — список активных диалогов
GET /health
```
### Формат сообщения
```json
{
"channel": "telegram",
"external_id": "140245519",
"text": "Здравствуйте, интересует цена",
"timestamp": "2026-07-05T12:00:00+05:00",
"metadata": {
"chat_id": "-1001234567890",
"message_id": 456,
"username": "user123",
"first_name": "Иван"
}
}
```
### Сессионный ключ
```
session_key = sha256(f"{channel}:{external_id}")
```
Один ключ → одна сессия, даже если пользователь переключается между каналами (если указал телефон/email).
### Хранение
**Postgres таблицы:**
```sql
CREATE TABLE conversations (
id UUID PRIMARY KEY,
channel VARCHAR(32) NOT NULL, -- telegram, whatsapp, etc.
external_id VARCHAR(256) NOT NULL, -- ID пользователя в канале
twenty_person_id VARCHAR(64), -- UUID Person в Twenty
twenty_company_id VARCHAR(64), -- UUID Company
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(channel, external_id)
);
CREATE TABLE messages (
id UUID PRIMARY KEY,
conversation_id UUID REFERENCES conversations(id),
direction VARCHAR(8) NOT NULL, -- in, out
content TEXT NOT NULL,
channel_message_id VARCHAR(128), -- ID сообщения в канале
llm_prompt_tokens INT,
llm_completion_tokens INT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE channel_configs (
id UUID PRIMARY KEY,
channel_type VARCHAR(32) UNIQUE,
config JSONB NOT NULL, -- токены, webhook URLs
enabled BOOLEAN DEFAULT true
);
```
### Redis (опционально)
Для rate-limiting и кеширования сессий:
```
conversation:{session_key}:last_activity → timestamp
conversation:{session_key}:person_id → twenty_person_id
rate_limit:{channel}:{external_id} → счётчик
```
---
## AI Agent — мозг системы
### Назначение
Принимает сообщение + контекст из Twenty Gateway, генерирует ответ и список действий.
### API
```
POST /api/process
```
**Запрос:**
```json
{
"session": {
"key": "sha256...",
"channel": "telegram",
"person": {
"id": "uuid-person",
"name": "Иван Петров",
"phone": "+79123456789"
},
"company": null,
"active_deal": {
"id": "uuid-deal",
"name": "КП на CRM",
"stage": "Contacted",
"amount": 150000
},
"last_messages": [
{"role": "user", "text": "Интересует цена"},
{"role": "assistant", "text": "Добрый день! Для какого бизнеса?"}
]
},
"message": {
"text": "Ресторан, доставка",
"timestamp": "2026-07-05T12:01:00+05:00"
},
"kb_context": "### Прайс\nБазовая — 4500 руб/мес. Pro — 9500 руб/мес..."
}
```
**Ответ:**
```json
{
"reply": "Отлично, для ресторана с доставкой подойдёт Pro-тариф — 9500 ₽/мес. Там есть интеграция с iiko и Яндекс.Едой.",
"actions": [
{
"type": "update_deal_stage",
"data": {"deal_id": "uuid-deal", "stage": "Qualified"}
},
{
"type": "update_person",
"data": {"person_id": "uuid-person", "position": "Владелец"}
},
{
"type": "schedule_followup",
"data": {"at": "2026-07-07T14:00:00+05:00", "text": "Уточнить потребность в iiko"}
}
],
"kb_sources": ["Прайс-лист (релевантность 0.94)", "FAQ по интеграциям (0.87)"]
}
```
### Инструменты (tools), доступные агенту
| Инструмент | Описание |
|-----------|----------|
| `search_kb(query)` | Поиск в Qdrant по KB (прайс, FAQ, скрипты) |
| `update_person(data)` | Обновить поля контакта (должность, город и т.д.) |
| `update_deal_stage(deal_id, stage)` | Передвинуть сделку по воронке |
| `create_deal(data)` | Создать новую сделку |
| `add_note(text)` | Добавить заметку в CRM |
| `schedule_followup(at, text)` | Запланировать звонок/встречу |
| `handover_to_human(reason)` | Передать диалог оператору |
| `send_invoice(amount, description)` | Выставить счёт |
| `call_voice(phone, script)` | Инициировать звонок через calls24 |
### Структура сервиса
```
ai-brain/
main.py — FastAPI app
agent.py — LLM-оркестрация (DeepSeek + tool calling)
prompts/
system_v1.md — Системный промпт (редактируемый)
personas/ — Персоны агента
sales.md — Продавец (основной)
support.md — Поддержка
qualifier.md — Квалификатор лидов
tools.py — Реализация инструментов
rag.py — Qdrant-клиент для KB
```
---
## Twenty Gateway — API-прослойка CRM
### Назначение
Прокси для Twenty CRM API. Скрывает детали авторизации, кеширует частые запросы, нормализует ошибки.
### API
```
POST /api/persons/find-or-create — найти по phone/email или создать
GET /api/persons/{id} — контакт + связанные объекты
GET /api/persons/{id}/deals — активные сделки
GET /api/persons/{id}/notes — последние заметки
POST /api/persons/{id}/notes — добавить заметку
GET /api/companies/search — поиск по названию
POST /api/deals — создать сделку
PATCH /api/deals/{id}/stage — сменить этап
POST /api/activities — создать активность
GET /api/pipelines/stages — список этапов воронки
```
### Кеширование
```
person:{phone} → TTL 5 min
person:{id} → TTL 1 min
deal:{id} → TTL 1 min
pipeline_stages → TTL 30 min
```
### Управление ошибками
- **401** — ротация API-ключа
- **429** — retry с backoff (100 RPM лимит)
- **Сетевые ошибки** — 3 ретрая с экспоненциальной задержкой
---
## LLM Prompt Strategy
### Системный промпт (sales.md)
```
Ты — ИИ-продавец компании {company_name}.
ТВОЯ РОЛЬ: квалифицировать лидов, отвечать на вопросы о продукте,
обрабатывать возражения, назначать встречи, доводить до сделки.
ПРАВИЛА:
1. ВСЕГДА начинай с приветствия и представления (только в первом сообщении)
2. Квалифицируй лида: имя → потребность → бюджет → сроки → ЛПР
3. Используй базу знаний для ответов о продукте — НЕ придумывай
4. Если вопрос вне твоей компетенции → честно скажи "уточню у коллег"
и передай диалог оператору
5. Двигай сделку по воронке по мере прогресса диалога
6. Не будь навязчивым — если лид просит "подумать", предложи
вернуться к диалогу через 2-3 дня
ТОН ОБЩЕНИЯ:
- Дружелюбный, но деловой
- Короткие сообщения (2-4 предложения), не полотна текста
- Один вопрос за сообщение
- Эмодзи умеренно, без перебора
КОНТЕКСТ:
- Продукт: {product_summary}
- Прайс: {pricing_summary}
- Текущий лид: {person_name}, {person_position}, {person_city}
- Стадия сделки: {deal_stage}
ДОСТУПНЫЕ ИНСТРУМЕНТЫ:
{available_tools}
```
### Пайплайн сообщения (как LLM принимает решение)
```
1. Сообщение от пользователя
2. Поиск в KB (Qdrant) → релевантные куски
3. Формирование промпта: system + KB + контекст CRM + история
4. LLM (DeepSeek) → reply + actions
5. Парсинг actions → выполнение через Twenty Gateway
6. Отправка reply в Message Router → канал
```
### Fallback
Если DeepSeek недоступен → локальный Ollama (qwen3.6/gemma4).
### Мониторинг качества
- `handover_rate` — % диалогов, переданных оператору (норма <15%)
- `response_time_p95` — время ответа (цель <3 сек)
- `deal_progression` — % сделок, дошедших до Won
---
## Knowledge Base (RAG)
### Хранилище: Qdrant
Уже запущен на a2000. Коллекция: `pleep24_kb`.
### Структура чанков
```json
{
"id": "pricing_pro_tariff",
"text": "Pro-тариф: 9500 ₽/мес. Включает: до 1000 диалогов/мес, интеграцию с CRM, ...",
"metadata": {
"category": "pricing",
"source": "pricing.md",
"updated_at": "2026-07-01",
"tags": ["тариф", "цена", "pro"]
}
}
```
### Категории KB
| Категория | Пример | Обновляется |
|-----------|--------|------------|
| `pricing` | Прайс-лист, тарифы, скидки | При изменении цен |
| `faq` | Частые вопросы и ответы | По мере накопления |
| `scripts` | Скрипты обработки возражений | Версионируется |
| `catalog` | Каталог продуктов/услуг | При изменении ассортимента |
| `cases` | Кейсы, отзывы, примеры | По мере появления |
| `legal` | Договор, оферта, реквизиты | При изменении |
### Загрузка в Qdrant
```bash
python scripts/load_kb.py --file pricing.md --category pricing
python scripts/load_kb.py --file faq.md --category faq
```
### Стратегия поиска
1. Embedding-поиск: top-5 чанков по релевантности
2. Фильтрация: убираем чанки с score < 0.65
3. Сборка: склеиваем в контекст, добавляем в промпт
---
## Web Widget
### Чат-виджет для сайта
```
┌──────────────────────────────┐
│ 💬 Чат с экспертом │
│ ────────────────────────── │
│ │
│ AiAgent │
│ Здравствуйте! Я помогу │
│ подобрать решение. │
│ │
│ User │
│ Интересует CRM для │
│ ресторана │
│ │
│ ────────────────────────── │
│ [Введите сообщение...] 📎 │
└──────────────────────────────┘
```
### Технологии
- **Vanilla JS** (никаких фреймворков, <50KB gzip)
- **WebSocket** → Message Router (быстрее HTTP polling)
- **WebRTC** → звонок через calls24 прямо из виджета
### Встраивание
```html
<script src="https://widget.tarasov.top/chat.js"
data-org="acme-corp"
data-theme="dark">
</script>
```
**Параметры:**
- `data-org` — ID организации (маппится на Twenty workspace)
- `data-theme` — `light` / `dark`
- `data-position` — `right` / `left`
- `data-voice` — `true` если показывать кнопку звонка
---
## Voice Integration (calls24)
### Интеграция с Twenty
После каждого звонка через calls24:
1. calls24 отправляет webhook в Twenty Gateway
2. Twenty Gateway создаёт:
- **Activity** (тип: Call) — длительность, статус, запись
- **Note** — транскрипт звонка (ключевые моменты)
3. Если звонок квалифицирующий → создаётся/обновляется Deal
### Webhook от calls24
```
POST /api/webhooks/calls24
{
"call_id": "call-uuid",
"direction": "outbound",
"from": "+74951234567",
"to": "+79123456789",
"status": "completed",
"duration": 245,
"recording_url": "https://...",
"transcript": "полный текст разговора...",
"summary": "Лид заинтересован в Pro-тарифе, бюджет до 15К, ЛПР — директор",
"person_id": "uuid-person" // если уже есть в Twenty
}
```
### Исходящий звонок через AI Agent
1. Агент решает: `call_voice(phone="+7912...", script="Уточнить бюджет и сроки")`
2. Twenty Gateway → calls24 API: инициировать звонок
3. После завершения → webhook создаёт Activity + Note
---
## Каналы связи
### Telegram (MAX Messenger API)
Уже работает: nik_bot, user_id 140245519.
```python
# Отправка сообщения
curl "https://u0776982.cp.regruhosting.ru/bots/nik_bot/sendMessage" \
-d "user_id=140245519&text=Привет!"
# Webhook приём
# MAX Messenger поддерживает webhooks — настраивается в ЛК
```
### WhatsApp
**Вариант 1 — WhatsApp Business API (Meta):**
- Официальный API через Meta
- Требует верификации бизнеса
- Webhook: `POST /api/webhooks/whatsapp`
**Вариант 2 — Baileys (Node.js):**
- Неофициальная библиотека, reverse-engineered WA Web
- Риск блокировки номера
- Не для production без резервного номера
В архитектуре закладываем абстрактный `WhatsappProvider`, который можно подменить.
### Instagram
Через Instagram Messaging API (Meta), тот же механизм что и WhatsApp.
### Web Widget
WebSocket-соединение к Message Router. Не зависит от платформ.
---
## База данных
### Postgres (общая для всех сервисов)
**База:** `pleep24`
**Таблицы:**
| Таблица | Сервис | Назначение |
|---------|--------|-----------|
| `conversations` | Router | Сессии диалогов |
| `messages` | Router | Лог всех сообщений |
| `channel_configs` | Router | Конфиги каналов |
| `webhook_logs` | Router | Лог входящих webhook'ов |
| `agent_decisions` | Brain | Лог решений AI (audit trail) |
| `kb_documents` | Brain | Метаданные документов KB |
| `call_logs` | Gateway | Лог звонков calls24 |
| `payment_intents` | Gateway | Платёжные намерения |
### Redis (опционально)
- Кеш сессий (conversation_key → person_id)
- Rate limiting
- Очередь сообщений (если нужна асинхронная обработка)
---
## Деплоймент (Coolify + Docker)
### Docker Compose
```yaml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: pleep24
POSTGRES_USER: pleep24
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
message-router:
build: ./message-router
ports:
- "8100:8100"
environment:
DATABASE_URL: postgresql+asyncpg://...
REDIS_URL: redis://redis:6379
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN}
depends_on:
- postgres
- redis
ai-brain:
build: ./ai-brain
ports:
- "8101:8101"
environment:
DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY}
QDRANT_URL: http://192.168.1.230:6333
TWENTY_GATEWAY_URL: http://twenty-gateway:8102
depends_on:
- postgres
twenty-gateway:
build: ./twenty-gateway
ports:
- "8102:8102"
environment:
TWENTY_API_KEY: ${TWENTY_API_KEY}
TWENTY_BASE_URL: http://192.168.1.230
YOOKASSA_SHOP_ID: ${YOOKASSA_SHOP_ID}
YOOKASSA_SECRET: ${YOOKASSA_SECRET}
```
### Требования к серверу
| Ресурс | Минимум | Рекомендовано |
|--------|---------|--------------|
| RAM | 2 GB | 4 GB |
| CPU | 2 cores | 4 cores |
| Диск | 10 GB | 20 GB |
### Что уже есть на a2000
| Сервис | Статус |
|--------|--------|
| Postgres | Есть (много инстансов, можно новый) |
| Redis | Нет → добавить в compose |
| Qdrant | ✅ 192.168.1.230:6333 |
| Twenty CRM | ✅ 192.168.1.230 (за Traefik) |
| DeepSeek API | ✅ через провайдера |
| Ollama (local fallback) | ✅ |
| Silero TTS | ✅ |
| calls24 | ✅ |
| Coolify | ✅ 192.168.1.230:8000 |
| Telegram (MAX API) | ✅ |
---
## Roadmap
### Фаза 1 — MVP (2-3 недели)
- [ ] **Twenty Gateway** — базовые CRUD (Person, Deal, Note)
- [ ] **AI Brain** — единый промпт + DeepSeek + поиск в Qdrant
- [ ] **Message Router** — Telegram приём/отправка
- [ ] **Web Widget** — простой чат на WebSocket
- [ ] **Docker Compose** — деплой на Coolify
### Фаза 2 — Production (4-6 недель)
- [ ] WhatsApp-канал
- [ ] Интеграция calls24 → Twenty (Activity + Note после звонка)
- [ ] Админ-панель (диалоги, аналитика, настройка KB)
- [ ] Мультиарендность (несколько организаций = разные Twenty workspace)
- [ ] Мониторинг и алерты
### Фаза 3 — Расширение (8-12 недель)
- [ ] Instagram-канал
- [ ] Приём платежей (YooKassa)
- [ ] A/B тестирование промптов
- [ ] Self-improving KB (AI сам предлагает дополнить FAQ)
- [ ] API для партнёров