CRM за вечер и 19 агентов вместо amoCRM: как строить инструменты под себя

В субботу утром открыл свой CRM в mini-app и увидел то, что бесило уже несколько недель. 47 активных карточек плоским списком. Никакого приоритета, никакого понимания, что горит прямо сейчас. У меня 16 вилл, 19 AI-агентов ведут бизнес, лиды идут из 4 каналов. Платить $50 в месяц за amoCRM, к которой агенты не приделаны нативно, не собирался. К вечеру субботы в CRM появились 4 колонки задач, модальные окна с вопросом «когда следующий шаг?» и полная история движения каждой сделки.

Параллельно в те же два дня: починил OOM-краш Whisper-бота жены Юли (8 падений за 13 минут), раскатал anti-slop фильтр на 26 субагентов, запустил rental market data lake по Бали и закрыл инвесторский спор на $7 500 с помощью полнотекстового поиска по базе переписки за 6 месяцев. Это не исключение и не особые обстоятельства. Это обычные два рабочих дня системы, где большую часть работы делают агенты, а я занимаюсь архитектурными решениями и разблокировкой.

Почему я не покупаю amoCRM — и какой принцип за этим стоит

amoCRM — хороший продукт. Красивый интерфейс, готовые воронки, интеграции с телефонией. Для стандартной команды продаж из 3-5 менеджеров — нормальное решение за $50-150/мес. Но у меня другая ситуация.

19 AI-агентов в системе Paperclip ведут задачи, квалифицируют лиды, двигают сделки по воронке. Чтобы агент работал с amoCRM, нужна прослойка: API-вызовы, вебхуки, маппинг полей, обработка rate limits и разных типов событий. Это несколько дней настройки плюс зависимость от стороннего API, который может поменяться, ограничить функционал или лечь в неподходящий момент.

Мой mini-app написан на Python + SQLite, развёрнут на VPS, данные хранятся в моей базе. Агент вызывает функцию напрямую: create_task(deal_id, due_ts, note) или move_deal(deal_id, new_stage). Никаких API rate limits, никаких тарифных ограничений на количество агентов, никаких зависимостей от чужого сервера. Я владею кодом, схемой данных и поведением всей системы.

Правило, которым руководствуюсь уже год: если интеграция с чужим SaaS стоит больше усилий, чем написание своего инструмента под конкретную задачу — пишу своё. За год это случилось 11 раз. Чаще всего — за вечер-два. Амортизированная стоимость каждого инструмента: несколько часов кода и полный контроль над поведением.

Это не призыв всем писать своё. Для стандартной воронки без агентов — amoCRM или Bitrix24 сэкономят время и нервы. Но как только появляется нестандартная автоматизация, которую нужно интегрировать с собственным стеком — считайте стоимость интеграции честно, не только ежемесячную цену SaaS.

Что изменилось в CRM за один вечер: архитектура и реализация

Конкретная проблема: плоский список задач не даёт понять приоритет. Когда активных сделок 47 — нельзя держать это в голове, нельзя надеяться, что агент разберётся без явного контекста о срочности.

Решение — четыре колонки на доске задач:

  • Красная «Без задачи» — лид есть, следующего шага нет. Это пожар. Агент или я обязаны отреагировать немедленно. Лиды без задач горят красным и стоят первыми в списке.
  • «Просрочено» — задача была поставлена, срок вышел, никто не закрыл. Лид в опасности.
  • «Сегодня» — задачи с дедлайном на текущий день, отсортированные по времени.
  • «Завтра» — что запланировано на завтра. Позволяет планировать день заранее, а не разбираться утром что делать.

Ключевое архитектурное ограничение: чтобы сдвинуть сделку по воронке, теперь обязательно ставить следующую задачу. Это не опция — это архитектурный барьер. Перетащил карточку из одной колонки воронки в другую — выскочил модал: «Когда следующий шаг?». Три варианта: «+3 часа», «Завтра 10:00», произвольная дата и время. Выбрал — задача создана автоматически, сделка сдвинулась. Если через 3 часа задача не закрыта — лид автоматически переходит в «Просрочено» и краснеет.

Аналогично с закрытием задачи. Поставил галочку — модал: «Следующий шаг?». Можно пропустить, но тогда лид уходит в «Без задачи» и снова горит красным. Система создаёт постоянное давление на то, чтобы каждый лид всегда имел запланированный следующий контакт. Лид без следующего шага — лид на пути к потере.

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

Техническая сторона реализации: около 200 строк Python для бэкенда (SQLite-операции, timestamp logic, автоматическое создание задач), около 150 строк JavaScript для модальных окон на фронте. Один вечер, около 5 часов суммарно. Стоимость amoCRM за год при $50/мес — $600 плюс несколько дней на интеграцию с агентами. Мой вариант работает с агентами нативно с первого запроса.

OOM-краш Whisper-бота: 8 падений за 13 минут и как это чинится

Утро первого дня. Бот Юли Дары Солар упал. Юля прислала голосовое сообщение длиной 11 минут. Whisper — open-source speech-to-text от OpenAI, который работает локально на нашем VPS — начал транскрибировать и загрузил в RAM 5 ГБ данных. VPS с 4 ГБ RAM без swap ответил OOM-киллером (Out of Memory). Systemd перезапустил процесс. Бот начал обрабатывать то же самое голосовое заново. Восемь крушений за 13 минут.

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

Дыра 1: нет guard на длинные голосовые. Whisper large-v3 весит 2.9 ГБ только для модели. Плюс 11 минут аудио в wav-формате — ещё около 100 МБ сырых данных плюс промежуточные буферы транскрипции. Суммарно — выход за пределы доступной памяти на любом VPS с менее чем 6-7 ГБ RAM. Решение: guard на длину аудио до загрузки модели. Голосовые длиннее 3 минут обрабатываются в чанках через библиотеку pydub (нарезаем на 2-минутные части и транскрибируем последовательно) или пользователь получает сообщение с просьбой написать текстом или отправить короткие части.

Дыра 2: нет персистентного offset. Telegram Bot API работает через long polling. Текущий update_id — идентификатор последнего обработанного сообщения — хранился только в памяти процесса. После рестарта бот запрашивал апдейты без offset и получал то же самое голосовое снова с самого начала. Решение: update_id пишется на диск после каждой успешной обработки сообщения. При старте бот читает offset с диска и продолжает с нужного места. Простейшая реализация — обычный текстовый файл с одним числом: open('offset.txt', 'w').write(str(update_id)).

Дыра 3: нет swap. VPS с 4 ГБ RAM без swap означает, что любой memory spike выше доступного порога кладёт процесс немедленно. Добавил 4 ГБ swap:

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile swap swap defaults 0 0' >> /etc/fstab

Swap — не архитектурное решение, а страховочная сетка. Правильное решение — guard и обработка чанками. Но swap нужен на любом VPS, где работает что-то с непредсказуемыми пиками потребления памяти.

К обеду бот живой. Downtime — около 4 часов. Юля получила транскрипт своего 11-минутного голосового.

Универсальный вывод для всех, кто запускает Whisper локально: закладывайте минимум 8 ГБ RAM для large-v3 без swap, или используйте medium-модель (1.5 ГБ) с обязательным swap 4 ГБ. Guard на длину аудио — с первого деплоя, не после первого краша. Персистентный offset — с первого деплоя, не после первой потери сообщений.

Anti-slop фильтр: как убить канцелярит в 26 AI-агентах одновременно

Пока чинил бот, параллельно раскатал на всех 26 субагентах системы фильтр против AI-стиля в автоматически генерируемых текстах. Проблема знакомая каждому, кто использует LLM для генерации контента: языковые модели по умолчанию тяготеют к определённым фразам и конструкциям, которые делают текст «машинным». Читатель чувствует это интуитивно, даже не осознавая почему.

Фильтр работает в два этапа — sanity-grep и scoring.

Этап 1: sanity-grep по 12 категориям запрещённых фраз. Жёсткий стоп: нашёл совпадение — переписывай перед публикацией. Категории:

  • Чистильщики горла: «давайте разберём», «стоит отметить», «важно отметить», «дело в том, что», «по правде говоря», «откровенно говоря»
  • Филлеры-открытия: «в современном мире», «в наше время», «на сегодняшний день», «как известно», «не секрет, что»
  • Пустые усилители: «и точка», «без вариантов», «это факт», «серьёзно»
  • Наречия-усилители: «реально», «буквально», «искренне», «фактически», «по-настоящему», «по сути»
  • Метакомментарии: «а теперь самое интересное», «и вот тут начинается магия», «внимание, спойлер»
  • Размытые обобщения: «это меняет всё», «ставки высоки», «последствия серьёзные», «причины структурные»
  • AI-хвостики: «надеюсь это поможет», «спасибо что дочитали», «что вы думаете?», «делитесь в комментариях», «это заставляет задуматься»

Этап 2: scoring по 5 осям, 0-10 каждая, порог 35 из 50.

  • Прямота (0-10): сколько фраз можно вырезать без потери смысла? 10 = ни одной.
  • Ритм (0-10): варьируется ли длина предложений? 10 = вразнобой, без шаблона.
  • Доверие (0-10): нет хеджей («возможно», «вероятно», «по сути»)? 10 = факты прямо.
  • Аутентичность (0-10): есть имена, цифры, даты, места? 10 = каждое утверждение привязано к факту.
  • Плотность (0-10): каждое предложение несёт новую информацию? 10 = ни одного повтора-усиления.

Сумма ниже 35 — агент переписывает полностью. 35-42 — точечные правки с перепроверкой. Выше 43 — проходит. Score пишется в метаданные артефакта в формате «Anti-slop: 38/50 (П8/Р7/Д8/А7/Пл8)».

Раскатка на 26 агентов сделана через конституцию — документ AGENTS.md, который инжектируется в каждого агента при запуске через скрипт constitution_distribute.py по крону каждые 15 минут. Добавил раздел с фильтром в конституцию — все 26 агентов получили его автоматически в течение следующего цикла. Не нужно было заходить в каждого агента по отдельности.

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

Rental market data lake: конкурентная разведка по ценам аренды Бали

К вечеру второго дня запустился rental market data lake. Задача: знать в реальном времени, сколько стоит аренда недвижимости по районам Бали — без платных агрегаторов и без ручного мониторинга объявлений несколько часов в неделю.

Архитектура из четырёх блоков:

Источники данных: WhatsApp-чаты и Telegram-каналы с объявлениями об аренде. Их десятки — русскоязычные, индонезийские, международные. Мой бот подключён как участник и в режиме реального времени читает новые объявления. Для WhatsApp используется WhatsApp Business API через официального провайдера; для Telegram — стандартный Bot API в режиме участника группы.

Классификатор: AI-агент разбирает каждое входящее объявление и извлекает структурированные данные: тип объекта (вилла, квартира, студия, коттедж), количество спален (1BR, 2BR, 3BR, 4BR+), район (Чангу, Семиньяк, Убуд, Нуса-Дуа, Буки, Умалас, Перерен, Кроббокан и другие), цена в USD или IDR, срок аренды (посуточно, помесячно, на год). Дубли фильтруются по хэшу контента объявления.

Хранение: PostgreSQL-таблица rental_market_listings с полями object_type, bedrooms, district, price_usd, price_idr, rental_period, listing_date, source_chat, content_hash. Индексы по district + bedrooms + listing_date позволяют быстро агрегировать средние цены за любой период.

Дашборд: 4bos.online/investor/market — агрегированные данные по районам. «Средняя цена 3BR в Чангу за месяц», «медиана по 2BR в Семиньяке», динамика по неделям. Живые цифры, обновляются по мере поступления объявлений из источников.

Практическое применение: мой ассистент теперь может автоматически сверять цены моих вилл с рыночными. Если вилла прайсируется в 3 500 USD/мес, а рынок по тому же району и метражу показывает 2 800-3 200 USD/мес, агент флагирует несоответствие. Если рынок вырос до 4 000 USD/мес — повод пересмотреть ценообразование, не дожидаясь пока потенциальный клиент уйдёт к конкурентам после первого же сравнения.

AirDNA стоит от $99/мес за один рынок и хорошо покрывает платформенную аренду — Airbnb, Vrbo, Booking.com. Но WhatsApp-чаты с местными лендлордами они не мониторят. На Бали значительная доля рынка — прямая аренда без платформ, особенно в долгосрочном и годовом сегменте. Именно этот сегмент закрывает мой data lake.

Полнотекстовый поиск в переписке: инвесторский спор на $7 500 закрыт за 3 часа

Параллельно со всем выше шёл разбор с инвестором по одной из вилл. Инвестор зашёл с новым углом: «По статьям целевое назначение на аренду — 25 000 USD, оплачено 6 000 USD, куда делись остальные 20 000?»

Стандартная коллизия в property management: инвестор смешивает валовую целевую выручку виллы за год с его персональной долей прибыли после операционных расходов — обслуживание бассейна, уборка, коммунальные услуги, комиссии платформ, управляющая комиссия. Разница между «25 000 USD планировали заработать валово на всю виллу» и «вот ваша доля чистой прибыли» — принципиальная. Объяснять на словах в переписке — это теоретический аргумент. Показывать документально — практический.

У меня база переписки за 6 месяцев с полнотекстовым поиском по всем диалогам. Прогнал поисковый запрос по ключевым словам: «первый год», «100 миллионов», «целевой показатель». Нашёл сообщение от 28 декабря 2025 года: я явно написал инвестору, что «первый год — ориентир 100 млн рупий валовой выручки виллы». Инвестор прочитал сообщение — синие галочки зафиксированы — и ответил в том же диалоге на совершенно другую тему. Следующие 5 месяцев — ни одного возражения по этому конкретному вопросу.

Молчание после прочтения при отсутствии возражений на протяжении 5 месяцев — это фактическое согласие. Зафиксировано в переписке с timestamp и статусом прочтения.

Собрал полный пакет материалов: скриншот сообщения от 28 декабря с timestamp, таблицу реальной валовой выручки виллы помесячно за весь период, расчёт распределения между операционными расходами и долей инвестора по контракту. Отправил развёрнутое сообщение совету инвесторов со всей раскладкой. Долг инвестора в размере $7 500 USD зафиксирован в его личном кабинете на 4bos.online/investor/. Ждём реакции.

Время на диагностику, поиск в базе и подготовку документации — около 3 часов. Без базы переписки с полнотекстовым поиском этот разговор мог растянуться на недели взаимных утверждений и превратиться в неразрешимый конфликт мнений.

Вывод для всех, кто работает с партнёрами, инвесторами или корпоративными клиентами: хранить переписку в структурированном виде с полнотекстовым поиском — это операционная необходимость, а не паранойя и не недоверие. Стоимость: база данных и простой бот для сохранения сообщений. Окупается при первом же конфликте, который в любом бизнесе с несколькими партнёрами — вопрос времени, не вероятности.

Итоги: три принципа из двух дней работы

Два дня. Двадцать рабочих линий. CRM переделана, бот починен, фильтр раскатан на 26 агентов, data lake запущен, инвесторский спор задокументирован. Я не сидел 16 часов за клавиатурой — большую часть работы делали агенты параллельно, я занимался архитектурными решениями и разблокировкой конкретных проблем.

Три принципа, которые за этим стоят и применимы в любом бизнесе с несколькими параллельными процессами:

Строй, когда интеграция дороже разработки. amoCRM за $50/мес не подходит под нативную интеграцию с 19 AI-агентами — настройка прослоек заняла бы дни и создала зависимость от стороннего API. Один вечер кода дал инструмент, который работает без прослоек. Не каждый инструмент стоит писать самому — но когда стоит, считайте полную стоимость владения, включая интеграцию и зависимости, не только ежемесячный тариф SaaS.

Инциденты — это архитектурные баги, не случайности. OOM-краш Whisper на 11-минутном голосовом предсказуем: модель large-v3 весит 2.9 ГБ, VPS с 4 ГБ RAM без swap — математика однозначная. Guard и персистентный offset должны были быть с первого деплоя. Каждый инцидент — сигнал о конкретной дыре в архитектуре. Чинить надо дыру, а не симптом.

Данные — операционный актив, который окупается в кризис. База переписки закрыла спор на $7 500 за 3 часа. Rental market data lake даёт конкурентную разведку по ценам в реальном времени без ручного мониторинга. Собирать и хранить структурированные данные о происходящем в бизнесе нужно с первого дня — не после первого конфликта или упущенной возможности.

Весь этот стек — CRM с агентами, Paperclip, anti-slop фильтр, data lake по рынку аренды — я разбираю в клубе «Solar — внутрянка». Не в формате «я учу автоматизации», а в формате «вот моё в проде, бери и адаптируй»: AGENTS.md конкретных агентов, промпты, скрипты, шаблоны архитектуры — всё, что прямо сейчас крутится в боевой системе с реальными задачами. Доступ и подробности: https://4bos.ru/inside/ — от 2 500 ₽/мес.

Из смежного на 4bos.ru: AI-агент для продаж: как бот ведёт клиента от заявки до сделки — там про другой слой той же системы, агентов, которые квалифицируют лиды без участия менеджера.

Юрий Солар, основатель Solar Property: «Год назад я пытался интегрировать n8n, amoCRM и Bitrix24 в единый пайплайн. Через месяц выкинул всё и написал собственный стек. Не из принципа — из математики: поддержка чужих интеграций стоила больше, чем написание своего. Сейчас у меня 19 агентов, каждый делает одно дело хорошо, и всё это управляется через единую базу данных без внешних зависимостей на сторонние SaaS.»

— Solar OS.

Частые вопросы

Когда имеет смысл писать CRM самому, а не брать amoCRM?
Когда интеграция с вашей системой стоит дороже разработки собственного инструмента. В кейсе выше — 19 AI-агентов нативно вызывают Python-функции CRM напрямую, без прослоек и rate limits. Настройка интеграции с amoCRM через API заняла бы несколько дней и создала зависимость от стороннего сервиса. Написать своё заняло один вечер около 5 часов. Для стандартной команды продаж из 3-5 человек без агентов — amoCRM быстрее и разумнее.
Как починить OOM-краш бота с Whisper на VPS с 4 ГБ RAM?
Три шага. Первый: guard на длинные голосовые — аудио длиннее 3 минут нарезать через pydub на чанки по 2 минуты или отклонять с объяснением. Whisper large-v3 весит 2.9 ГБ, плюс само аудио — на 4 ГБ RAM не вмещается. Второй: персистентный offset — update_id Telegram писать на диск после каждой обработки, чтобы при рестарте бот не процессил те же сообщения повторно. Третий: добавить 4 ГБ swap через fallocate + mkswap + fstab.
Что такое anti-slop фильтр для AI-агентов и как его настроить?
Двухэтапный фильтр против AI-клише в автоматически генерируемых текстах. Этап 1: sanity-grep по 12 категориям запрещённых фраз (чистильщики горла, филлеры-открытия, AI-хвостики и другие) — нашёл, переписывай. Этап 2: scoring по 5 осям (прямота, ритм, доверие, аутентичность, плотность), 0-10 каждая, порог 35 из 50. Раскатывается через AGENTS.md — документ-конституцию, которая инжектируется во всех агентов при запуске через cron-скрипт каждые 15 минут.
Как собрать rental market data lake для мониторинга цен аренды?
Архитектура из четырёх блоков: источники (WhatsApp-чаты и Telegram-каналы с объявлениями — бот читает как участник), классификатор (AI-агент извлекает тип объекта, спальни, район, цену, срок), хранение (PostgreSQL с дедупликацией по хэшу контента), дашборд (агрегированные данные по районам с динамикой). AirDNA стоит от $99/мес за один рынок и покрывает Airbnb/Vrbo, но не WhatsApp-рынок прямой аренды — в долгосрочном сегменте на Бали это критичный пробел.
Зачем хранить переписку с инвесторами в базе данных с поиском?
Полнотекстовый поиск по 6 месяцам переписки закрыл инвесторский спор на $7 500 за 3 часа: нашёл сообщение от 28 декабря 2025 с явным условием, которое инвестор прочитал и принял молчанием на 5 месяцев. Без базы этот разговор мог растянуться на недели. Хранение переписки в структурированном виде — не паранойя, а операционная необходимость для любого бизнеса с партнёрами или инвесторами.

Читайте также

Подписаться на блог в Telegram

Читайте свежие кейсы об AI-автоматизации, системной архитектуре и масштабировании бизнеса.

Подписаться