Дисклеймер: в статье упоминается Meta — организация, признанная экстремистской и запрещённая на территории РФ.
Все ключи, телефоны и названия в примерах изменены; код, схема, логика и скрины‑ из рабочего проекта заказчика, и строго с его разрешения! Статья не является рекламой/самопиаром и тому подобное.
В прошлой статье я разобрал конвейер между агентом и клиентом: теги, регулярки, абзацы по 180 символов. Осталось два больших пояснения — что происходит со сделкой в amoCRM, когда диалог дошёл до неё. Поэтому сегодня показываю два Salesbot’а, которые замыкают контур: «Раздатчик» (диспетчеризация задач менеджерам) и «Идентификатор» (оцифровка старой базы).
Хочу начать с вопроса, который оставался за кадром всех предыдущих статей. Нода IF: Is New User? в начале ветки проверяет Redis‑ключ связки: пустой — значит клиент новый, запускаем синхронизацию со сделкой. А если клиент старый — заведён в CRM руками за год до внедрения ИИ? Если к примеру, как в данном проекте, у заказчика сделки хранятся до последнего пока, база не дойдёт примерно до 30 000 сделок? У такого клиента связки тоже нет. Формально, для автоматизации он выглядит как новый. Обычная система в этот момент создаёт вторую сделку на первого же старого клиента, который написал ночью. Дубль = Добро пожаловать в слепую зону!
CRM‑ветка: что происходит после Is Dialog Finished?
Напомню, где мы остановились. Нода Is Dialog Finished? (три условия через OR) решила: диалог больше не болтовня, несём данные в CRM. Дальше топология такая:
Is Dialog Finished? -> Redis: Get Union Link -> IF: Has Union Link? TRUE -> Amo: Update Existing Lead (Union) -> Redis: Save Union Link FALSE -> Prepare IG Response -> Send direct message -> Clear Cache
FALSE‑ветка скучная и правильная: ответили клиенту, почистили агрегат, разошлись. Ничего более. А TRUE‑ветка — это поход в amoCRM. Перед ним, естественно, ещё одна проверка: связку не просто читаем, а валидируем:
// из Redis достаётся ключ вида {"leadId":"123456"} IF: JSON.parse($json.amoLeadId).leadId не пустое
И только потом — обновление сделки. Вот его реальный маппинг (ID кастомных полей amoCRM оставил как есть — они вам ничего не говорят, зато честно видно, что поле не одно):
Поле amoCRM |
Что пишем из n8n |
|---|---|
Вердикт ИИ (text) |
|
MESSENGER‑ID (textarea) |
|
MESSENGER‑TYPE (textarea) |
источник — объект вебхука ( |
Ответ ИИ (textarea) |
анкета: Имя / Дата рождения / Контакт / Дизайн / Сфера |
Тег сделки |
|
Код обновления, сокращённо до сути:
{ id: JSON.parse($json.amoLeadId).leadId, responsible_user_id: 13533162, // жёстко прописанный менеджер custom_fields_values: [ { id: 2452289, value: verdict }, // Вердикт ИИ { id: 2461565, value: chatId }, // MESSENGER-ID { id: 2458673, value: 'Имя: ...\nДата рождения: ...\nКонтакт: ...\nДизайн: ...\nСфера: ...' } ], _embedded: { tags: [{ id: task }] } }
Три решения здесь не случайны.
Почему «Ответ ИИ» — отдельное поле, а не «пусть менеджер откроет Direct». Менеджер утром открывает карточку и видит анкету целиком: имя, дата рождения, контакт, сфера, дизайн. Ему не нужно листать мессенджер и собирать данные по сообщениям. Это и есть разница между «данные где‑то в системе» и «данные в карточке».
Почему responsible_user_id прописан жёстко. Помните засаду из второй части — штатная интеграция при обновлении перетягивала «Ответственного» на своего технического пользователя? Вот его лечение в коде: каждый апдейт возвращает сделку нужному менеджеру. Не однажды — а именно каждый).
Кстати, поясню про «апдейт возвращает сделку нужному менеджеру». В этом проекте весь ночной поток замыкается на одного ответственного: старшего менеджера, который утром быстро разбирает сделки и распределяет дальше. Роутинг по исполнителям (этот лид в воронку ХХХ менеджеру 1, этот лид в воронку ХХХ менеджеру 2 и тому подобное) Это внутренняя бизнес‑логика заказчика: она живёт на его стороне и меняется, и зашивать её в код автоматики я не хочу — автоматизация не должна знать о бизнесе больше, чем требуется для её задачи! В идеальном мире здесь динамический ID из конфига; здесь же граница «отдать на единую точку входа, дальше — люди и их правила» оказалась честнее.
Почему после апдейта снова Save Union Link. TTL связки продлевается при каждом касании: клиент, который пишет каждую неделю, никогда не выпадет из контекста.
Salesbot “Раздатчик”: почему задача, а не уведомление
ИИ агент отработал ночь, данные в карточках. Казалось бы — победа. Но представьте утро менеджера: в воронке пятнадцать сделок, обновлённых за ночь, и среди них три горячих лида с телефонами. Без диспетчера он открывает карточки по очереди, в порядке, в котором они отображаются — а не в порядке приоритета. Горячий лид с телефоном ждёт рядом с «посмотрел каталог».
Это и есть слепая зона между «данные зафиксированы» и «данные отработаны». Закрывает её Salesbot "Раздатчик" — встроенный механизм amoCRM, который живёт уже не в n8n, а внутри CRM и триггерится на события воронки.
Алгоритм из четырёх шагов:
Сканирование маркеров. Salesbot проверяет сделку на системные теги (к примеру
NEED_MANAGER_CALLиз[TASK:]) и валидность поля «Вердикт ИИ».Оценка критичности. Поле «Вердикт ИИ» заполнено значит, ночь закончилась не просто перепиской: есть имя, контакт и суть запроса. Сделка признаётся приоритетной.
Постановка задачи. На ответственного менеджера мгновенно вешается задача с типом «Связаться с клиентом (Лид от ИИ)» и жёстким дедлайном.
Контроль внимания. Менеджер приходит на смену и видит не «какую‑то обновлённую карточку», а активную задачу со счётчиком времени в разделе «Мои задачи».
Почему Salesbot, а не n8n напрямую. Резонный вопрос: задача создаётся в amoCRM — почему бы не слать её из воркфлоу через API? Технически можно. Но у этой операции нюанс,если можно сказать, «юрисдикции». Момент "сделка горячая = ставь задачу" определяет не мой воркфлоу, а состояние воронки: тег появился, поле «Вердикт ИИ» заполнилось, ответственный назначен. Чтобы отследить это из n8n, пришлось бы строить вторую подсистему наблюдения: поллинг состояний сделки, собственные расписания, обработку смены ответственного. Salesbot — это штатный механизм amoCRM: он живёт внутри событий воронки и выполняет в данном проекте ровно одну функцию — как только в сделке появился тег NEED_MANAGER_CALL и валидный «Вердикт ИИ», железобетонно выставить задачу ответственному, с дедлайном.
Разделение ролей получается жёсткое. Интеллект = в n8n: сформировать правильный тег, посчитать вердикт, закинуть его в сделку = это работа инженера, и вся она описана выше. Диспетчерская доставка = Salesbot'у: нативный механизм, которому эта функция заложена изначально. Принцип: мы не отдаём Salesbot'у мышление — мы отдаём ему доставку.
И это не «тупо просто решение», а осознанная граница инструментов. Возражение возможны против такого подхода: в community нодах amoCRM для n8n есть ноды по задачам — Get list of tasks, Create new tasks, Update tasks. Технически создать задачу из воркфлоу можно.

Salesbot живёт по другую сторону в данном проекте — внутри amoCRM. Его триггер не мой вызов API, а само состояние сделки: в карточке появился тег NEED_MANAGER_CALL и валидный «Вердикт ИИ» = задача выставлена ответственному, с дедлайном. Неважно, кто поставил тег: воркфлоу ночью или менеджер руками днём, механизм отработает одинаково. Кросс‑системных запросов между «тег появился» и «задача в Моих задачах» равен нулю. Ломаться нечему здесь нечему в принципе.

Бонус, который оценить должен в принципе любой заказчик: задача с дедлайном является самым видимым и проверяемым следом!. Менеджер пропустил горячий лид? Это видно по задаче, а не по жалобе клиента через два дня. Снял тег вручную, чтобы ИИ агент не мешал? Действие осталось в истории карточки = саботаж автоматизации наблюдаем, а не растворяется в тишине. Технические сбои падают в executions,а человеческие остаются в карточке: система не прячет ни тех, ни других. Может звучит как то жёстко, наверное и не к месту, но вполне рабочая инструкция по оценке работы каждого.

Возникает вопрос про дубли: Salesbot триггерится на тег, а что если тег сняли и он появился снова? Задача встанет повторно. И это не баг, а цикл сделки: тег = рабочая метка людей, а не флаг машины. Ночью агент ставит тег, когда появились свежие данные; днём менеджер, взяв карточку, снимает его и двигает сделку дальше по своим правилам. Тег вернулся = значит, ночью были новые данные или новый повод, и вторая задача оправдана. Пока тег живёт в карточке = задача одна; тег снят = контур молчит.
Так что граница простая: сложную логику = извлечение вердикта, защиту от race condition, буферы = реализуем в n8n своими мозгами. Нативную доставку задачи внутри CRM = отдаём платформе: у неё для этого штатный механизм, который срабатывает по событию, а не по вызову.
Отдельно про «почему задача, а не уведомление». Ответ: это принципиальный выбор. Уведомление можно смахнуть и забыть; оно живёт секунды. Задача с дедлайном является неким элементом учёта: она висит в списке, у неё есть срок, её невыполнение видно. Когда я пишу «исключить человеческий фактор», я не имею в виду, что менеджеры плохие. Я имею в виду, что «посмотрю карточки после кофе» обычное, нормальное человеческое поведение, и система должна быть рассчитана на него, а не на идеального исполнителя.
Salesbot “Идентификатор”: слепая зона старой базы
Теперь обещанная разгадка из интро данной статьи. Схема из второй части работает идеально, пока связка «чат = сделка» строится для новых клиентов: клик по рекламе = новая сделка от штатной интеграции = синхронизация = связка в Redis на 30 дней. Замкнутый цикл.
Но у любого бизнеса, внедряющего автоматизацию, за плечами уже есть база. Клиенты, заведённые менеджерами вручную, со сделками, историей, покупками. Что происходит, когда такой клиент вспоминает о вас в час ночи и пишет в Direct?
Разбираем по схеме: связки в Redis нет (её некто не создавал — сделку тогда создавал человек), поле MESSENGER-ID в карточке пустое. IF: Is New User? видит пустой ключ и делает единственно возможный логичный вывод: новый клиент. Дальше штатная интеграция создаёт вторую сделку на человека, который уже купил у вас браслет. Он замечает, что его «заново завели» — и это уже не техническая проблема, а репутационная.
Salesbot “Идентификатор” закрывает эту дыру на стороне amoCRM. Его настройки (реальные):
источник: НЕЛЬЗЯgram‑сообщения;
триггер: первое входящее сообщение от контакта;
режим: ежедневно с 20:00 до 00:00 и с 00:00 до 10:00 — ровно окно работы ИИ;
этапы воронки: все, кроме «Неразобранное».
Алгоритм работы:
Перехват. Старый контакт пишет в Direct в нерабочее время. Salesbot, в отличие от меня, всегда смотрит в базу: этот chatId у нас уже есть. Он инициализирует технический POST‑запрос в n8n.
Runtime‑идентификация. n8n параллельно держит два потока: вебхук от amoCRM (через Salesbot) и входящий поток от НЕЛЬЗЯgram Graph API. Они приходят почти одновременно.
Генерация связей. n8n прописывает
MESSENGER-IDв существующую карточку и создаёт в Redis ключ связкиapp:union:ig:{chatId}с обычным TTL 30 дней.Результат. Слепая зона закрывается на лету, сессия не прерывается: к моменту, когда ветка агента дойдёт до
Is New User?, связка уже существует, и старый клиент опознаётся как старый. ИИ видит контекст прошлой покупки, а не спрашивает «чем могу помочь?» у человека, который у вас уже покупал.
Возникает вопрос: почему параллельные вебхуки не конфликтуют? Ответ реализован в два этажа защиты — вкратце поясню оба. Первым является идемпотентная запись: ключ детерминирован chatId, значение —leadId той самой карточки; кто бы ни пришёл первым, Salesbot‑вебхук или поток НЕЛЬЗЯgram, в Redis ляжет одно и то же. Однако могу сказать что как раз запись только полдела. Вторая защита — двухэтапное решение. Ранняя защита нодой IF: Is New User? — предварительный этап: он лишь решает, ставить ли ключ синхронизации, и ничего не создаёт. Финальный вердикт выносится позже, в CRM‑ветке, на свежих данных: перед обновлением сделки стоит повторная проверка — ноды Redis: Get Union Link → IF: Has Union Link? (видно на топологии в начале статьи). От старта потока до этой перепроверки проходят десятки секунд = Salesbot и штатная интеграция успевают отработать, связка на месте, и ветка воркфлоу уходит в обновление существующей карточки, а не в создание дубля. В общем одной фразой можно пояснить так: Идемпотентная запись закрывает гонку записи, перепроверка = гонку решения.
Самое приятное в этом модуле — он оцифровывает базу сам. Каждый старый клиент, написавший ночью, навсегда получает MESSENGER-ID в карточке и связку в Redis. Через пару месяцев работы вся активная база оказывается «подключённой» к ИИ‑контуру без единого ручного действия.


Стоп‑кран: как человек перехватывает диалог
Последний элемент, который отличает боевую систему от демо: что происходит, когда менеджер хочет вмешаться в диалог, который ведёт бот.
Требование формулируется просто: любое событие «человек вступил в диалог» должно глушить бота — иначе клиент получит два ответа подряд от разных сущностей. В моей схеме это решено на двух уровнях.
Проверка перед отправкой. В ветке отправки стоит предохранитель IF: Go or STOP?, который смотрит на связку со сделкой до того, как воркфлоу пойдёт дальше. Отбойная ветка (Clear Cache STOP) подчищает агрегат сообщений, чтобы накопленный буфер не протёк в следующую сессию. Гарантия банальная, но критичная: не отправляем то, что отправлять уже не нужно.
Управление по состоянию сделки. Идея, которую я вынашиваю в следующую итерацию из обсуждений с заказчиком — явный флаг: скрытое поле‑чекбокс «Остановить ИИ» в карточке. Перед отправкой ответа n8n проверяет галочку; менеджер, взяв диалог, ставит её = бот молчит. Вариант ещё проще, который уже работает в amoCRM из коробки: смена этапа сделки на «взят в работу» = как сигнал. Здесь честно скажу: текущая версия закрывает основной сценарий, чекбокс — следующий шаг, и я сознательно не выпускаю его, пока не проверю все ветки (ну и обсуждение условий и одобрения заказчика).
Важно, что стоп‑кран не ломает сессию: Redis‑контекст и связка остаются на месте. Когда менеджер закончит и клиент снова напишет ночью — бот продолжит с того места, где был контекст, а не с «Здравствуйте! Чем можем помочь?».
Что в итоге в цифрах
Методология прежняя: amoCRM + Google Sheets, не контролируемый эксперимент. Что могу сказать честно:
сделок с дублями после внедрения «Идентификатора» = 0;
задача «Связаться с клиентом (Лид от ИИ)» ставится на каждую сделку с непустым «Вердиктом ИИ» — здесь механика даёт 100% покрытие по построению;
среднее время реакции менеджера на задачу: около 15 минут (в пики нагрузки конечно может и до получаса доходить);
снижение ручной работы команды — около 40% (оценка по списку задач до/после, как и во второй части).
Что дальше
На бумаге всё выглядит красиво: вот мы элегантно закрыли проблему вебхуков, вот дисциплинированные Salesbot'ы ставят задачи, вот стоп‑кран для человека. Но у каждой схемы есть обратная сторона, которую не рисуют на архитектурных картинках: собственная архитектура ломает всё сама (сложный промпт — это тоже риск), есть ограничения платформ, и есть баги, которые всплывают не в день запуска, а спустя время — когда трафик идёт как снежный ком.
В следующей части — разбор самого странного бага: рассуждающая модель тратила токены, отчитывалась finish_reason: "stop", а клиенту уезжала пустая строка. Reasoning Lock: почему LLM сама решает молчать, почему это не ловится «автотестами» — и четвёртый контур предохранителей, на этот раз от самой модели.
Всем добра, и надеюсь, что понравился разбор, а статья будет полезна!:‑)