- BrainTools - https://www.braintools.ru -

Как я автоматизировал почти всю работу в CRM

Я долго ходил по конференциям, у меня хороший нетворк, и все это длительное время я наполнял CRM контактами, результатами звонков, переписками, договорённостями и тд.
В какой-то момент в ней оказалось почти 10К человек и вся моя история отношений с ними.
Но накопить данные конечно легче чем применять их так, чтобы была максимальная польза. Чтобы CRM приносила эту пользу, я должен помнить, кого и как там  искать, какие фильтры включить, что делать дальше и как масштабировать это.
Я хотел автоматизировать почти всё.

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

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

  • Контакты, которые у меня появились после личных знакомств на конференциях и телефонных митингов 

  • Отдельно информация о встречах и звонках за 2022–2026 годы;

  • архивы Telegram с десятками тысяч диалогов;

  • карточки людей, заметки, статусы и теги;

  • отдельная старая CRM, которая умела отправлять сообщения.

После объединения и дедупликации получалось 9 718 сущностей-контактов.

Но один человек мог присутствовать сразу в нескольких источниках: например, сначала написать в Telegram, потом прийти на звонок, а через год появиться в заметках под каким-то  другим именем.

В общем,  определить, какие записи относятся к одному человеку, сохранить происхождение каждого факта и не потерять историю – не всегда просто

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

Сначала я хотел взять эту ранее написанную старую CRM, составить список функций и написать вместо нее новую версию, которую смогу сделать идеальнее.

Я от этого отказался.

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

Я разделил систему на две части.

Старая CRM выполняет механическую работу:
– читает и записывает данные;
– получает события;
– отправляет сообщения;
– соблюдает лимиты;
– повторяет запрос после временной ошибки [1];
– сохраняет доказательство отправки.

Все решения переходят к агенту. Он решает:
– кого сейчас стоит поднять из базы;
– почему этот человек важен;
– что изменилось после последнего общения;
– какое действие будет следующим;
– нужен ли вообще контакт сейчас.

Получилась не новая CRM в привычном смысле. Скорее, старая CRM стала руками, а агент – как бы слоем принятия решений.

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

В ней пять основных слоёв:

Как я автоматизировал почти всю работу в CRM - 1

Немного про каждый слой отдельно.

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

У меня 51 000 Telegram-диалогов по четырём аккаунтам. Выгружать полтора миллиона сообщений через LLM дорого и медленно. С этой работой лучше справляются обычные скрипты и SQLite:

SELECT
    dialog_id,
    MAX(message_date) AS last_contact,
    COUNT(*) AS message_count
FROM messages
GROUP BY dialog_id;

Скрипт просто и бесплатно определяет дату последнего общения, количество сообщений и наличие ответа. Модель нужна, когда потребуется понять смысл разговора.

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

Следующий слой объединяет события вокруг человека.

Контакт может быть записан как:
– имя в заметках после звонка;
– Telegram username;
– числовой Telegram ID;
– телефон из WhatsApp;
– имя и компания из визитки;
– участник группового чата.

Надёжного универсального идентификатора нет. Username меняется, имена совпадают, телефон присутствует не везде.

Поэтому объединение идёт в несколько ступеней:

  1. Точное совпадение идентификатора.

  2. Совпадение по username.

  3. Имя плюс компания или другой дополнительный признак.

  4. Совпадения проверяются, не объединяются автоматически.

В карточке сохраняется происхождение каждого факта. Если два источника противоречат друг другу, система должна показать мне это.

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. Автоматизация

Передавать агенту всю историю CRM при каждом запросе нельзя. Даже если забыть о цене, данных для обработки слишком много.

Сначала работает детерминированный поиск:

SELECT *
FROM people
WHERE reactivation_priority >= 75
ORDER BY reactivation_priority DESC
LIMIT 20;

Для каждого лида собирается информация:
кто это;
откуда мы знакомы;
дата последнего контакта;
последние содержательные сообщения;
результаты звонков;
незакрытые договорённости;
подтверждённые общие интересы;
причина, по которой контакт попал в очередь.

Только после этого подключается языковая модель.

Её задача – не искать человека среди тысяч карточек. Она должна решить локальную задачу: что разумно сделать с конкретным контактом, имея подтверждённые факты.

Если данных недостаточно, правильным результатом считается решение needs_review. 

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

Агент не отправляет сразу сам сообщения.

Сначала он подготавливает действие. Затем это действие получает отдельный транспортный слой, который ничего не знает о стратегии, зато знает ограничения канала.

Он проверяет:
– с какого аккаунта можно писать этому человеку;
– не превышен ли лимит;
– не было ли это сообщение уже отправлено;
– не пересекаются ли параллельные кампании;
– есть ли идентификатор доставленного сообщения;
– нужно ли остановиться после ответа.

Между отправками добавляется случайная задержка. При 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: его поставили при заведении карточки и с тех пор никто не менял, потому что статус ни с чем не связан.

Ночной сборщик получает свежие сообщения и видит новый входящий сигнал. Детерминированный расчёт обновляет дату последнего контакта и поднимает приоритет реактивации.
Агент получает только карточку лида с последними сообщениями и с информацией об обещаниях, которые надо выполнять.

После подтверждения сообщение уходит через транспорт. CRM сохраняет идентификатор доставки, дату и причину касания. Если человек отвечает, запланированная цепочка автоматически останавливается.

В этом месте CRM становится моей  системой продолжения отношений с людьми

Не получилось

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

Очень хотелось давать агенту открытые запросы по типу “найди лучшего лида” для определенной цели. На практике это дорогой и плохо проверяемый путь. Модель тратит контекст на сортировку, которую SQL выполняет быстрее и точнее.

Я делаю разделение: код считает, база фильтрует, модель оценивает смысл, транспорт отправляет.

Доверие к статусам

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

Автоматизация только исходящих

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

Но я поменял акценты, мне важнее сейчас тот лид, кто пришёл сам. Поэтому входящие обращения получили отдельную очередь, владельца и срок реакции [2].

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

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

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

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

Без участия LLM выполняются обработка примерно 1,7 млн сообщений, агрегация десятков тысяч диалогов, дедупликация, расчёт давности, фильтрация, проверка лимитов и журналирование отправок.

Модель видит только те несколько карточек, которые уже отобраны обычным кодом. Поэтому стоимость работы агента зависит не от размера всей CRM, а от размера текущей очереди решений.

Большая память [3] агента не должна целиком помещаться в контекст. Она должна уметь доставать маленький, проверяемый фрагмент в нужный момент.

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

Если бы пришлось начинать заново, я бы не начинал с интерфейса CRM.

Я бы построил систему в таком порядке:
1. Неизменяемый архив событий.
2. Устойчивые идентификаторы людей.
3. Провенанс каждого факта.
4. Вычисляемый скоринг с датой пересчёта.
5. Очередь следующих действий.
6. Отдельный безопасный транспорт.
7. И только потом интерфейс.

Большая часть ценности – в правильном переходе от события к следующему действию.

Вывод

Я наполнил CRM данными, а автоматизация началась позже

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

Что я хочу сделать еще? Проанализировать результаты автоматизации и результаты по конверсиям по всей моей базе лидов. Мои агенты будут считать не только все, что и кому они написали, а будут делать мне живые графики по тому, какие категории лидов приносят больше денег, какие этапы коммуникаций стоит доработать, какие формулировки и варианты ответов лидам стоит совершенствовать, чтобы в результате росло количество продаж моих сервисов.

Старая CRM продолжает выполнять механическую работу, которую уже умеет делать.

Автор: Antondz

Источник [4]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/35428

URLs in this post:

[1] ошибки: http://www.braintools.ru/article/4192

[2] реакции: http://www.braintools.ru/article/1549

[3] память: http://www.braintools.ru/article/4140

[4] Источник: https://habr.com/ru/articles/1081584/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1081584

www.BrainTools.ru

Rambler's Top100