Files
pleep24/ARCHITECTURE.md
T

27 KiB
Raw Blame History

Pleep24 — Архитектура AI Sales Agent

Аналог Pleep.app — мультиканальный AI-агент продаж на стеке FastAPI + DeepSeek + Twenty CRM.

Оглавление

  1. Обзор системы
  2. Архитектура микросервисов
  3. Twenty CRM — модель данных и интеграция
  4. Message Router — маршрутизация сообщений
  5. AI Agent — мозг системы
  6. Twenty Gateway — API-прослойка CRM
  7. LLM Prompt Strategy
  8. Knowledge Base (RAG)
  9. Web Widget
  10. Voice Integration (calls24)
  11. Каналы связи
  12. База данных
  13. Деплоймент (Coolify + Docker)
  14. 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/

# 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

Формат сообщения

{
  "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 таблицы:

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

Запрос:

{
  "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 руб/мес..."
}

Ответ:

{
  "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.

Структура чанков

{
  "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

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 прямо из виджета

Встраивание

<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.

# Отправка сообщения
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

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 для партнёров