Telegram-бот штрафует своих: как ложные срабатывания модератора выкашивают участников сообщества

28 июня 2026 года я открыл лог удалений в чате «Байки на Бали» и нашёл две записи с одинаковым user_id 269123663. Участник написал «Всем привет. Где можно арендовать авто на 1 день, на завтра?» — бот удалил. Написал почти теми же словами снова — бот снова удалил и влепил страйк. Ни уведомления, ни объяснения. Человек пришёл с обычным вопросом, а система дважды обошлась с ним как с рекламным мусором.

В том же логе — msg 213430: настоящий автоспам с wa.me/@CheapestBaliRentall, прайсом и типовым объявлением автопроката. Его бот оставил заблокированным без проблем. С задачей «убрать спам» бот справлялся. С задачей «не трогать живых людей» — нет.

Хроника инцидента

Чат «Байки на Бали» — сообщество для тех, кто ищет аренду скутеров, советуется про маршруты и спрашивает, где взять машину на день. Типичные вопросы: «Какой байк брать для гор?», «Сколько стоит Honda ADV на неделю?», «Где в Убуде дают авто без залога?» Чат работает примерно как городской форум: люди помогают друг другу, делятся опытом, рекомендуют конкретные места.

Около полутора лет назад я поставил туда бота-модератора. Задача простая: чистить спам — крипту, казино, рефералки, объявления от компаний проката, которые заваливают чат прейскурантами и ссылками на WhatsApp. Бот работал тихо. Я заглядывал туда раз в несколько недель.

28 июня заглянул. Нашёл записи user_id 269123663. Поднял историю: человек сделал два идентичных вопроса с разницей в 10 минут — видимо, решил, что первое не прошло из-за ошибки соединения. Оба раза бот классифицировал сообщение как «реклама автопроката» и удалял. После второго удаления — ещё и страйк.

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

Что происходит с участником в таком случае? Скорее всего — ничего публичного. Человек видит, что сообщение исчезло. Возможно, пробует ещё раз. Получает страйк, не понимает за что. Решает, что в чате строгие непонятные правила или что его почему-то не любят. Уходит молча или остаётся, но больше не пишет вопросов. Это невидимые потери: нет жалоб, нет тикетов, нет сигнала администратору. Просто человек перестал быть активным.

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

Какой спам реально ходит по таким чатам — и почему с ним сложно

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

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

Вторая волна — прокат авто и байков от сторонних компаний. Здесь сложнее: тема «аренда транспорта» — это именно то, о чём говорят в байк-чате. Граница между «объявление от компании» и «вопрос участника» тонкая. Именно на этой волне написали паттерн CAR_PROMO_RE, который потом дал инцидент 28 июня.

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

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

Анатомия ложного срабатывания: почему «авто» стало табу

Логика фильтрации в car_rental.py была простой: ловить любое сообщение, где рядом встречаются слова «авто» или «машина» с «аренда» или «прокат». Расстояние между словами — до 60 символов. Регистр не важен.

Проблема: паттерн ловил любое сообщение, где рядом встречались эти слова, независимо от контекста. Вопрос «Где можно арендовать авто?» давал точно такой же match, что и коммерческое объявление «Аренда авто от 350k IDR/день, wa.me/CheapestBaliRentall». Бот не видел разницы между вопросом и рекламой. С точки зрения регулярного выражения из семи токенов — разницы и правда не было.

Паттерн написали один раз, как эвристику, под конкретную волну спама от компаний автопроката. В момент написания задача была очевидной — фильтровать объявления. Задачу «не зацепить вопрос» никто не проверял, потому что казалось, что вопрос и объявление — очевидно разные вещи. Для простого регулярного выражения они оказались одинаковыми. Это классическая ошибка при написании фильтров: разработчик думает о том, что нужно поймать, и не думает о том, что нельзя трогать. Blacklist пишется без whitelist-теста.

Чем вопрос участника отличается от рекламного объявления

Разница, которую человек чувствует интуитивно, — боту нужно прописывать явно, через признаки структуры, а не через ключевые слова темы.

Вопрос участника: короткий (1-2 предложения, до 120 символов), нет ссылки (wa.me, t.me, instagram.com, любой URL), нет номера телефона (+62...), нет цены и диапазона цен («25$», «200к IDR», «от 50 000»), нет оффера — слов «сдаю», «предлагаем», «звоните», «пишите», «бронируйте». Есть вопросительная конструкция: «где», «как», «сколько», «кто знает», знак вопроса.

Рекламное объявление: содержит wa.me/ или t.me/ ссылку, или явный номер телефона; содержит цену или диапазон цен в любой валюте; содержит призыв к действию («пишите», «звоните», «бронируйте», «DM»); как правило длиннее 200 символов; содержит маркеры-эмодзи (✅, 🔥, 💰) как сигнатуру коммерческого поста.

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

Как мы это исправили: два класса вместо одного правила

Решение — два отдельных регулярных выражения с явным приоритетом проверки. Первое ловит вопросы: смотрит на наличие вопросительных маркеров («где», «как», «кто», «можно», «помогите», «подскажите», «вопрос») рядом с ключевыми словами темы, при этом не требует ни ссылки, ни цены. Второе ловит объявления: смотрит на связку «ключевое слово темы» плюс «контакт или цена» — wa.me, телефон, IDR, USD, рубли.

Порядок проверки критичен. Сначала проверяем паттерн-вопрос. Если совпало — пропускаем сообщение, останавливаем все дальнейшие проверки по этой теме. Только если не совпало с вопросом — проверяем паттерн-объявление. Если совпало — блокируем. Логика: вопрос участника никогда не станет рекламой, даже если содержит оба ключевых слова. Приоритет «разрешить вопрос» всегда выше приоритета «заблокировать рекламу». Это стандартный принцип whitelist перед blacklist.

Тест на реальных сообщениях после правки: «Всем привет. Где можно арендовать авто на 1 день, на завтра?» — вопрос, пропущено. «Аренда авто 4x4 от 350k IDR/день wa.me/CheapestBaliRentall» — не вопрос, заблокировано. «Как сравнить аренду авто и байка по цене?» — вопрос, пропущено. «Сдам авто Honda HRV на месяц, +62 812 345 6789» — не вопрос, заблокировано. Все четыре обработаны правильно.

Оба ложных страйка с user_id 269123663 сняты прямым SQL в таблице предупреждений. Msg 213424 и 213434 удалены из лога нарушений. Msg 213430 (настоящий спам CheapestBaliRentall) оставлен в блоке.

Это второй инцидент за две недели

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

Тогда исправили один паттерн. Сейчас обнаружили другой. Это не случайность — это системная проблема в архитектуре фильтрации, которую строили по принципу «добавить правило и забыть». Каждый паттерн писался как эвристика под конкретный тип спама. Работал до тех пор, пока легитимное сообщение случайно не попадало в тот же шаблон. И каждый раз об этом узнавали не потому что мониторили — а потому что случайно заглянули в лог.

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

Тихая автоматизация: почему работающий бот опаснее сломанного

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

Это называется false negative failure mode в терминах надёжности систем: система не выдаёт ошибок, она просто делает не то. В системах с обратной связью это самый опасный режим именно потому, что его не видно. Нет красного индикатора, нет алерта, нет 500-ки в логах. Всё зелёное — и поэтому не очевидно, что что-то идёт не так.

Пострадавшие участники, как правило, не пишут жалобы. Они просто уходят — или остаются, но перестают задавать вопросы, потому что их слова исчезают непонятно куда. Маленькие сообщества живут на активности реальных людей. Потерять 3-5 активных человека в месяц из-за ложных страйков — за год это ощутимо. Причём это потери не от конкурентов и не от плохого контента, а от инструмента, который ты сам поставил для защиты.

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

Есть важный операционный момент про «тихость» этого типа ошибок. Когда падает сервер — вы знаете это через минуту, потому что мониторинг алертит. Когда бот делает что-то не то — вы можете не знать об этом неделями, потому что бот продолжает отчитываться как «работающий». Именно поэтому мониторинг качества работы бота должен быть отдельным процессом, не смешиваться с мониторингом работоспособности. «Бот живёт и отвечает» — это одна метрика. «Бот не блокирует лишнего» — совершенно другая, и её надо проверять вручную, потому что она не торчит ни в каком автоматическом дашборде.

Долгосрочное обслуживание бота: как не накапливать технический долг

Инциденты 17 июня и 28 июня показали: бот не требует ежедневного внимания, но требует системного обслуживания. Это как с инфраструктурой — можно не думать о ней месяцами, но откладывать обслуживание бесконечно нельзя.

Несколько принципов, которые вывел из двух инцидентов за две недели.

Еженедельный просмотр лога удалений занимает 15 минут и является самой эффективной мерой из всех. Не весь лог — достаточно первых 20-30 записей за неделю, смотреть на сообщения, которые на вид похожи на вопросы или разговор. Без этой привычки узнаёшь о ложных срабатываниях только случайно или от пострадавших — оба варианта значительно хуже.

Явный лог причины блокировки меняет природу расследований. Когда бот писал только «удалено» и текст сообщения, разборка каждого инцидента начиналась с перечитывания кода 15 правил. После добавления поля reason с именем паттерна — «CAR_RENTAL_PROMO_RE», «CRYPTO_RE», «CASINO_RE» — инцидент диагностируется за 2 минуты, а не за час. Это кажется мелочью, но именно так выглядит операционная зрелость.

Тест-набор для каждого нового паттерна — обязательно 5-10 тестовых сообщений: 3-4 «должны блокироваться» и 2-3 «должны пропускаться». Прогонять при старте бота; не прошли — бот не запускается. Второй инцидент не случился бы, если бы при написании CAR_PROMO_RE добавили в тест «Где можно арендовать авто на день?» в список «должно пропускаться».

Добавлять правила по одному, не пакетом. Когда в чате появляется новая волна спама, соблазн — добавить сразу 5-10 правил. Правильная тактика: по одному правилу с недельным наблюдением. При пакетном добавлении при следующем инциденте невозможно изолировать, какое именно из десяти новых правил виновато.

Есть ещё одна вещь, которую сложно формализовать, но важно понимать: контекст чата меняется. В 2024 году основной спам был про крипту. В 2025-м — про прокат авто. В 2026-м появились мотошколы. Правила, которые хорошо работали год назад, могут давать ложные срабатывания сейчас — не потому что стали хуже, а потому что изменился сам контент. Регулярный аудит правил (раз в квартал — минимум) нужен не только для поиска багов, но и для оценки: не устарела ли сама категория спама, которую мы фильтруем? Бывает, что волна прошла, а правило осталось — и теперь ловит уже не спам, а легитимные сообщения на похожую тему.

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

Когда стоит пересмотреть правила своего Telegram-бота

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

Если хотя бы два пункта совпадают — стоит потратить 30 минут на аудит лога и правил. Это дешевле, чем терять доверие реальных участников.

Итого: что стоит забрать из этой истории

Главный вывод не технический. Опаснее не бот, который ничего не делает, а бот, который уверенно делает не то. Тихо, без ошибок, с правильными записями в логе.

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

Один обиженный участник дороже десяти удалённых спамеров. Это не метафора — буквально так, если вы строите живое сообщество, а не накрутку подписчиков. Обиженный уходит молча, забирает с собой рекомендации, которые мог бы дать другим.

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

Как устроен мой бот изнутри — правила, логика классификации, схема приоритетов, код — всё это в клубе «Solar — внутрянка». Не курс, не лекция — просто то, что крутится в моём проде, в первозданном виде. Бери и адаптируй под свой чат: 4bos.ru/inside/

Также по теме: AI-агент для продаж — другой конец той же задачи: там агент вовремя отвечает живым людям. Здесь бот вовремя не трогает живых людей. Оба случая требуют одного — не доверять правилам, которые никто не пересматривал последние несколько месяцев.

— Solar OS.

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

Как понять, что telegram-бот блокирует нормальных участников?
Самый надёжный признак — жалобы участников, что «написал вопрос и сообщение пропало» без уведомления. Второй признак — падение активности в чате при неизменном числе подписчиков. В нашем случае обнаружили проблему через 2 дня: бот удалил 2 легитимных сообщения и выдал 2 ложных страйка пользователю с id 269123663. Оба раза человек не понял, за что его наказали, и больше не писал в чат.
Чем вопрос участника отличается от рекламного объявления в Telegram?
Вопрос: 1-2 предложения, нет ссылки (wa.me/t.me/URL), нет номера телефона, нет цены, нет оффера («сдаю», «предлагаем», «звоните»). Объявление: содержит wa.me/ или t.me/ ссылку, или +62 номер, или конкретную цену в IDR/USD, или призыв к действию. Правило простое: если нет контакта и нет прайса — это вопрос, трогать нельзя.
Как написать правила для telegram-бота, чтобы не блокировать своих?
Разбейте паттерны на два класса: QUESTION_RE (вопрос без контакта) и PROMO_RE (объявление с контактом/ценой). Порядок проверки: сначала QUESTION_RE — если совпало, пропускаем и останавливаемся. Только если не вопрос — проверяем PROMO_RE. Такой приоритет гарантирует: вопрос никогда не станет рекламой, даже если содержит ключевое слово «аренда» или «авто».
Что делать с ложными страйками, которые уже выданы?
Снять немедленно через API или прямым SQL в таблице предупреждений. В нашем случае обнулили счётчик user_id 269123663 — удалили записи msg 213424 и 213434 из лога нарушений. Спам msg 213430 (CheapestBaliRentall) оставили в блоке. Важно: пройтись по логу удалений за весь период действия «плохого» правила.
Нужен ли человек в связке с telegram-ботом-модератором?
Да, особенно первые 2-3 месяца после запуска или после каждого обновления правил. Хорошая схема: бот удаляет и логирует причину (имя паттерна), человек раз в неделю просматривает 20-30 последних удалений на ложные срабатывания. Это 15 минут в неделю против ежедневной ручной модерации. Без еженедельного просмотра лога узнаёте о проблемах только от пострадавших.

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

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

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

Подписаться