Перейти к содержанию
Публикация AiManual

Как построить AI-агента поверх старой CRM без переписывания: кейс с 10 000 контактов, SQLite и Telegram

Разбор кейса: как добавить LLM-агента к существующей CRM почти на 10 000 контактов, не переписывая её. Пять слоёв архитектуры, SQLite, Telegram и правило «код с

Коротко

Что будет в материале

  1. 01

    Почему старую CRM не нужно переписывать: суть подхода

  2. 02

    Архитектура из пяти слоёв: от событий до безопасной отправки

  3. 03

    Как LLM-агент принимает решения, не перебирая все контакты

  4. 04

    Что понадобится для внедрения: стек и данные

В личной CRM может накопиться почти 10 000 контактов и несколько лет переписки. Переписывать такую систему ради AI-агента не обязательно: в кейсе она разделена на две части, где старая CRM делает механическую работу, а LLM-агент решает, с кем и зачем связаться.

Принцип распределения ролей короткий: код считает, база фильтрует, модель оценивает смысл, транспорт выполняет действия. Модель не ищет людей среди тысяч карточек, поэтому 10 000 контактов не превращаются в неподъёмный промпт.

Ниже разобраны пять слоёв этой архитектуры, порядок их работы и условия, при которых подход оправдан. Материал пригодится тем, у кого уже есть CRM или база контактов на SQLite и кто хочет добавить AI-агента, не переписывая её целиком.

Почему старую CRM не нужно переписывать: суть подхода

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

Разделение ответственности выглядит так. Старая CRM читает и пишет данные, отправляет сообщения и следит за соблюдением лимитов Telegram. LLM-агент принимает решения: с кем связываться, зачем и что написать. Ни одной части не приходится делать чужую работу.

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

Контекст кейса: личная CRM почти с 10 000 контактов, история переписок за несколько лет, SQLite как хранилище и Telegram как канал связи. Это важная деталь, потому что для личной базы требования к надёжности, нагрузке и разграничению прав отличаются от корпоративной системы на несколько отделов.

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

Архитектура из пяти слоёв: от событий до безопасной отправки

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

Неизменяемый архив событий: зачем хранить всё как есть

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

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

Единая карточка контакта с провенансом каждого факта

Карточка собирает данные о человеке в одном месте, и у каждого факта есть провенанс: источник и время появления. Имя, телефон, компания, интересы, часовой пояс, часовой пояс последнего обращения - всё с пометкой, откуда пришло значение.

Провенанс снимает проблему расхождений. Если из Telegram пришло новое имя, а в CRM лежит старое, видно, какое значение свежее и какому каналу доверять. LLM-агент получает не плоский набор полей, а поля с историей, и может обратиться к человеку так, как он сам себя назвал, вместо варианта пятилетней давности.

Скоринг приоритета реактивации: как выбрать, с кем связаться

Скоринг - вычисляемый показатель, который расставляет контакты по приоритету реактивации. Конкретных формул в кейсе не приводится, но логика факторов читается по структуре данных: давность последнего контакта, частота взаимодействий, текущий статус, источник появления записи. Человек, с которым плотно общались месяц назад, и человек из выгрузки пятилетней давности не могут стоять на одной позиции.

Считает скоринг код, а не LLM. Модели не нужно держать в голове арифметику по 10 000 записей: это дорого, медленно и невоспроизводимо. Число, полученное SQL-запросом или скриптом, одинаково при каждом запуске, его можно объяснить и пересчитать одной командой.

Детерминированный поиск кандидатов через SQL

Кандидатов отбирают SQL-запросы. Условия задаются явно: скоринг выше порога, последний контакт больше N дней назад, нет отметки «не беспокоить», нет открытого диалога. Пример структуры запроса на SQLite:

SELECT id, reactivation_score
FROM contacts
WHERE reactivation_score >= 60
  AND last_touch_at < datetime('now', '-180 days')
  AND do_not_contact = 0
  AND has_open_dialog = 0
ORDER BY reactivation_score DESC
LIMIT 20;

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

Транспортный слой: безопасная отправка сообщений в Telegram

Транспорт изолирует отправку от логики решений. Агент передаёт готовый текст и идентификатор контакта, а слой отвечает за то, чтобы сообщение ушло один раз, в допустимое время и без превышения лимитов Telegram. В кейсе эту работу продолжает старая CRM, которая уже умеет отправлять сообщения и соблюдать ограничения.

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

СлойЗадачаЧего от него не ждут
Архив событийХранить все события без измененияПерезаписи истории
Карточка контактаСобирать факты с провенансомПотери источника значения
Скоринг реактивацииСчитать приоритет кодомОценки приоритета через LLM
Поиск кандидатовФильтровать базу через SQLПередачи модели всей базы
ТранспортОтправлять с учётом лимитовРешения, кому писать

Как LLM-агент принимает решения, не перебирая все контакты

На вход модели приходит короткий список, например 20 контактов с наивысшим скорингом. Дальше цикл повторяется:

  1. SQL-запрос выбирает кандидатов по порогу скоринга и условиям отбора.
  2. Для каждого кандидата собирается компактный контекст: карточка, последние события переписки, статус, прошлые попытки реактивации.
  3. LLM оценивает смысл: уместно ли писать сейчас, что предложить, как сформулировать сообщение.
  4. Готовый текст проходит детерминированные проверки и уходит в транспорт.
  5. Результат отправки фиксируется как новое событие в архиве и влияет на скоринг при следующем запуске.

Работа модели ограничена смысловой задачей. Она не считает дни с последнего контакта и не сверяется со стоп-листами: это делает код до и после неё. Такой порядок снижает нагрузку на LLM в разы, потому что вместо 10 000 карточек модель видит два десятка.

В промпт обычно попадают четыре блока: данные контакта с провенансом, краткая выжимка истории, цель обращения и жёсткие правила. В правилах перечисляют запреты (не обещать скидок, не упоминать чужие данные, не давить на срочность) и требуемый формат ответа, например JSON с текстом сообщения, обоснованием и оценкой уверенности. Порог уверенности отсекает случаи, которые лучше показать человеку.

Проверять, что агент не разошёлся с исходными требованиями, можно без вызовов LLM. Как устроены такие проверки и почему длинного контекста для них не хватает, разобрано в статье про intent continuity и верификацию требований: три проверки на чистом Python, без эмбеддингов и обращений к модели.

Что понадобится для внедрения: стек и данные

Минимальный набор компонентов: существующая база контактов, SQLite как хранилище, Telegram как канал связи, LLM для оценки смысла и скрипт или сервис для механики. Конкретные модели, версии SQLite и библиотеки для Telegram в кейсе не указаны, так что выбор остаётся за вами.

SQLite подходит для такого объёма по нескольким причинам. База живёт одним файлом, не требует отдельного сервера, поддерживает полноценный SQL с индексами и транзакциями, а 10 000 контактов вместе с историей переписок укладываются в гигабайты. Ограничение тоже стоит знать: у SQLite один писатель в момент времени, и при параллельной записи из нескольких процессов появятся блокировки. Для личной CRM это редко становится проблемой, для многопользовательской нагрузки лучше сразу смотреть в сторону серверной СУБД.

Выбор LLM зависит от того, сколько кандидатов вы пропускаете через модель в сутки и нужна ли локальная обработка персональных данных. После фильтрации через SQL объём запросов небольшой, поэтому на первый план выходят стоимость и качество формулировок, а не размер модели. Как сравнивать варианты под свою задачу, а не по общему лидерборду, разобрано в материале про прикладной бенчмарк для выбора LLM.

Python здесь удобен тем, что связывает три части: доступ к SQLite, вызов LLM и отправку в Telegram. Слой доступа к данным стоит вынести сразу, чтобы SQL-запросы не расползались по коду агента. Если собираете систему сами, полезен разбор архитектуры AI-агента с нуля: оркестрация, память, инструменты, обработка ошибок и метрики latency, cost и reliability.

Ограничения и подводные камни подхода

Честный список того, что стоит учитывать до старта.

  • В описании кейса названы пять слоёв и их назначение, но деталей реализации нет. Схему базы, формат карточки и правила скоринга придётся проектировать самостоятельно.
  • Метрик эффективности реактивации, точности скоринга и объёмов обработки в кейсе не приводится. Результат придётся оценивать на своей базе.
  • Провенанс требует дисциплины. Как только факты начинают попадать в карточку без источника, преимущество перед плоской таблицей исчезает.
  • Скоринг может ошибаться: контакт с давней историей иногда важнее свежего, а формальные признаки этого не покажут. Порог отбора стоит периодически пересматривать.
  • Отправка в Telegram ограничена лимитами, и их нарушение ведёт к ограничениям аккаунта. Транспортный слой и старая CRM снижают риск, но не отменяют его.
  • Кейс описывает личную CRM. В корпоративной системе добавятся права доступа, несколько пользователей, журнал согласий и требования к хранению персональных данных.
  • Без понимания SQL и основ работы LLM проект быстро упирается в отладку: непонятно, ошибается запрос, скоринг или промпт.

Отдельный риск - стоимость. Если передавать модели всю базу, расход токенов растёт линейно вместе с числом контактов. Фильтрация через SQL убирает эту зависимость, но только пока она выполняется до вызова LLM.

Пошаговый план: как адаптировать кейс под свою CRM

  1. Проведите аудит базы: сколько контактов, какие поля, сколько дублей, есть ли история переписок и в каком виде.
  2. Спроектируйте схему SQLite: таблица событий, таблица карточек и таблица фактов со ссылкой на событие-источник. Начинайте с событий, карточку собирайте из них.
  3. Посчитайте скоринг как SQL-запрос или скрипт с явными коэффициентами. Формулу держите в коде, чтобы её можно было пересчитать и объяснить.
  4. Настройте запросы отбора кандидатов с параметрами: порог скоринга, окно давности, стоп-листы. Ограничьте выдачу небольшим числом строк.
  5. Подключите LLM к уже отфильтрованному списку: соберите контекст из карточки и последних событий, задайте правила и формат ответа.
  6. Сделайте транспорт отдельным модулем с логированием: идентификатор контакта, текст, время отправки, результат. Логи пишите в архив событий.

Начать можно с одного слоя. Соберите архив событий и карточки, а отправку первое время оставьте ручной: агент готовит тексты, вы нажимаете «отправить». Так видно качество решений до того, как система получит доступ к каналу связи.

Итоги: кому подходит и что запомнить

Подход работает там, где уже есть CRM или база контактов с историей и нет желания её переписывать. Он же подойдёт тем, кто ведёт базу на SQLite и хочет получить работающий реактивационный сценарий без покупки новой платформы. При этом понадобятся навыки SQL, понимание работы LLM и готовность поддерживать порядок в данных.

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

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

Подписаться на канал