status/volatile Конкретные модели и F1-баллы (PromptGuard-2, BrowseSafe, Qwen3-30B, GPT-5/Sonnet 4.5) быстро устаревают. Ревизия раз в квартал — актуализировать цифры/модели.
Суть
Атаки семантически разнообразны — их нельзя надёжно поймать паттерн-матчингом или regex. Нужна модель, понимающая структуру (включая HTML, скрытые CSS-свойства, комментарии, alt-текст картинок) и семантику. На выходе — бинарный сигнал safe/injection, при неуверенности эскалация на более «умную» frontier-модель.
Зачем это нужно
Это «уровень 1» защиты в продакшн-пайплайнах. Бинарный сигнал нужен для мгновенной остановки пайплайна (в отличие от размытых оценок 1-5 у LLM as Judge). Заодно это аргумент против использования слишком лёгких моделей в security-задачах (ср. Agent Routing, где маленькие модели — норма для роутинга, но не для защиты).
Как работает
Метрики (почему именно F1):
- Precision — из всех, кого модель пометила «атака», сколько реально атак → борется с false positive (ложная блокировка «бесит пользователя»).
- Recall — из всех реальных атак, сколько поймано → борется с false negative (пропуск атаки).
- Они конкурируют: снижаешь порог → растёт Recall, но падает Precision. F1 — гармоническое среднее: если одна метрика просаживается, F1 падает — нельзя «спрятать» плохой Recall за хорошим Precision.
Бенчмарк моделей-детекторов:
| Модель | F1 | Комментарий |
|---|---|---|
| PromptGuard-2 (Meta, ~100M) | ~0.35 | Слишком низко для прода; паттерн-матчинг не ловит семантику |
| GPT-5 / Sonnet 4.5 (reasoning) | ~0.85 | Хорошо, но медленно — не для real-time |
| BrowseSafe (Qwen3-30B-A3B MoE) | ~0.91 | Файн-тюн под задачу; быстрая, бинарный safe/injection |
Архитектура: детектор работает параллельно основному пайплайну (не добавляя latency) — извлекает сырой HTML до начала reasoning, отдаёт бинарный сигнал. Гибридный подход: при неуверенности эскалация на frontier-модель. Альтернатива «не хочу разворачивать Qwen» — взять PromptGuard / gpt-oss-safeguard-20b для входной проверки (с поправкой на точность).
Ресурсы: модель perplexity-ai/browsesafe + датасет browsesafe-bench (Hugging Face), arXiv 2511.20597.
Эвристический детектор (слой 0, под классификатор): дешёвый regex-скан маркеров инъекций — быстрый фильтр, поверх которого в проде ставят ML-классификатор / Llama Guard:
import re
INJECTION_PATTERNS = [
r"ignore\s+(all\s+)?previous", r"disregard\s+(all\s+)?(above|previous)",
r"игнорируй\s+(все\s+)?(инструкции|выше|предыдущ)", r"system\s+prompt",
r"you\s+are\s+now", r"ты\s+теперь", r"chat[_\s-]?id", r"new\s+instructions",
r"reveal\s+(the\s+)?(system|prompt|secret|api[_\s-]?key)", r"exfiltrate",
]
_INJ_RE = re.compile("|".join(INJECTION_PATTERNS), re.IGNORECASE)
def scan_injection(text) -> list[str]: # [] = чисто; иначе список сработавших маркеров
return sorted({m.group(0).lower() for m in _INJ_RE.finditer(str(text or ""))})
⚠️ Regex — это только «гигиена»: ловит известные паттерны, но не семантически новые атаки. Поэтому поверх — файн-тюненый классификатор (см. таблицу выше). scan_injection() используется и в Guardrails (input-санитизация, output-ре-скан).
Regex-guard и его штатный обход
Базовый слой детекции в разобранной реализации — список паттернов, ловящий типовые формулировки инъекций:
KNOWN_INJECTION_PATTERNS = [
r"игнориру\w* (все|предыдущие)", r"забудь,? что ты",
r"ты (теперь|больше не)", r"без ограничени",
r"систем\w* промпт", r"систем\w* сообщени",
r"служб\w* безопасности", r"без уведомлени",
r"это приказ", r"\bcvv\b",
]
# та же атака транслитом — наивный список выше её не поймает
KNOWN_INJECTION_PATTERNS_TRANSLIT = [
r"ignoriruy\w* vse", r"bez ogranicheniy", r"pravila i ogranicheniya",
]
Второй список приведён специально: он показывает, что regex-guard обходится сменой алфавита, и это не гипотетическая уязвимость, а первое, что пробует атакующий на русскоязычном сервисе. Поэтому слой считается нулевым уровнем защиты — дёшево, мгновенно, отсекает массовый шум, но не является барьером против адресной атаки.
Практическое следствие: транслит, кодировки и ролевые формулировки обязаны входить в набор для регрессии (Over Refusal), иначе замер защиты меряет только наивные попытки.
Альтернативный взгляд: Semalith v1.4 — дело не в размере, а в калибровке
Вывод основного материала — «маленькие классификаторы проваливаются, нужна модель класса Qwen3-30B» — подтверждается в цифре и не подтверждается в диагнозе.
Цифра независимо сходится: на browsesafe-bench frontier-модели дают около 0.85 F1, а PromptGuard-2 — около 0.35. Но причина не в числе параметров. Специализированный энкодер Semalith v1.4 на 184M параметров (DeBERTa-v3-base, одна голова на 22 класса) выигрывает все 7 injection-бенчмарков у Llama-Guard-3-8B при в 44 раза меньшем размере: на HackaPrompt recall 0.995 против 0.084, на 208 доброкачественных агентных промптах FPR = 0.000 против 0.063, latency 11.6 мс против 33-кратно большей.
Что на самом деле не так с PromptGuard-2: у него recall близок к 1.0, но ложноположительных 96% на AgentHarm-benign и 98% на ToxicChat. Он помечает атакой почти всё подряд — и именно это обрушивает F1, а не неспособность «понять семантику». То есть перед нами не слабый детектор, а некалиброванный: классический over-defense (Over Refusal), только измеренный.
Практический вывод меняется: выбирать детектор нужно не по размеру и не по одному числу F1, а по паре «recall на своей атаке / FPR на своём нормальном трафике». Маленькая модель, обученная под одну ось, может обыграть большую универсальную — и наоборот: тот же Semalith проигрывает Llama-Guard-3 на общем вреде (HarmBench-contextual recall 0.181 против 0.553) и заявлен только для английского.
Почему любой F1 из таблицы завышен
Отдельная проблема — как эти числа получены. Работа по оценке классификаторов под сдвигом распределения (18 датасетов, 105 тыс. примеров, четыре семейства атак) показывает: стандартная кросс-валидация и отложенная выборка систематически переоценивают поведение на незнакомых данных. Разрыв между 5-fold CV и leave-one-dataset-out составил 8.0–16.5 процентных пункта AUC (для Llama-3.1-8B: 0.996 → 0.912), а на отдельных датасетах точность падала с 94.5% до 69.1%.
Причина: 28–44% наиболее весомых признаков оказались «ярлыками датасета», а не признаками атаки — классификатор, обученный угадывать, из какого набора пришёл пример, достигает 96.6% точности. То есть модель во многом учится распознавать источник данных, а не инъекцию.
Практическое следствие для выбора детектора: требовать оценку leave-one-dataset-out, а не CV, и дополнять её адверсариальным прогоном на своём трафике. Цифры из вендорских таблиц — верхняя граница, не ожидание.
Что решать перед выбором детектора
Развилка «дорогая 30B против дешёвой 100M» после разбора выше уже не главная — размер оказался не той осью. Практически решение сводится к двум величинам, обе измеряются на своём трафике, а не берутся из таблицы:
- Допустимый FPR на нормальном потоке. Это продуктовое ограничение: сколько легитимных запросов можно заблокировать, не сломав сервис. От него выбор зависит сильнее, чем от F1, потому что рекордный recall достигается тривиально — блокировкой всего подряд (Over Refusal).
- Цена пропущенной атаки для конкретного потока. Некритичный поток без доступа к инструментам и данным терпит слабый детектор; поток, за которым стоит необратимое действие, требует детерминированного гейта поверх любого детектора (Deterministic Veto).
Третье — не решение, а требование к поставщику: у выбранной модели должна быть оценка leave-one-dataset-out, а не только кросс-валидация, иначе заявленное качество завышено на величину, разобранную выше.
Связано с
- Prompt Injection — что именно детектируем
- Guardrails — детектор как Input-слой guardrails
- LLM as Judge — родственная идея «модель-оценщик», но там качество, здесь — бинарная безопасность
- Agent Routing — контраст: лёгкие модели ок для роутинга, не для security