Неделя 163. Чужой дом, свой счётчик

Неделя 163. Чужой дом, свой счётчик

Разбор этой статьи

AI-подкаст BotsellerВ чужом доме управляешь не правилами, а объяснениями
0:00 / 0:00

Эту тему разобрали в подкасте. Слушай параллельно с чтением.

Это сто шестьдесят третья неделя с момента, как мы запустили Botseller в августе 2023 года. Период: с 7 сентября 00:00 до 14 сентября 00:00 по Москве.

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

376 записей разработки. Больше, чем любая неделя августа, и в полтора с лишним раза больше прошлой.

Неделя получилась про две разные вещи, которые неожиданно сошлись. Первая: мы всерьёз зашли в чужие экосистемы. Реклама Facebook, комментарии и личные сообщения Instagram. Там не наши правила, не наши форматы и не наши сроки, и половина работы ушла на то, чтобы понять, как именно чужой дом устроен.

Вторая: внутри своего дома мы начали называть цену. У каждого обхода AI-помощника в чатах теперь есть стоимость в деньгах, у каждой остановки причина, у каждого молчания объяснение.

Сырой счётчик недели: 376 записей разработки в 10 рабочих контурах, из них 144 объединённые задачи и 232 прямые правки. По объёму 83,4 тысячи добавленных строк.

Меня зовут Дмитрий Дьяконов, я основатель и CEO Botseller AI. Мы делаем платформу с AI-продавцом, CRM, мессенджерами, автоматизациями, рассылками, календарём и звонками. Каждую неделю я разбираю, что реально сдвинулось в продукте и зачем это нужно бизнесу. Поехали по 163-й.

Пульс недели

Пульс недели 163, сырой счётчик: 376 записей разработки в 10 контурах и 83,4 тысячи добавленных строк кода. Четыре карточки с полосами прогресса: Instagram 110 обновлений, канал стал полноценным, комментарии, реакции и личные сообщения в одном окне; Рой и AI 90 обновлений, внедрены цена обхода, причины молчания и честная остановка очереди; заявки из рекламы 45 обновлений, сквозная передача лидов в CRM за секунду; WhatsApp и тарифы больше 70 обновлений, медиа-шаблоны, защита от дублей и прозрачные тексты отказов провайдера.

НаправлениеЗаписей разработкиЧто это значит простыми словами
Instagram как полноценный канал110комментарии, личные сообщения, голосовые и ответы в одном окне CRM
Рой: цена обхода, причины молчания, честная остановка90видно, сколько стоил каждый обход и почему помощник промолчал
Заявки из рекламы Facebook в CRM45лид из лид-формы попадает в воронку сам, за секунду с небольшим
Тарифы, подписки и платные модули40готовится модель «тариф плюс модули», клиенту пока не видно
WhatsApp: медиа-шаблоны, защита от повторов, тексты отказов30образец картинки прикладывается в форме, отказ провайдера объясняется словами
Автоматизации: пауза и перенос сценариев15сценарий можно поставить на паузу, а не удалять
Права и доступы12право смотреть перестало означать право менять

Главная мысль недели: в чужой экосистеме вы не управляете правилами, но обязаны управлять объяснениями. Меня всю неделю ловили на том, что я не могу ответить клиенту «почему».

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

Заявка из рекламы становится лидом за секунду

Заявка из рекламы становится лидом за секунду. Слева телефон с лид-формой внутри ленты, время 19:45:26, клиент нажимает кнопку отправки. В центре таймер «00:00:01» и пояснение: площадка гарантирует доставку хотя бы один раз, наша база блокирует гонки и параллельные дубли, удалённый менеджером лид не воскрешается. Справа карточка лида в CRM в 19:45:27 с именем, телефоном, меткой источника и статусом, рядом правило маршрутизации: каждая лид-форма имеет свой статус в воронке и свою метку источника.

Начну с того, ради чего неделя и затевалась.

Лид-формы в рекламе Facebook и Instagram собирают заявки прямо внутри ленты: человек нажимает кнопку, поля уже заполнены его данными, отправка занимает секунды. Дальше эти заявки надо откуда-то забирать, и обычно их забирают руками, выгрузкой раз в день. За это время лид остывает.

Теперь заявка попадает в CRM сама. Клиент подключает свою страницу в настройках в один клик, выбирает воронку и статус. Дальше всё.

Замер в бою, в среду вечером: событие от площадки пришло в 19:45:26 по Москве, лид в CRM появился в 19:45:27. Секунда на нашей стороне, и в карточке уже лежат имя, телефон, почта и ответы на вопросы формы.

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

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

Вот такое я люблю: снаружи одна кнопка, внутри полтора десятка решений про гонки, повторы и удалённые записи.

А теперь про то, во что обошлась эта кнопка, потому что тут начинается чужой дом.

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

Всё было готово: подключение проходит, страница отвечает, тестовая заявка создаётся. Заявки не приходили. Ни одна.

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

Хорошо, публикуем. Нажатие кнопки «Опубликовать» через одиннадцать секунд возвращает отказ: недействительный адрес политики конфиденциальности.

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

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

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

Это как сдавать документы в окно, куда ваш район не относится. Бумаги правильные, печати на месте, и вам полдня объясняют, что не так с бумагами. А не так адрес окна, и на стенде об этом не написано.

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

Instagram: голос, который приходит видео, и реакции, о которых не сообщают

Скрытый контракт Instagram, модель айсберга. Над водой обещание интерфейса: канал подключён. Под водой шесть особенностей, у каждой своё решение. Аудио приходит видео-контейнером, решение в перекодировании на лету. Эхо: запись двухканальная, расшифровка выдавала каждую фразу дважды, решение в сведении в моно. Призрачные правки: на каждое сообщение приходят два уведомления об изменении с нулём правок, из-за чего сбрасывался ответ AI. Слепые реакции: о реакциях собственного аккаунта уведомлений нет, CRM теперь запоминает их сама. Блокировка файлов: наши ссылки не открывались, решение в одноразовых ссылках со своего домена. Пустые пузыри: пересланные ролики приходили без содержимого, решение в разборе их в карточки со ссылками.

Instagram на этой неделе перестал быть половинчатым каналом. Комментарии под публикациями, ветки обсуждений, личные сообщения, ответ на комментарий в личку, реакции, голосовые, пересланные ролики. Всё это теперь живёт в одном окне CRM вместе с WhatsApp и Telegram.

Половина работы ушла не на функции, а на особенности, которые снаружи выглядят бредом. Ни одна из них не ошибка площадки. Это её правила, просто нам о них не сказали.

Голосовое сообщение. Площадка в уведомлении честно пишет: это аудио. А по ссылке отдаёт файл в видео-контейнере. Наша система сохраняла его как видео, расшифровка отказывалась работать, AI на голосовое не отвечал вовсе. Теперь тип берётся из уведомления, а сам файл перекодируется в тот же формат, в котором приходят голосовые из Telegram и WhatsApp.

Дальше смешнее. Расшифровка заработала и начала выдавать каждую фразу дважды: «ну здравствуй ещё раз ну здравствуй ещё раз». Оказалось, запись приходит двухканальной, а сервис распознавания обрабатывает оба канала и склеивает результат. Свели звук в один канал, эхо пропало.

Служебные уведомления о правке сообщения. После каждого обычного сообщения приходят два уведомления «сообщение отредактировано» с нулём правок. Система считала их настоящими правками, обновляла версию переписки, а обработка, которая в этот момент готовила ответ AI, видела, что версия изменилась, и молча отменялась. То есть клиент писал, всё сохранялось, и никто не отвечал.

Реакции. Площадка не присылает уведомлений о реакциях, которые ставит сам аккаунт. Мы знаем о сердечке клиента, но не знаем о своём. Из-за этого кнопка «снять реакцию» работала вслепую. Теперь CRM запоминает свою реакцию сама, после подтверждения отправки.

Файлы. Ссылка на файл из нашего хранилища у площадки не открывалась: подпись ссылки не проходила проверку на их стороне. Вложения из CRM просто не доходили до клиента, и снова молча.

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

Пересланный ролик. Когда клиент пересылает в переписку Reels, приходит вложение особого типа, о котором мы не знали. В чате появлялся пустой пузырь, система пыталась скачать веб-страницу как медиафайл, AI получал пустой текст и молчал. Теперь такое приходит карточкой с ссылкой на публикацию, а ссылка становится текстом сообщения, если подписи нет.

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

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

Канал, который умирал ровно через шестьдесят дней

Тихий убийца: доступ на шестьдесят дней. Верхняя линия, как было: доступ выдаётся на шестьдесят дней, потом канал молча умирал, пять попыток отправки уходили в пустоту, в интерфейсе всё оставалось зелёным, а починить можно было только созданием нового бота. Нижняя линия, архитектура выживания: фоновый процесс раз в шесть часов ищет доступы, истекающие через неделю; запас прочности в 28 попыток автопродления переживает временную недоступность площадки; если доступ всё же протух, канал переходит в честный статус «нужен повторный вход» с явной кнопкой. Внизу: в системе не может быть флажков без последствий, стандартный признак «повторный вход» сломал бы Telegram, запросив код из SMS, поэтому логика должна быть изолированной.

Отдельная находка недели, из тех, что заставляют поморщиться.

Доступ к аккаунту Instagram выдаётся на шестьдесят дней. Продлевать его надо самому, обратившись к площадке до истечения срока. Так вот, кода, который это делает, у нас не было вовсе.

То есть любой подключённый Instagram-канал ровно через шестьдесят дней превращался в тыкву. Бот при этом продолжал числиться подключённым, в интерфейсе всё зелёное. Сообщения уходили в пустоту: система пять раз повторяла попытку в мёртвый доступ и сдавалась молча.

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

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

С кнопкой была тонкость, которая мне нравится как пример того, почему в продукте нельзя просто «включить флажок». Существующий признак «канал поддерживает повторный вход» переиспользовать было нельзя: он же управляет открытием окна ввода кода из SMS для Telegram. Поставь мы его, и Instagram при переподключении просил бы у человека код подтверждения, которого никто не присылал.

Я забираю отсюда простое правило: у любого выданного доступа есть срок, и если в системе нет кода, который его продлевает, значит есть дата, когда всё встанет. Проверьте свои интеграции на этот вопрос. У нас таких дат было ровно столько, сколько подключённых аккаунтов.

Сколько стоил этот обход

Цена обхода: ноль это не «пусто». Крупная цитата: мы учим систему объяснять себя, называть цену, причину и остаток. Три карточки. Точная стоимость: журнал вызовов, у каждого обращения своя цена, закон логов гласит, что неопределённость не равна нулю, и если стоимость неизвестна, пишем «неизвестно», потому что ноль это утверждение, что вызова не было. Дерево решений: по каждому чату видно, сколько новых сообщений, что решила модель, какие действия в очереди и какие отклонены, с цитатой сообщения-повода. Причина тишины: у молчащего чата есть человеческое объяснение, например «ждём одобрения администратора», «запрет на запись», «ошибка чтения истории».

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

Теперь видно три вещи, которых не было.

Первая: сколько стоил обход. Каждое обращение к модели считается в деньгах и записывается вместе с журналом. Отдельно скажу про решение, которым я доволен: если стоимость определить не удалось, в журнале стоит «неизвестно», а не ноль. Ноль это утверждение, что вызова не было. Неизвестно это неизвестно. Мы уже наступали на разницу между «пусто» и «не знаю» два выпуска подряд, так что здесь заложились сразу.

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

Третья: почему здесь тихо. У молчащего чата есть причина словами: нет вступившего помощника, ждём одобрения администратора беседы, в этом чате нам запрещено писать, обход не смог прочитать историю.

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

Остановка, которая не врёт

Остановка, которая не врёт. Слева иллюзия, как было: система гасила первую страницу очереди, глотала ошибки и рапортовала «остановлено», а остаток очереди продолжал улетать в чаты. Справа реальность, как стало: команда остановки гасит очередь целиком одной транзакцией, порядок строгий, сначала запрет, потом очистка; в ответ приходят числа «отменено столько-то» и «уже начато отправок столько-то, результат уточняется», а начатые отправки не трогаются, чтобы не потерять ответ и не прислать дубль. Внизу контекст безопасности: право смотреть больше не означает право менять, проверка прав вынесена на сервер для каждого изменяющего действия.

Вторая большая тема по Рою: управление.

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

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

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

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

Там же закрыли два перекоса, которые я считаю важнее новых функций.

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

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

Один оффер пять раз, или почему это правилось в тексте, а не в коде

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

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

Выглядит как бот. Ровно то, чего мы избегаем.

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

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

Проверил на настоящих входах из тех самых чатов: повтор объявления теперь пропускается, первое объявление получает ответ, ответ собеседнику получает ответ.

Один хвост остаётся, и прятать его не буду: объявление, на которое ответили два часа назад и которое уже уехало из окна беседы, по-прежнему не распознаётся как повтор. В списке недавних действий нет адресата, и восстановить его пока неоткуда.

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

Оба раза уронили клиента сами, и оба раза не кодом

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

Теперь про то, как мы сами уронили клиента.

Ловушка среды: 332 падения за час. Слева стойка машины разработчика с рядами пройденных тестов, справа дымящаяся стойка рабочего сервера с ошибками запуска, между ними разница версий. Симптомы: бот клиента ушёл в цикл, живёт двадцать секунд, падает, перезапускается, 332 падения, три часа полной тишины. Ложный след: журнал писал «не авторизован» и уводил диагностику в сторону. Реальная причина: на сервере версия языка младше, и библиотека отказывалась собирать сервис ещё до запуска. Внизу: добавлена проверка сборки в точном образе рабочей среды, урок в том, что версия среды это часть контракта, а зелёные тесты на другой версии не доказывают ничего.

В субботу в 15:23 по Москве выкатили обновление для Telegram-аккаунтов. Через минуту бот одного из клиентов ушёл в цикл перезапусков: живёт двадцать секунд, падает, поднимается снова. За час сорок пять таких кругов набралось 332. Три часа ни одного исходящего сообщения.

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

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

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

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

Правило звучит скучно, но стоило трёх часов молчания у клиента: версия среды это часть контракта. Зелёные тесты на другой версии не доказывают ничего.

Второй инцидент недели тише, но нагляднее.

Сорокатрёхдневный призрак в базе данных. График числа подключений к базе, который ползёт вверх и упирается в потолок, рядом врезка с симптомами: платформа начала отдавать ошибки, база отказала 351 раз за один час. Диагноз: 34 слота заняты мёртвыми служебными сеансами, самому старому 43 дня. Решение: жёсткие лимиты и автоматическое закрытие зависших сеансов, занятость упала почти вдвое. Бизнес-аналогия справа: считать надо не среднюю нагрузку, а сумму в худший день, как в барбершопе на шесть кресел в субботу, где все мастера записали людей по максимуму, а ключи от кресел забрали домой уволившиеся.

С воскресенья по среду платформа периодически отдавала ошибки в кабинете. Разобрались в среду: база данных упиралась в потолок одновременных подключений. Вечером 8 сентября за один час она отказала 351 раз.

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

Закрыли, стало сорок три занятых места из ста вместо семидесяти семи.

Хвост отсюда простой и он в работе: считаем и разводим лимиты, чтобы запас был не на бумаге.

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

Мелочи, которые видно клиенту

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

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

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

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

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

Главный итог недели

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

Неделя оказалась про границу между своим и чужим.

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

Своё это объяснения. Почему тихо, сколько стоило, что именно отменилось при остановке, какой доступ истекает через неделю. Это единственная часть, которой мы управляем целиком.

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

И два инцидента этой недели показали, что дело не только в системе. Бот молчал три часа, потому что тесты доказывали что-то не про ту среду. База отказывала сотни раз в час, потому что служебное подключение осталось открытым сорок три дня назад. Обе поломки не про код. Обе про то, что мы считали само собой разумеющимся и не проверяли.

Следующая неделя начнётся с двух разборов. Первый: почему у одного из клиентов AI-продавец перестал отвечать в WhatsApp, и виноват в этом оказался его собственный приветственный сценарий. Второй: как мы развели право видеть диагностику и ключи от систем, чтобы помогать с разбором мог человек со стороны.

Приходите в Telegram-канал

Если этот формат отчётов вам полезен, подпишитесь на наш Telegram-канал @botseller_ai. Там я каждую неделю выкладываю бортовые журналы и короткие заметки про продуктовые решения, эксперименты и инциденты. Без рекламы, без воды, только то, что мы сами считаем важным.

Если хотите попробовать Botseller в своём бизнесе, используйте кнопку регистрации в шапке сайта. Я не вставляю отдельную ссылку в текст: платформа сама выберет правильный путь входа в зависимости от контура и настроек.

FAQ

Как подключить заявки из рекламы Facebook к своей CRM?

В настройках CRM появилась вкладка для этого: вы входите через Facebook, выбираете свою страницу и указываете, в какую воронку и в какой статус класть заявки. Дальше лиды попадают в CRM сами, обычно за пару секунд после отправки формы. Для каждой лид-формы можно задать отдельный статус и метку источника, чтобы разные кампании не смешивались в одной колонке.

Instagram подключён, но AI не отвечает на голосовые. Это чинится?

Уже починено. Голосовые Instagram приходят в формате, который наш сервис расшифровки не принимал, а часть из них ещё и распознавалась дважды из-за двухканальной записи. Теперь такие файлы перекодируются автоматически, расшифровка идёт по тому же пути, что для Telegram и WhatsApp, и AI отвечает на голосовое так же, как на текст.

Мой Instagram-канал переставал работать примерно через два месяца. Почему?

Потому что доступ к аккаунту выдаётся на шестьдесят дней, а продления в сервисе не существовало: канал молча умирал по истечении срока, оставаясь «подключённым» на вид. Теперь доступ продлевается автоматически заранее, а если он всё же истёк, канал честно показывает, что нужен повторный вход, и рядом есть кнопка переподключения.

Сколько стоит работа AI-помощника в моих рабочих чатах?

Теперь это видно в кабинете: у каждого обхода есть оценка стоимости, и есть сводка за период. Если стоимость какого-то обхода определить не удалось, мы пишем «нет данных», а не ноль, и отдельно показываем, сколько обходов осталось без оценки. Цифры доступны владельцу бизнеса, а не только администраторам платформы.

Я нажал «Остановить» у миссии. Значит, в чаты точно ничего не уйдёт?

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

Сотрудник с доступом к разделу может удалить миссию?

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