Загрузка 0
ПОДЕЛИТЬСЯ

Мой блог

Листай вниз

Как я автоматизировал CRM-систему с помощью AI-агентов, SQL и Python

Как я автоматизировал CRM-систему с помощью AI-агентов, SQL и Python

За годы активного посещения отраслевых мероприятий, конференций и поддержания нетворкинга я накопил огромное количество деловых контактов. Со временем в моей CRM-системе сформировалась база почти из 10 000 человек, включающая подробную историю встреч, звонков, переписок и договоренностей. Однако само по себе накопление данных не приносит пользы, если вы не можете эффективно их задействовать. Наступил момент, когда вручную отслеживать статусы, выстраивать фильтры и вспоминать контекст каждого знакомства стало невозможно. Я поставил перед собой задачу автоматизировать максимум процессов в CRM, сохраняя при этом персональный подход к каждому человеку.

Что было в первой версии моей CRM

Первоначально мои данные существовали в разрозненном виде в нескольких независящих друг от друга источниках:

Панель управления очередью контактов и скорингом
Очередь реактивации контактов с наглядными приоритетами и тегами давности касания.
  • База контактов после личных встреч на офлайн-мероприятиях и онлайн-созвонах;
  • Подробные архивы встреч и звонков за период с 2022 по 2026 год;
  • Telegram-архивы, содержащие десятки тысяч диалогов;
  • Заметки, персональные карточки, теги и вручную выставленные статусы;
  • Предыдущая версия CRM, в которой был настроен базовый функционал отправки сообщений.

Когда я объединил и очистил все эти массивы от явных дублей, у меня получилось 9 718 уникальных профилей. Главная сложность заключалась в том, что один и тот же человек мог оставлять следы в разных местах. Например, сначала он писал мне в Telegram, затем приходил на видеовстречу, а еще через год попадал в мои заметки под совершенно другим именем. Связать эти записи в единую цепочку, не потеряв происхождение каждого факта и исторический контекст, оказалось непростой технической задачей.

Реклама

Почему я не стал переписывать CRM с нуля

Изначально у меня было желание полностью выкинуть старый код и написать идеально сконструированную CRM-систему с нуля. Однако я вовремя отказался от этой идеи. В старой системе уже безупречно работали критически важные механизмы: авторизация аккаунтов, корректная отправка сообщений, управление лимитами Telegram и обработка сетевых ошибок. Переписать все это с нуля означало потратить месяцы на повторное исправление сотен мелких багов и краевых случаев, о которых я мог уже и не помнить.

Схема взаимодействия слоев данных в CRM
Разделение механической работы и логики принятия решений в автоматизированной CRM.

Вместо этого я принял решение четко разделить систему на две составляющие:

  1. Старая CRM («Руки»): берет на себя всю рутинную исполнительскую работу — чтение и запись в БД, обработку событий, отправку сообщений, строгое соблюдение лимитов, повторные запросы при сбоях и фиксацию факта доставки.
  2. AI-агент («Мозг»): отвечает за стратегические решения — определяет, кого из базы пора активировать, оценивает важность контакта, анализирует изменения после последних переговоров и формирует следующее целевое действие.

Как система устроена сейчас

Текущая архитектура моей CRM состоит из пяти последовательных слоев, каждый из которых решает строго выделенную задачу.

1. Архив событий

В моей работе задействовано 4 Telegram-аккаунта, суммарный архив которых превышает 51 000 диалогов и 1,5 миллиона сообщений. Прогонять весь этот гигантский объем через LLM неразумно: это слишком дорого и медленно. Поэтому первичное сканирование я доверил обычным скриптам и базе данных SQLite.

Скрипт быстро и абсолютно бесплатно вычисляет базовые метрики коммуникации с помощью простейших запросов:

Реклама
SELECT dialog_id, MAX(message_date) AS last_contact, COUNT(*) AS message_count 
FROM messages 
GROUP BY dialog_id;

Нейросеть на этом этапе вообще не привлекается — она подключается только тогда, когда требуется глубоко понять смысловое содержание конкретной беседы.

2. Единая карточка

На втором слое происходит сборка всех разрозненных фактов вокруг конкретной личности. Информация о контакте может храниться в самых разных формах:

  • Имя в заметках после проведенного звонка;
  • Никнейм (username) в Telegram;
  • Цифровой Telegram ID;
  • Номер телефона в WhatsApp;
  • Имя и название компании с визитки;
  • Данные из групповых чатов.

Универсального идентификатора не существует: юзернеймы меняются, имена повторяются, а телефоны указаны далеко не везде. Поэтому связывание происходит поэтапно: сначала по точному совпадению ID, затем по username, и лишь потом по комбинации «Имя + Компания». Автоматически спорные записи не объединяются — система помечает их и сохраняет источник каждого факта, чтобы при возникновении противоречий я мог лично принять решение.

3. Высчитываю все параметры

Каждому контакту я присвоил категорию отношений: Hot, Warm, Lukewarm, Cold или Archived. Кроме того, система динамически рассчитывает приоритет реактивации по шкале от 0 до 100.

Формула расчета выглядит следующим образом:

priority = 0.35 * recency + 0.20 * frequency + 0.25 * depth + 0.20 * resurgence - penalty

Где задействованы ключевые параметры:

  • Recency: давность последнего содержательного контакта;
  • Frequency: общая частота и количество созвонов/диалогов;
  • Depth: глубина проработки отношений;
  • Resurgence: появление нового входящего сигнала от человека;
  • Penalty: штраф за оставленные без ответа сообщения.

Для затухания активности во времени используется формула полураспада: score = 2 ** (-days_since_event / half_life). На основе этих вычислений система формирует оперативные задачи. К примеру, при последнем пересчете моя база распределилась так: 16 контактов требуют немедленного письма, 77 нужно обработать в течение недели, 601 — запланировать на месяц, а остальные оставлены в покое до новых сигналов.

4. Автоматизация и подготовка контекста

Передавать всю базу в контекстное окно AI-агента невозможно. Сначала срабатывает жесткий детерминированный фильтр в БД:

Реклама
SELECT * FROM people 
WHERE reactivation_priority >= 75 
ORDER BY reactivation_priority DESC 
LIMIT 20;

Для отобранных лидов формируется сжатый датасет: кем приходится человек, история знакомства, ключевые обещания, даты звонков и причины попадания в очередь. Только после этого подключается LLM. Ее задача крайне локальна — решить, какое целевое действие будет логичным для конкретной карточки. Если данных недостает, модель возвращает статус needs_review.

5. Автоматизация коммуникации с лидами

AI-агент никогда не отправляет сообщения напрямую. Он лишь генерирует черновик и предлагаемый шаг. Дальше в дело вступает изолированный транспортный слой, проверяющий ограничения канала:

  • Допустимо ли писать с данного аккаунта;
  • Не превышены ли суточные лимиты;
  • Не отправлялось ли аналогичное сообщение ранее;
  • Есть ли уникальный ID доставленного сообщения.

Между отправками обязательно добавляется случайная задержка (jitter). При получении ошибки FloodWait транспорт выжидает паузу. Все аккаунты используют единый журнал расхода лимитов. В коде это реализовано следующим образом:

if not budget.can_send(account):
    return "LIMIT_REACHED"
if already_contacted(person, campaign):
    return "DUPLICATE"

result = send_with_jitter(message)
if result.message_id:
    record_delivery(result.message_id)
else:
    record_attempt()

Состояние ATTEMPT (попытка) и SENT (подтвержденная доставка) строго разделены в базе, что исключает дублирование рассылок.

Пример работы системы в реальности

Представим лид трехлетней давности. В старой CRM у него висел застывший статус «new». Ночной скрипт-сборщик фиксирует новый входящий сигнал в Telegram. SQL-код обновляет дату контакта и подтягивает приоритет реактивации выше 75 баллов. AI-агент получает очищенную карточку с историей договоренностей и генерирует персональное сообщение. После моей санкции транспортный слой отправляет текст, сохраняя ID доставки. Как только человек отвечает — автоматическая цепочка моментально останавливается.

Не получилось: мои ошибки и выводы

1. Не удалась попытка заставить LLM делать всё

Изначально я хотел давать нейросети верхнеуровневые промпты в духе «найди лучшего лида для предложения сервиса». Это оказалось невероятно дорогим и неэффективным путем. Модель тратила тысячи токенов на банальную сортировку, которую SQL делает мгновенно. Я пришел к строгому разделению: классический код считает, база фильтрует, модель оценивает смыслы, транспорт отправляет.

2. Избыточное доверие к статичным статусам

Ручные статусы в CRM устаревают сразу после их присвоения. Вычисляемый динамический скоринг тоже может ошибаться, но он всегда содержит понятную формулу, дату пересчета и исходные события.

3. Фокус только на исходящих рассылках

Сначала я проектировал систему под холодные исходящие касания. Однако позже сместил акцент: максимальную ценность представляют входящие обращения. Теперь они получают отдельную приоритетную очередь и жесткий SLA на ответ.

Что в итоге автоматизировано

Без моего ручного участия в системе выполняются следующие процессы:

  • Выгрузка и сбор диалогов со всех аккаунтов;
  • Связывание и дедупликация профилей;
  • Расчет давности, глубины и «температуры» контакта;
  • Формирование динамической очереди задач;
  • Фиксация новых входящих сигналов;
  • Подготовка сжатого контекста для AI;
  • Генерация варианта следующего шага;
  • Контроль лимитов Telegram и защита от повторов;
  • Фиксация факта доставки и автоматическая остановка сценария при ответе.

За собой я оставил только ключевые точки контроля: утверждение стратегической цели, проверку рискованных действий и финальное одобрение текстов.

Сколько токенов это экономит

Благодаря переносу первичной обработки на SQLite и Python, около 1,7 млн сообщений и 51 000 диалогов обрабатываются без привлечения LLM. Нейросеть получает на вход лишь несколько отфильтрованных карточек из текущей очереди. Расходы на работу AI-агента зависят не от размера всей CRM, а исключительно от количества решений, принимаемых прямо сейчас.

Что бы я сделал иначе

Если бы я строил такую систему заново, я бы вообще не начинал с интерфейса. Оптимальный порядок разработки выглядит так:

  1. Неизменяемый архив сырых событий;
  2. Надежные сквозные идентификаторы контактов;
  3. Фиксация происхождения (провенанса) каждого факта;
  4. Вычисляемый скоринг с датой актуализации;
  5. Очередь целевых действий;
  6. Изолированный транспортный слой;
  7. И только в самом конце — пользовательский UI.

Вывод

Сначала я наполнил CRM богатой историей данных, и лишь затем построил поверх нее умную автоматизацию. В итоге архив хранит факты, SQL связывает и считает, AI-агент принимает смысловые решения, а транспорт гарантирует доставку. В ближайших планах — внедрить сквозную аналитику конверсий, чтобы агенты наглядно показывали, какие категории лидов и формулировки приносят максимальную финансовую отдачу.

Источник: habr.com

01.