Почему одной метки «опасно / безопасно» недостаточно

Один и тот же запрос может одновременно относиться к нескольким категориям — например, содержать признаки и финансового мошенничества, и киберпреступления. Поэтому задача поставлена как multi-label: модель принимает 15 независимых бинарных решений на каждый текст, а не выбирает одну категорию из списка.

Это нужно для управляемой модерации: Child_exploitation требуется эскалировать на ручную проверку, а Swear_words достаточно залогировать. Бинарный вердикт такого различия не даёт.

Сами 15 выходов неоднородны, и мы разделяем их явно:

  • 11 категорий вреда — эксплуатация детей, насильственные действия, вооружение, наркотики, причинение вреда себе, дискриминация и язык ненависти, нацизм, ненасильственные и финансовые преступления, киберпреступления, порнографические материалы.
  • 4 тематических флага — мат, политика, религиозные преступления, ЛГБТ. По умолчанию выключены и включаются под конкретное внедрение.

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

Как устроена модель

Один forward-проход из четырёх стадий:

  • Многоязычный энкодер mmBERT-base (307M параметров) превращает текст в скрытые состояния. Лимит контекста — 1024 токена.
  • 15 категориальных экспертов читают состояния параллельно, каждый со своими обучаемыми query-токенами. Эксперты независимы, поэтому редкая категория не делит решение с частой. Единый батчевый forward вместо цикла по категориям даёт ускорение примерно втрое.
  • Модуль взаимодействия категорий — двухслойный трансформер, читающий все 15 представлений вместе. Он кодирует то, что метки сообщают друг о друге: контент про оружие обычно и про насилие, нацизм обычно и про дискриминацию.
  • Суммирование и сигмоида дают 15 независимых вероятностей, каждая со своим порогом.

При обучении используется асимметричная функция потерь (ASL), намеренно штрафующая пропуски сильнее ложных срабатываний, дифференцированный learning rate (backbone 3e-5, эксперты 5e-4) и EMA-усреднение весов. Пороги подбираются для каждой категории отдельно через grid search, лежат в диапазоне 0.49–0.62 и хранятся отдельно от весов — чувствительность корректируется в production без переобучения.

Лимит в 1024 токена обоснован реальным распределением длин обучающего корпуса:

ПерцентильP50P75P90P95P99P99.5
Токены~43~87~184~279~555~714

Половина текстов короче 43 токенов, но хвост растёт нелинейно. При max_length=1024 покрывается 99.78% датасета из 1 836 335 примеров; оставшиеся 0.22% длиннее лимита и все безопасные, поэтому они исключаются из обучения целиком, а не усекаются.

Сравнение с 9 открытыми решениями

Мы прогнали единый бенчмарк двух наших моделей против 9 открытых guardrail- и toxicity-моделей сторонних разработчиков. Выборка — 7 480 примеров внешнего набора, собранного специально для оценки: он не пересекается со сплитами обучающего корпуса, каждый пример размечен тремя аннотаторами (Fleiss’ κ = 0.82), баланс 50/50.

МодельBinary F1F1-micro (14)F1-weighted (14)F1-macro (14)
HiveTrace Multilabel (наша)0.95880.74030.79870.7026
YuFengXGuard_0.6B0.95440.71970.66250.4581
Qwen3Guard_8B0.93370.57000.66830.3952
Qwen3Guard_4B0.93270.56760.66780.3923
Qwen3Guard_0.6B0.92350.55140.64700.3746
gliner_guard_omni (наша)0.90760.71110.70060.5489
opir_multitask_multilang0.87180.28240.25640.2735
gliguard_300m0.80250.55630.52680.2395
apanc_russian_sensitive_topics0.72950.47920.49970.4149
rubert_tiny_toxicity0.54550.52540.41140.1270
unitary_multilingual_toxic0.13040.51830.35840.0927

Главный вывод: бинарной метрики недостаточно для выбора модели. У Qwen3Guard_8B binary F1 = 0.9337, но multilabel F1-macro всего 0.3952 — модель хорошо ловит «опасно / безопасно» и плохо определяет, чем именно опасно.

По binary F1 наша модель идёт вровень с ближайшим конкурентом: 0.9588 против 0.9544. Разрыв 0.0044 при n = 7 480 укладывается в выборочную погрешность, поэтому честная формулировка — «на уровне», а не «обходим». А разрыв по F1-macro (0.7026 против 0.4581) — другого порядка и распределён по всем категориям.

Отличается и характер ошибок. Семейство Qwen3Guard работает почти исключительно на precision (0.9997 при recall 0.876) — оно не поднимает ложных тревог и платит за это пропусками. Наша модель держит precision 0.9725 при recall 0.9455 — тот баланс, ради которого настраивалась асимметричная функция потерь.

Экономика инференса

Замеры сделаны на одной NVIDIA RTX 3090 для трёх бэкендов при фиксированных размерах батча.

BatchPyTorch P95TensorRT P95TensorRT, текстов/сPyTorch, $/1MTensorRT, $/1M
117.4 мс5.9 мс173.41.35280.4806
818.2 мс7.9 мс1045.10.17880.0797
1618.8 мс12.5 мс1345.10.09440.0620
6472.4 мс69.1 мс954.60.09090.0873

Оптимум — TensorRT при batch=16: лучшая задержка среди практичных размеров батча, наивысшая пропускная способность и наименьшая стоимость одновременно, компромисса между ними здесь нет. Это в 2.9 раза дешевле наивного фиксированного batch=8 на PyTorch и в 21.8 раза дешевле работы вообще без батчинга. При batch ≥ 32 бэкенды сходятся и преимущество TensorRT практически исчезает. Веса модели ни одна из этих оптимизаций не затрагивает.

Для сравнения: внешний LLM-as-judge через API — это 300–2000 мс задержки и $63–400 за миллион запросов. Собственная модель выигрывает у него на 1–2 порядка по латентности и на 3–4 порядка по стоимости, а данные при этом не покидают инфраструктуру компании.

Где система ошибается

Агрегаты скрывают неровный профиль, поэтому называем слабые места прямо. Шесть из 13 risk-категорий бенчмарка попадают в диапазон 0.73–0.96 (Drugs 0.90, LGBT 0.89, Swear_words 0.86, Self_harm 0.85, Sexual_content 0.82, Child_exploitation 0.73), остальные ниже: Weapons 0.68, Religion 0.62, Politics 0.58, Cybercrime 0.56, Hate_discrimination 0.56, Violence 0.48, Non_violent_crime 0.34.

F1 по 13 каноническим risk-категориям и производной метке Safe

Hate_discrimination с F1 0.56 — критичная категория, которой нужен отдельный дашборд recall, а не вера в агрегат. Non_violent_crime с F1 0.34 — объединённая категория бенчмарка, вобравшая финансовые преступления, поэтому часть слабости объясняется свёрткой. Если убрать производную метку Safe, macro-F1 только по 13 risk-категориям — 0.682 против 0.7026 по 14 меткам.

Есть и системные ограничения:

  • принципиально новые техники обфускации потребуют дообучения — модель устойчива к трансформациям из обучающей выборки;
  • окна длинных запросов скорятся без контекста остального документа;
  • совместное срабатывание 4+ категорий в обучающих данных встречалось редко, и поведение модели здесь менее предсказуемо.

Подстраховка одна и та же во всех случаях: пороги правятся в production мгновенно, а для критичных для вас категорий, рекомендуется human-in-the-loop эскалация в «серой зоне».

Guardrail-классификатор закрывает регуляторный и репутационный риск на объёмах, где ручная модерация уже не масштабируется, и оставляет данные внутри контура компании.

Полная методология бенчмарка, детали архитектуры и метрики доступны в техническом отчёте.