# 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 ``` **Параметры:** - `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 для партнёров