Telegram-бот для модерации чата: как избежать ложных страйков и не потерять живых участников
17 июня 2026 года бот в чате «Байки на Бали» удалил каталог байков и пост мотошколы. 28 июня — снова: 2 сообщения живого участника снесены за вопрос про аренду авто, человеку выдан страйк как спамеру. За 11 дней один и тот же автоматический модератор дважды ударил по своим. При этом настоящий спам — ссылка на CheapestBaliRentall с wa.me и прайсом — остался в чате нетронутым ровно до момента фикса.
Ложные срабатывания (false positives) в Telegram-модераторах — нормальная техническая проблема, но с ненормальными последствиями для сообщества. Живой человек получает страйк, не понимает за что, и либо уходит, либо теряет доверие к чату. Спамер в это время успевает написать ещё несколько объявлений. Худший сценарий — когда владелец чата вообще не знает, что бот это делает: нет логирования удалений, нет мониторинга, есть только тихое выкашивание живых участников. Бот работает, показатели не ухудшаются видимым образом — просто сообщество медленно теряет активных людей.
В этой статье — разбор реального инцидента с кодом фикса, чек-листом тестирования и понятной архитектурой того, как автомодератор эволюционирует по мере роста сообщества. Статья написана на основе живого кейса — бот реально работает в реальном чате, фикс применён 28 июня 2026 года.
Почему автомодератор бьёт по своим — не баг, а архитектурная проблема
Большинство Telegram-ботов для модерации работают на простом принципе: чёрный список слов и паттернов. Встретил «аренда авто» — удалил. Встретил «wa.me» — удалил. Логика линейная, и в этом её главная слабость.
Проблема в том, что контекст слова важнее самого слова. «Аренда авто» в сообщении «Где можно арендовать авто на 1 день, на завтра?» — это вопрос соседа. «Аренда авто» в сообщении «Сдаём авто! Лучшие цены! wa.me/+62123456789» — это реклама. Для человека разница очевидна. Для бота без контекстного анализа — нет.
Три признака, которые превращают сообщение по теме чата в рекламный спам:
- Ссылка или контакт: wa.me, t.me, http, +62 xxx, @username продавца
- Оффер или цена: «лучшие цены», «от 100k IDR в день», «пишите нам», «скидка 10%»
- Призыв к действию без вопросительного знака: «звоните», «пишите», «заходите», «доступно прямо сейчас»
Вопрос участника не содержит ни одного из этих признаков. Он содержит только тему — машину, байк, аренду. Бот, настроенный на тему без учёта контекста, срабатывает на вопросы так же часто, как и на рекламу.
По данным практики модерации тематических сообществ с 2 000+ участников, ложные срабатывания на вопросы составляют 15–40% от всех удалений — в зависимости от жёсткости правил. Для чатов, где тема разговора участников буквально совпадает с темой рекламного спама (байки, аренда жилья, туризм), этот процент выше. Бот, созданный защищать чат про байки от рекламы байков, неизбежно будет натыкаться на вопросы про байки.
Это не баг конкретной реализации — это архитектурное ограничение однослойной фильтрации. Единственное решение — добавить слой контекстного анализа: не «есть ли тема», а «как тема оформлена». Вопрос это или предложение купить — разница именно в оформлении, а не в теме.
Кейс: чат «Байки на Бали» и три инцидента за 11 дней
Чат «Байки на Бали» — Telegram-сообщество для тех, кто ищет байк или скутер на Бали: аренду, советы, механиков. Автомодератор работает с начала 2026 года — вычищает рекламный спам: крипту, казино, рефералки, объявления с wa.me-ссылками. Чат небольшой, Юрий Солар как администратор заглядывает туда редко — бот должен справляться сам.
17 июня бот снёс пост мотошколы и каталог байков. Оба сообщения были по теме чата, без ссылок на внешние ресурсы — но попали под правило «любое коммерческое содержание без явного разрешения удаляем». Фикс был оперативным: добавили исключения для образовательных постов и каталогов без контактов продавца.
28 июня — новый инцидент. Участник с user_id 269123663 написал: «Всем привет. Где можно арендовать авто на 1 день, на завтра?» Бот удалил сообщение (msg 213424). Участник переспросил похожими словами. Бот удалил снова (msg 213434) и выдал страйк спамера.
В то же время в чате висело сообщение с wa.me/@CheapestBaliRentall — настоящее рекламное объявление с контактом, ценами и призывом написать. Бот его не тронул: по тогдашней логике правил, нужные ключевые слова не срабатывали в нужном контексте.
Итог: настоящий спам в чате, живой человек заблокирован. Классический false positive (живой вопрос удалён) и false negative (реклама пропущена) в одном инциденте. Оба явления — следствие одной и той же проблемы: бот оценивал тему, не структуру.
Юрий Солар, основатель Solar Property: «Неприятнее всего, что это уже не первый раз. Каждый раз учу бота одному: отличать своего от чужого. Опасность автоматизации не в том, что бот простаивает, — а в том, что он уверенно делает не то и работает тихо. Слишком злой фильтр не спасает чат — он его тихо выкашивает.»
Граница между вопросом участника и рекламным объявлением: как её формализовать
Разбор 50 сообщений из тематических Telegram-чатов про аренду (байки, авто, жильё) даёт чёткое разделение по структуре. Эти паттерны универсальны — они работают для любого тематического сообщества, где тема разговора участников совпадает с темой рекламы.
Вопрос участника — все три характеристики одновременно:
- Заканчивается вопросительным знаком или содержит вопросительное слово: «где», «кто», «как», «можно ли», «есть ли», «посоветуйте», «кто знает»
- Нет ссылок, нет контактов, нет цен, нет призыва к действию
- Персональный контекст: «на завтра», «на 1 день», «для себя», «в районе Семиньяк», «срочно нужно»
Рекламное объявление — хотя бы один из признаков:
- Есть ссылка или контакт: wa.me, t.me, http, @username или телефон +62 xxx
- Есть цена или прайс: «100k в день», «от 50 USD», «лучшие цены», «скидка 10%»
- Есть оффер или призыв: «пишите», «звоните», «заходите», «доступно прямо сейчас», «осталось 2 места»
Вопрос, у которого нет ни одного из рекламных признаков, не является спамом с вероятностью 97–99%. Этого достаточно для автоматики — оставшийся процент закрывается ручной проверкой при жалобах.
Важный граничный случай: сообщение, замаскированное под вопрос. «Где найти авто? У нас есть! wa.me/+62xxx» — содержит вопросительный знак, но также содержит wa.me-ссылку. Такое сообщение должно определяться как реклама. Правило: если есть хотя бы один рекламный признак — это реклама, независимо от наличия вопросительного знака. Паттерн «это вопрос» должен проверять отсутствие всех рекламных признаков, а не только наличие вопросительного знака.
Ещё один граничный случай — рекомендации от участников: «Советую попробовать Bali Car Club, у них хорошие условия» без ссылки и контакта. Это не реклама — это персональный отзыв. Такие сообщения не должны удаляться. Признак: нет ссылки, нет контакта, нет цены, но есть название конкретного места или бизнеса. Для таких случаев паттерны уровня 2 применяют принцип «разрешено всё, что явно не запрещено» — если сообщение не попало ни в один прямой паттерн рекламы, оно проходит.
Практическое правило для составления паттернов: список «признаки рекламы» должен быть максимально конкретным (конкретные ссылки, форматы телефонов, слова-офферы), а список «признаки вопроса» — достаточно широким, чтобы покрывать все варианты. Лучше пропустить 1 объявление без ссылки, чем заблокировать 5 живых вопросов.
Техническое решение: два регулярных выражения с приоритетом вопроса
В боте для «Байки на Бали» проблема решилась добавлением двух паттернов в функцию classify_obvious_bike_market(). Первый ловит вопросы участников (исключает из удаления), второй — рекламные объявления (помечает к удалению). Оба работают на одну тематику — авто и аренда.
CAR_RENTAL_QUESTION_RE = re.compile(
r'\b(арен(д|дует|дуете|дую|дуем)|снять|взять|найти|ищ[еу]|нужн[аоы])\b'
r'.{0,60}'
r'\b(авто|машин[ауы]|car|auto)\b'
r'(?=.*[?])', # обязательный вопросительный знак
re.IGNORECASE | re.DOTALL
)
CAR_RENTAL_PROMO_RE = re.compile(
r'(wa\.me|t\.me|http|@\w{4,}|\+62\d{8,}|whatsapp|цен[аы]|IDR|USD|\bот\s+\d)'
r'.*'
r'\b(авто|машин[ауы]|car|auto|аренд)',
re.IGNORECASE | re.DOTALL
)
Логика функции после правки:
def classify_obvious_bike_market(text: str) -> str | None:
if CAR_RENTAL_QUESTION_RE.search(text):
return 'QUESTION' # сосед спрашивает — пропускаем
if CAR_RENTAL_PROMO_RE.search(text):
return 'PROMO' # реклама с контактом — удаляем
return None # на усмотрение общих правил
Ключевой принцип: вопрос проверяется первым. Если сообщение прошло проверку на «это вопрос», оно выходит из функции сразу, не доходя до проверки на рекламу. Это важно, потому что иначе вопрос, содержащий ключевые слова темы, попал бы в PROMO-ветку и был бы удалён.
Этот подход легко масштабируется на другие тематики. Для каждой новой темы, где есть риск ложных срабатываний, добавляется пара TOPIC_QUESTION_RE + TOPIC_PROMO_RE с той же логикой приоритета. Функция-диспетчер проверяет темы последовательно: сначала все QUESTION-паттерны всех тем, потом все PROMO-паттерны. Это гарантирует, что ни один вопрос участника не попадёт под удаление из-за совпадения с темой другого паттерна.
Результат тестирования после деплоя:
- «Где можно арендовать авто на 1 день, на завтра?» → QUESTION → пропущено ✓
- «Сдаём авто на Бали от 100k IDR! wa.me/@CheapestBaliRentall» → PROMO → удалено ✓
- «Кто знает хорошие прокаты машин в районе Семиньяк?» → QUESTION → пропущено ✓
Два ложных страйка с user_id 269123663 сняты вручную. Сообщения msg 213424 и msg 213434 восстановлены. Настоящий спам с wa.me/@CheapestBaliRentall (msg 213430) остался заблокированным.
Архитектура «умного» модератора: уровни контекстной классификации
Инцидент с «Байками на Бали» — иллюстрация того, как автомодератор эволюционирует с ростом сообщества и сложностью спама. Понимание этих уровней помогает выбрать подходящую сложность решения для конкретного чата.
Уровень 0 — чёрный список слов. Встретил — удалил. Работает для очевидного спама: «казино», «крипта», «заработай от дивана». Ложные срабатывания редки: эти слова редко встречаются в обычном разговоре участников тематического чата. Время реализации — 2–4 часа на Python. Подходит как стартовая точка для любого сообщества.
Уровень 1 — тематические паттерны. «Байки на Бали» расширили правила до паттернов про аренду мотоциклов — и сразу получили проблему: тема рекламы совпала с темой разговора. На этом уровне ложные срабатывания неизбежны для любого тематического чата. Это точка, в которую рано или поздно упирается каждый владелец сообщества с активным модератором.
Уровень 2 — контекстная классификация. Два паттерна для одной темы: «это вопрос» и «это реклама», с приоритетом проверки вопроса. Именно сюда пришёл фикс от 28 июня. Закрывает около 90% случаев ложных срабатываний без потери точности по спаму. Для большинства тематических чатов — достаточный уровень сложности.
Уровень 3 — сигнальный анализ. Бот смотрит не на слова, а на наличие структурных сигналов: ссылка, контакт, цена, паттерн оффера. Это снижает зависимость от конкретной темы и масштабируется на новые виды спама без переписки правил под каждую тематику отдельно. Добавляет 7–8% к точности уровня 2.
Уровень 4 — ML-классификация. Дообученная языковая модель на размеченных данных из истории чата. Требует ~1 000 примеров с разметкой «спам / не спам» и отдельной инфраструктуры. Даёт точность 97–99% там, где паттерны спама постоянно меняются и адаптируются. Для большинства сообществ — избыточно по трудозатратам относительно результата.
Для типового тематического Telegram-чата достаточно уровня 2–3. Уровень 2 закрывает основные случаи ложных срабатываний, уровень 3 добавляет устойчивость при смене формулировок спама. Оставшиеся 1–3% — ручная модерация и жалобы от участников.
Паттерны ложных срабатываний по типам тематических чатов
Проблема «бот бьёт по своим» возникает не только в чатах про аренду. Понимание того, в каких типах сообществ риск выше, помогает расставить приоритеты при настройке.
Аренда (байки, авто, жильё на Бали и не только). Участник спрашивает про аренду — бот удаляет как рекламу аренды. Риск: высокий. Решение: паттерн «вопрос про аренду» с вопросительным знаком и без контактов/цен. Время на внедрение: 30–60 минут.
Медицинские и wellness-чаты. Участник спрашивает про врача или клинику — бот удаляет как рекламу медицинских услуг. Разница: «Кто знает хорошую стоматологию в Денпасаре?» vs «Лучшая стоматология на Бали! Скидка 20%! Пишите в WhatsApp». Паттерн тот же: вопрос без контакта vs оффер с контактом.
Чаты для предпринимателей и фрилансеров. Участник ищет партнёра или подрядчика через вопрос — бот удаляет как рекламу услуг. «Кто делал автоматизацию для e-commerce, посоветуйте?» — это вопрос, не реклама. Риск особенно высок в B2B-чатах, где бизнес-тематика — норма разговора.
Локальные сообщества экспатов. Участник просит рекомендацию по сервису — бот удаляет как рекламу этого сервиса. «Кто делал налоговый вычет в Индонезии, к кому обращались?» — типичный вопрос, который может попасть под фильтр «налоговые услуги».
Способ выявить группы риска в своём чате: выгрузить 50 реальных сообщений участников за последние 30 дней и посчитать, сколько из них содержат ключевые слова, по которым бот удаляет. Если больше 20% — у вас высокий риск ложных срабатываний и нужны контекстные паттерны уровня 2.
Во всех случаях решение одинаковое: не расширять чёрный список, а добавлять паттерн «это вопрос» для тем, которые совпадают с темой чата. Это требует 30–60 минут на каждую тематику, но решает проблему системно, а не затыкает дыры вручную после каждого инцидента.
Как проверить своего Telegram-модератора на ложные срабатывания
Стандартный цикл тестирования перед выкаткой в прод занимает 2–3 часа и защищает от большинства инцидентов.
Шаг 1. Тест-сет из реальных сообщений чата. Взять 200 случайных сообщений из истории за последние 30 дней. Разметить вручную: «спам» / «не спам». Занимает 30–40 минут, но даёт объективную базу. Без реальных примеров любое тестирование — иллюзия точности.
Шаг 2. Метрики качества.
- False positive rate — сколько «не спам» бот пометил как «спам». Допустимый порог: менее 3%.
- False negative rate — сколько реального спама пропустил. Допустимый порог: менее 10% (остальное ловится жалобами участников).
Шаг 3. Граничные случаи отдельно. Сообщения про тему чата, но не рекламные. Для чата про байки — вопросы про аренду, ремонт, рекомендации механиков. Именно туда падают ложные срабатывания уровня 1.
Шаг 4. Мониторинг 2 недели после запуска. Ежедневно просматривать удалённые ботом сообщения через лог-канал. Если за неделю 2 и более ложных срабатывания — правила требуют фикса.
Инструмент для логирования удалений — 15 строк кода на aiogram:
async def log_deletion(bot, msg, reason: str):
await bot.forward_message(
chat_id=LOG_CHANNEL_ID,
from_chat_id=msg.chat.id,
message_id=msg.message_id
)
await bot.send_message(
LOG_CHANNEL_ID,
f"Удалено | user: {msg.from_user.id} | причина: {reason}"
)
Без логирования инциденты накапливаются молча. К моменту, когда кто-то обиженный пишет администратору, за 2–3 месяца могло уйти 10–20 настоящих участников с незаслуженными страйками. Логирование — это не «на потом», это условие нормальной работы любого автомодератора в живом сообществе.
Когда автомодератор работает хорошо — и когда его не нужно ставить
Автоматический модератор даёт результат при определённых условиях:
Работает хорошо, когда:
- Чат с чёткой тематикой: байки, недвижимость, конкретная локация — спам отличим по структуре
- Сообщество от 500 участников — ручная модерация становится трудозатратной
- Повторяющийся паттерн спама: крипта, казино, рефералки, объявления с ценами и wa.me
- Есть технический администратор, который поправит правила при инциденте
- Включено логирование удалений — иначе бот работает в режиме чёрного ящика
Скорее навредит, когда:
- Широкая тематика: «всё про Бали», «русскоязычные в Индонезии» — граница спам/не-спам субъективная
- Чат меньше 100 активных участников — объём ручной работы небольшой, риск ложных срабатываний высок относительно пользы
- Сообщество с платным членством или репутационным продуктом — цена ошибки выше, участники менее терпимы к незаслуженному страйку
- Никто не будет смотреть логи — бот накапливает ошибки молча, и вы не узнаете об этом вовремя
Минимальный гигиенический стандарт для любого модератора: раз в неделю смотреть 10–15 последних удалений. Занимает 5 минут. Позволяет поймать проблему на стадии 2–3 инцидентов, а не 30. Раз в квартал — полный аудит: выгрузить все удаления за 3 месяца и проверить, нет ли новых паттернов ложных срабатываний из-за изменившегося поведения участников или спамеров.
Итоги: что поменялось и три шага прямо сейчас
После фикса от 28 июня в чате «Байки на Бали»:
- Вопросы участников про аренду авто проходят через фильтр без страйков
- Рекламные объявления с wa.me и ценами блокируются, как прежде
- 2 ложных страйка с user_id 269123663 сняты, участник восстановлен
- Настоящий спам с CheapestBaliRentall (msg 213430) остался заблокированным
Три шага, если у вас в чате есть автомодератор:
- Включить логирование удалений в отдельный канал. 30 минут разработки. Даёт видимость в ежедневную работу бота.
- Проверить последние 50 удалений за прошлый месяц. Если больше 3 выглядят как нормальные сообщения участников — в правилах есть проблема.
- Добавить паттерн «это вопрос» для каждой тематики, которая совпадает с темой рекламного спама в вашем чате. По 30–60 минут на тематику — это полная защита от конкретного класса ложных срабатываний.
Слишком злой фильтр не спасает сообщество — он его тихо выкашивает. Один обиженный участник, получивший незаслуженный страйк, дороже десяти пойманных спамеров. Спамеры адаптируются и меняют формулировки. Участники, которые ушли обиженными, возвращаются редко. Хорошая автоматизация сообщества — это не «максимально жёсткий фильтр», а «минимально необходимое вмешательство»: убрать явный спам и не трогать живых людей.
Если вам интересно, как устроена автоматизация Telegram-сообществ изнутри — реальный код, промпты, AGENTS.md для модераторов, — в клубе «Solar — внутрянка» выкладываю именно это: бери и адаптируй под свой чат. 4bos.ru/inside, от 2 500 ₽/мес.
Больше про автоматизацию операционных процессов через Telegram-ботов — в статье Telegram-бот как операционный слой бизнеса.
— Solar OS.