Безопасность чат-ботов Just AI
Проект по разработке инструмента для автоматического анализа текстовых сообщений и выявления потенциально опасного контента среди ботов компании JustAI
Контекст проблемы
Продажа наркотиков является серьёзной проблемой в интернете. Помимо крупных нелегальных площадок (RAMP, Hydra, Blacksprut), значительный объём торговли запрещёнными веществами происходит в защищённых мессенджерах. Покупка через бота в мессенджере автоматизирует процесс и обеспечивает анонимность для обеих сторон сделки: продавец не контактирует с покупателем напрямую [1].

Действия со стороны регулятора оказались ограниченно эффективными: попытка блокировки Telegram Роскомнадзором в 2018 г. не дала результата — мобильная версия мессенджера продолжала работать без VPN [1]. В феврале 2026 года Роскомнадзор ввёл замедление Telegram на территории России, однако платформа сохраняет широкую доступность.

Для успешного обнаружения сообщений, содержащих лексику на тему наркоторговли, необходимо понимать особенности языка которым пользуются продавцы и покупатели. Чтобы уклониться от обнаружения, они используют разные методы:
  • Омонимы
    Слова, которые имеют два значения - бытовое и наркотическое. Примеры: "клад", "закладка", "книжка".
  • Сленг
    Постоянно обновляющийся сленг делает статичные списки слов со временем устаревшими.
  • Эмодзи, цифры и замены букв
    Намеренное искажение слова при добавлении эмодзи, символа, цифры или буквы из других алфавитов. Примеры: "кл💙д", "нен@ход","@DeaIler" (буква I вместе L)
  • Числовые обозначения доз и цен без контекста
    Сообщения содержат только цифры и единицы измерения без явного указания что продаётся. Например, "300 gel"
  • Одиночные буквы как запросы
    В контексте продажи запрещённых средств сообщение с единственной буквой "H" может значить определённый тип наркотиков, но без знания контекста диалога нельзя однозначно интерпретировать такое сообщение — одиночная буква встречается и в обычной переписке.
О заказчике
JustAI разрабатывает продукты в сфере разговорного AI, позволяя пользователям создавать собственные чат-боты и запускать их в работу в нужном канале (например, Telegram, ВКонтакте и др.).

Когда аудитория ботов растёт, растут и риски: среди тысяч сообщений могут появляться чаты с нелегальным контентом.
Отслеживание подозрительных чатов вручную, по словарю паттернов, требует значительных ресурсов. Поэтому JustAI предложил разработать совместный проект, который поможет автоматизировать обнаружение нелегального контента, чтобы высвободить ресурсы своей команды для других задач
Цели проекта
  • Исследовать различные подходы к обнаружению нелегального контента (тематика: продажа наркотических средств) в текстовых диалогах на русском языке.
  • Разработать и сравнить прототипы моделей модерации
  • Подготовить комплексный отчет с выводами и рекомендациями для внедрения наиболее эффективного решения.
Обзор подходов
Для выбора оптимального подхода к решению задачи мы провели обзор существующих исследований в области автоматического обнаружения нелегального контента. Ниже представлены основные методы, применявшиеся в схожих задачах, и их ключевые характеристики. Среди них базовый словарный метод, самый прогрессивный метод - LLM и несколько подходов в рамках ML.
  • Поиск по словарю + Регулярные выражения (regex)
    Поиск ключевых слов из ранее составленного словаря в сообщениях с применением регулярных выражений
  • TF-IDF + логистическая регрессия

    Метод частотного анализа текста + классификатор. Из минусов: часто не понимает семантику и контекст [4].
  • Word-based ML: Word2Vec, CantReader, Zhu et al
    Анализируют отдельные слова, но не понимают контекст предложения [5].
  • BERT, RoBERTa, ruBERT
    Трансформерные языковые модели, которые понимают контекст всего предложения, но только ruBERT - русскоязычная версия. Ограничение: требуют большого объёма размеченных данных и переобучения под конкретный домен [7].
  • JEDIS
    Cпециализированный фреймворк на основе BERT для обнаружения наркотического жаргона [6]. JEDIS обучен на англоязычных данных.
  • LLM prompting
    Готовая языковая модель классифицирует текст через инструкцию в промпте, без дополнительного обучения [6].
Изучение данных
Just AI предоставили тестовую выборку логов чат-ботов для первичного анализа и изучения данных.

Данные тестовой выборки:
  • 10 097 строк.
  • 64 колонки (примеры: 'account_id', 'project_short_name', 'channel_type', 'response_data', 'data', 'system_data', 'operator_id').
  • При проверке составных полей, содержащих информацию в формате json, обнаружили, что там дублируются уже существующие поля.
  • Использовали fasttext-langdetect для детекции языков в датасете.

После первичного анализа и описания выборки, мы запросили у JustAI основной датасет, в котором:
  1. только те записи, где в полях есть question и text_answer.
  2. в поле ChannelType только тип: chatwidget, telegram, vk. Остальные каналы (chat2desk, marusia, i_digital и chat2desk) используются крупными корпоративными заказчиками, и компания уверена в отсутствии нелегальных сообщений в них.
Основной датасет
- логи взаимодействий пользователей с чат-ботами. Данные собраны из настоящих диалогов, но специально скомпилированы и размечены для задач данного проекта. Данные были анонимизированы компанией Just AI перед передачей.
Каждая строка датасета соответствует одному диалоговому ходу с полями question и answer, сгруппированными по session_id. У одного аккаунта может быть много session_id, то есть структура вложенная: account_id → session_id → message.

Разметка выполнялась комбинированным образом.

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


Пример сообщений legal и illegal класса
Описание основного датасета
  • Строки: 7 816 579.
  • Колонки (10): 'timestamp', 'account_id', 'project_short_name', 'channel_type', 'question', 'nlp_class', 'answer', 'session_id', 'from_illegal_account', 'message_label'.
  • Дисбаланс классов (колонка 'message_label'): legal 7816116 (99.99%) / illegal 463 (0.01%).
  • Пропуски в колонках: 'nlp_class' - 99.98%, 'answer' - 41.53%, 'account_id' - 3.12%.
  • Язык: русский, английский, транслит с английского, эмодзи.

Решение проблемы с дисбалансом: для обучения и оценки моделей был создан сбалансированный поддатасет из 1392 сообщений с соотношением illegal:legal примерно 1:2, разделённый на train (748), val (336) и test (305).
Как мы выбирали метод
Словарный метод
Несмотря на то что словарный метод является базовым, он не требует больших ресурсов и работает быстро. Результаты метода могут быть отправной точкой для сравнения с другими подходами.
Различные ML подходы
  • Недостаток размеченных данных (463 illegal сообщения) и ресурсов для обучения.
  • Большинство ML-моделей обучены на английском.
  • Наша задача шире стандартной классификации.
LLM prompting
  • Не требует обучения.
  • Быстрее в разработке - можно провести больше итераций по улучшению промпта.
  • Понимает контекст и текст с разными символами без дополнительной настройки.
  • Современный подход.
Метод I: Словарный подход
Составление словаря
На основании изучения подходов NLP был сделан вывод о необходимости словаря illegal words. Так как не существует крупных датасетов, которые в достаточной мере охватывают русскую лексику незаконной торговли наркотиками, мы сами составили словарь, который содержит 840 слов. В основе его лежит датасет JustAI + источники словаря. Список английских терминов добавлен из статьи "Covering Cracks in Content Moderation: Delexicalized Distant Supervision for Illicit Drug Jargon Detection" [6]. Мы кратко описали значения каждого термина. Также был написан Python-скрипт, отделяющий термин от синонима по запятой и синонимичные термины от их значения по длинному тире, а также выполняющий очистку форматирования.
Это метод решения задачи бинарной классификации, также известен как правило-ориентированный. Его суть заключается во флагировании незаконного контента, основываясь на словаре.
Мы использовали DuckDB и pymorphy3, чтобы найти illegal message.
Naive version - поиск подстроки в тексте без учёта границ слов, найдёт "мет" в "метро". Smart version - поиск с границами слов через regex \b. Не находит "мет" в "метод", но находит "мет" как отдельное слово.
(иллюстрация регулярных выражений + добавить отчёт naive version)




Naive метод
Smart метод
Причины результатов:
  • Латиница и аббревиатуры "a-P**", "H", "G"
    Словарь ищет русские термины, а названия веществ написаны латиницей или сокращены до одной буквы. Словарь их просто не знает.
  • Команды бота "/newNode_5; А****-П**"
    Текст начинается со служебной команды, и словарь не распознаёт термин внутри неё.
  • Контекст без явных слов — "Баланс 0 g**" + ссылка на @G*******
    Здесь нет наркотических терминов вообще, но это явно нелегальный бот.
  • Ложные срабатывания на словах: номер, цифра
    Слова популярны в других, легальных контекстах
Метод II: LLM модели
Этапы работы
Разработка основного скрипта
Проработка скрипта, Error Analysis, разработка промптов.
Выбор лучшей модели
Тестирование нескольких LLM моделей (instruct и create) с асинхронной обработкой.
Получение ICL baseline
Тестирование стратегий отбора примеров для In-Context Learning на лучшей модели.
Усовершенствование ICL baseline
Пайплайн с подбором гиперпараметра количества примеров.
ICL + embedding
Добавление семантических эмбеддингов.
Разработка основного скрипта
Pipeline организован как линейная последовательность этапов: (i) построение доменного лексикона; (ii) подготовка входных данных модели из raw корпуса; (iii) сборка промпта; (iv) ограниченный вывод LLM; (v) оценка по эталонным меткам. Все этапы используют единую детерминированную конфигурацию, что позволяет точно воспроизвести прогон и возобновить его после прерывания.
Словарь нелегальных терминов включается в промпт — модель использует его как опорный список при классификации сообщений. Все слова в словаре уже приведены к начальной форме и нижнему регистру.
Результаты находятся в JSON.

Разработка промптов
Первые варианты промптов были написаны с помощью нейросетей. В запросе мы указали основные особенности данных: многозначность слов, вариативность написания, использование эвфемизмов и эмоджи для обозначения наркотиков, возможность употребления интересующей нас лексики в ироничном ключе. Опробовали 3 варианта промптов: короткий без словаря (prompt_a), подробный с максимальным описанием деталей и полным словарем (prompt_b), а также промпт, балансирующий между краткостью и обстоятельным описанием — в него был включен вариант словаря, содержащий только слова категории drugs (prompt_c). Последние 2 промпта показали macro F1-score 0.85.

После этих экспериментов были проанализированы ошибки классификации модели на train. Удалось выяснить, что чаще всего модель ошибается в следующих моментах:
1. Не распознает добавление лишних символов в слове.
2. Пропускает высказывания «с двойным дном». (Главное не забывать: счастье — это когда ты нашёл, а тебя нет!)
3. Не обращает внимание на подозрительные аббревиатуры, написанные латиницей.

В результате, мы дополнили инструкцию в новом промпте, prompt_d. Удалось достичь F1-score 0.91.
Финальный prompt_d состоит из детальных правил, определяющих:
  • a) положительный класс через несколько явных условий (прямые упоминания, сленг и эвфемизмы, транслитерация, контекст действия и сигналы эмодзи) + триггеры положительного класса: сущности наркоторговли, обфусцированные названия каналов и ботов, подозрительные сокращения и отдельные латинские символы, ссылки на криптовалюту и фразы с двойным смыслом,
  • b) отрицательный класс (омонимы в бытовом употреблении, медицинский контекст без злоупотребления, ирония, нерелевантный чат),
  • c) явный приоритет решения — контекст важнее отдельных токенов.
  • d) словарь в полном размере как опорный список слов.
Тестирование скрипта на разных LLM
Одновременно с разработкой промптов, мы протестировали различные LLM на задаче бинарной классификации, используя prompt_b и prompt_с. LLM были развёрнуты на сервере с видеокартой Nvidia RTX 5090 c 32 ГБ видеопамяти. Instruct модель сразу даёт ответ на основе инструкции, а reasoning модель сначала "думает вслух", то есть строит цепочку рассуждений перед финальным ответом, что занимает больше времени и токенов, но потенциально даёт более точный результат.
Мы исследовали следующие модели:
  • Qwen3.5-9B (использованы instruct и reasoning конфигурации);
  • Gemma-4-E4B (использованы instruct и reasoning конфигурации);
  • YandexGPT-5-Lite-8B-instruct;
  • Ministral-3-8B-Instruct-2512;
  • Ministral-3-8B-Reasoning-2512.
Работа над сравнением моделей
Разные модели требовали разных параметров и версий кода, при запуске Qwen в reasoning конфигурации часть ответов не удалось распарсить, модель возвращала некорректный JSON или обрезанный ответ из-за лимита токенов. Также, модели по-разному форматировали ответы, например, Gemma оборачивала JSON в markdown-блоки.
Мы также тестировали разные параметры LLM, настраивая количество максимальных токенов и количество повторных попыток при ошибке запроса.
Лучший результат среди instruct моделей показал YandexGPT (F1 illegal=0.663, Macro F1=0.765) благодаря более высокому Recall (0.553). Reasoning модели в целом не превзошли instruct — исключение составил Qwen reasoning (F1=0.667).
Лучшие результаты instruct и reasoning моделей, prompt_b и prompt_c
Главные выводы:
  • YandexGPT instruct — лучший по Recall (0.7926) и Macro F1 (0.7836).
  • Reasoning модели не превзошли instruct.
  • LLM метод лучше keyword baseline (0.65+).
YandexGPT-5-Lite-8B-instruct с новым prompt_d на тестовой выборке.
In-Context-Learning
Модели даётся описание задачи, набор размеченных примеров и запрос. Она предсказывает ответ, опираясь на конкатенированный контекст. Поскольку ICL крайне чувствителен к выбору примеров, их подбор является ключевым проектным рычагом: баланс между релевантностью, охватом классов и длиной промпта напрямую влияет на качество и стоимость.
В данном проекте, каждый промпт сочетает описание задачи, блок few-shot с размеченными примерами из обучающего набора и необязательный доменный словарь слэнг-терминов. Для изучения влияния выбора примеров мы сравниваем две стратегии выборки (случайная и сбалансированная 1:1 по классам), со словарём и без него.
Baseline ICL
Модель: YandexGPT-5-Lite-8B-instruct
Промпт: prompt_d (со словарём и без)
Выборка примеров: t = 10
Стратегии отбора примеров:
  • Random — примеры отбираются случайным образом, без балансировки классов legal и illegal
  • Balanced — улучшение случайной выборки, соотношение legal : illegal = 1:1
  • Финальные тесты на val
🏆Ключевой результат на сокращённом словаре DRUG_TERMS_SHORT (104 термина):
Лучший вариант по f1_macro prompt_d_balanced_few_shot_ with_dict
f1_macro=0.6396
🏆Ключевой результат на полном словаре DRUG_TERMS (800 терминов):
Лучший вариант по f1_macro prompt_d_balanced_few_shot_with_dict
f1_macro=0.6398
Результаты на DRUG_TERMS (полный словарь)
Результаты на DRUG_TERMS_SHORT (сокращённый словарь)
Усовершенствование ICL baseline
Добавили гиперпараметр:
  • Выборка примеров t : перебирается из массива[2, 4, 8, 16, 32])
🏆 Лучший вариант prompt_d_balanced_few_shot_with_dict_2exmpls f1_macro=0.8942
Модель без словаря работает лучше, чем с коротким словарем (SHORT_DRUG_TERMS), следовательно отказываемся от его использования.
Полная таблица результатов

Версия

Accuracy

Precision

Recall

F1 Binary

F1 Macro

prompt_d_random_wo_dict_2_examples

0,875

0,898

0,797

0,844

0,87

prompt_d_random_wo_dict_4_examples

0,741

0,667

0,783

0,72

0,74

prompt_d_random_wo_dict_8_examples

0,571

0,498

0,797

0,613

0,567

prompt_d_random_wo_dict_16_examples

0,509

0,456

0,79

0,578

0,495

prompt_d_random_wo_dict_32_examples

0,431

0,413

0,797

0,544

0,395

prompt_d_balanced_wo_dict_2_examples

0,887

0,92

0,804

0,858

0,882

prompt_d_balanced_wo_dict_4_examples

0,792

0,736

0,797

0,765

0,789

prompt_d_balanced_wo_dict_8_examples

0,64

0,554

0,79

0,651

0,64

prompt_d_balanced_wo_dict_16_examples

0,533

0,471

0,783

0,588

0,524

prompt_d_balanced_wo_dict_32_examples

0,482

0,44

0,797

0,567

0,461

prompt_d_random_with_dict_2_examples

0,884

0,9

0,818

0,857

0,88

prompt_d_random_with_dict_4_examples

0,771

0,712

0,776

0,743

0,768

prompt_d_random_with_dict_8_examples

0,628

0,543

0,79

0,644

0,627

prompt_d_random_with_dict_16_examples

0,518

0,461

0,776

0,578

0,508

prompt_d_random_with_dict_32_examples

0,455

0,424

0,776

0,548

0,431

prompt_d_balanced_with_dict_2_examples

0,899

0,943

0,811

0,872

0,894

prompt_d_balanced_with_dict_4_examples

0,836

0,819

0,79

0,804

0,832

prompt_d_balanced_with_dict_8_examples

0,664

0,578

0,776

0,663

0,664

prompt_d_balanced_with_dict_16_examples

0,58

0,505

0,755

0,605

0,579

prompt_d_balanced_with_dict_32_examples

0,5

0,449

0,776

0,569

0,487

ICL + embedding
Для подачи примеров в промпт мы сначала использовали случайный отбор — рандомный и сбалансированный (поровну legal и illegal). Чтобы улучшить качество классификации, мы перешли к семантическому отбору: примеры выбираются не случайно, а на основе смысловой близости к классифицируемому сообщению - модель Qwen3-8b получает наиболее релевантные примеры и точнее принимает решение.

Стратегии, которые мы разрабатываем:
  • Топ-N по семантике с балансировкой по классам
Выбирает N/2 наиболее похожих legal и N/2 наиболее похожих illegal примеров из обучающей выборки на основе косинусного сходства* эмбеддингов. Гарантирует представление обоих классов в промпте, но некоторые примеры могут быть менее релевантны чем при обычном топ-N отборе.

*математическая мера похожести двух векторов, измеряет угол между ними.

  • Балансировка по классам + диверсификация
Выбирает N/2 legal и N/2 illegal примеров которые одновременно похожи на тестовое сообщение и разнообразны между собой, чтобы избежать дублирующиеся примеры. На каждом шаге выбирается пример с наилучшим балансом между похожестью на тест и непохожестью на уже выбранные примеры:
score = λ × сходство с тестом − (1−λ) × сходство с уже выбранными
Параметр λ=0.7 балансирует релевантность и разнообразие.
Результаты топ-N по семантике с балансировкой по классам
Результаты тестов по стратегии 1 (Топ-N по семантике с балансировкой по классам)
Команда проекта
  • Валерия Моисеева
    Куратор проекта
  • Ильяс Асланов
    Куратор проекта
  • Екатерина Мамочкина
    Участник проекта
    Студентка программы ДПО ПАНДАН 2025-2026 года
  • Виктория Одношивкина
    Участник проекта
    Студентка программы ДПО ПАНДАН 2025-2026 года
  • Татьяна Хахалева
    Участник проекта
    Студентка программы ДПО ПАНДАН 2025-2026 года
Made on
Tilda