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.