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

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

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

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

Эвристика неэффективна

Начнём с главного вывода: эвристические алгоритмы неэффективны. Регулярные выражения и keyword-фильтры дают слишком много ложных срабатываний (false positive) и легко обходятся, поэтому мы сразу сделали ставку на LLM.

Это произошло несколько лет назад, когда выбор открытых языковых моделей был невелик — по-настоящему доступной и эффективной была разве что LLaMA. Мы провели серию экспериментов, последовательно улучшая качество фильтрации. Как тестовую базу использовали реальные запросы пользователей — собрали обезличенный набор данных из тысяч органических запросов, которые люди вводили в наших сервисах. После нескольких итераций правок мы разработали универсальную систему инструкций для языковой модели. Этот промпт выполнял несколько ключевых функций:

  1. Чётко определял ограниченный набор категорий запрещенного контента, например, насилие или криминал;

  2. Описывал пограничные случаи и правила их обработки;

  3. Учитывал контекст и семантику запросов, а не просто реагировал на триггерные слова;

  4. Содержал примеры корректных модерационных решений (few-shot).

До применения few-shot на тестовых данных
До применения few-shot на тестовых данных

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

После применения few-shot — стало меньше ложных срабатываний фильтра
После применения few-shot — стало меньше ложных срабатываний фильтра

Ограниченная LLaMA

Хотя LLaMA 7B и казалась удачным выбором, её способность анализировать контекст оказалась ограниченной. Типичные проблемы:

  • Зависимость от контекста 
    размытые границы — один и тот же текст может быть как нейтральным, так и провокационным 

  • Субъективность LLM
    сегодня запрос допустимый, а в следующую проверку система его блокирует

  • Ложные метафоры
    например, «взорвать мозг красивой картинкой» может попасть под фильтр насилия

  • Пуританская этика
    нейтральные запросы с намёками на романтику блокируются как эротические

  • Сложные контексты
    запросы в духе «нарисуй сцену из фильма Х» могут содержать NSFW-элементы, но не всегда должны блокироваться

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

Новые модели, новые возможности

С повсеместным внедрением structured output мы, конечно же, применили его в фильтре. Это не дало значительного прироста качества, зато повысило стабильность работы системы, что не могло не радовать. Мы чётко задавали ожидаемую структуру ответа, и LLM бесперебойно следовала этим правилам. Благодаря схемам данных стало проще добавлять новые фичи — например, фильтр начал возвращать категорию пользовательских запросов, список которых мы заранее декларировали в JSON-схеме.

Мы продолжили эксперименты с различными моделями, среди них особенно выделились:

  1. Qwen30B показал впечатляющие результаты в задачах контент-фильтрации с хорошим балансом точности и производительности.

  2. Сюрпризом стала GPT-4o mini — модель отлично справлялась с нашей задачей.

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

Пример валидации с использованием structured output из справочника OpenAI:

from enum import Enum
from typing import Optional
from openai import OpenAI
from pydantic import BaseModel

# Initialize client with custom base URL and API token
client = OpenAI(
    base_url="",  # Replace with your actual base URL
    api_key=""  # Replace with your actual API token
)

class Category(str, Enum):
    VIOLENCE = "violence"
    ILLEGAL_ACTIVITIES = "illegal_activities"
    DRUGS = "drug_abuse"
    EXTREMISM = "extremism"

class ContentCompliance(BaseModel):
    is_violating: bool
    category: Optional[Category]
    explanation_if_violating: Optional[str]

response = client.responses.parse(
    model="gpt-4o-mini",
    input=[
        {
            "role": "system",
            "content": "Determine if the user input violates specific guidelines and explain if they do.",
        },
        {"role": "user", "content": "User Request"},
    ],
    text_format=ContentCompliance,
)

compliance = response.output_parsed
print(compliance)

Умнее, быстрее и экономичнее

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

Так, за последние четыре дня новый тестовый фильтр небезопасного контента обработал около 10 тыс. запросов, отклонил почти 2 тыс. — ошибки составили всего 8%.

Наша цель — снизить ложные срабатывания до 2-3%, сохранив быструю скорость работы и не повысив затраты. 

Что продолжим делать:

  • Собирать отзывы, чтобы доучивать промпт на основе жалоб на блокировки;

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

  • Добавим больше контекстных правил в промпт;

  • Введём whitelist для безопасных, но подозрительных слов.

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


Над материалом работали:

текст — Миша Мартьянов

редактура — Игорь Решетников 

иллюстрации — Юля Ефимова


Это блог red_mad_robot. Мы запускаем цифровые бизнесы и помогаем компаниям внедрять AI. Здесь наша команда разработки на собственных кейсах рассказывает о том, что происходит с AI сегодня, а стратегические аналитики подсказывают, что будет завтра. Мы бы подписались.

Наш Telegram-канал (там всё другое, а ещё есть анонсы мероприятий): t.me/redmadnews

Комментарии (0)