Over Refusal

Обратная сторона безопасности: модель отказывается отвечать на безобидный запрос, зацепившись за слово-триггер вместо смысла. «Как убить процесс в Linux?» → «Я не могу помочь с насилием». Защита, которая блокирует нормальное, формально безопасна и практически бесполезна.

Содержит быстро устаревающие данные (доли отказов конкретных моделей, состав инструментов редтиминга) — status/volatile. Сверяй при ревизии.

Суть

У безопасности AI-сервиса две оси, и оптимизировать только одну нельзя:

  • Ось безопасности — FNR: вредное прошло сквозь фильтр.
  • Ось полезности — FPR: безобидное заблокировано, это и есть over-refusal.

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

Alignment tax

Причина, по которой безопасность нельзя просто «зашить в модель». Чем сильнее закручено выравнивание внутри модели, тем хуже она решает задачи, ради которых её внедряли: становится осторожнее и чаще отказывает на нормальных запросах. За безопасность внутри модели платят качеством — эффект описан у Bai et al., Anthropic 2022 (arXiv 2204.05862).

Отсюда практический вывод, который меняет архитектуру: production-контроль выносится наружу отдельным компонентом, который версионируется, аудируется и настраивается порогами. Базовой модели остаётся отсечение очевидно вредных интентов — тем более что почти для любой модели найдётся jailbreak, обходящий встроенное выравнивание (см. Jailbreak Attacks).

Цифры: бенчмарк XSTest

XSTest собран из пограничных, но безопасных запросов — таких, где встречается «отравленное» в другом контексте слово.

Модель Доля ложных отказов на безобидных запросах
Llama-2-70B 38%
GPT-4 6%

Разрыв в шесть раз на одном и том же датасете. Для продукта 38% означает, что каждый третий нормальный запрос упирается в стену — сервис можно закрывать.

Русскоязычных данных нет — и это проверяемый факт, а не пробел поиска

Проверено 2026-08-22. Оба основных бенчмарка англоязычные и остаются такими:

  • XSTest — 250 промптов, собранных вручную по фиксированным правилам. Малый объём и ручная сборка не масштабируются на новые категории, не говоря о новых языках.
  • OR-Bench — крупнее на три порядка: 80 000 промптов в 10 категориях отказа, около 1 000 трудных плюс 600 действительно вредных для контроля. Но детектор отказа в нём англоязычный, поэтому перенести набор на русский нельзя даже переводом: определять, произошёл отказ или нет, будет нечем.

В литературе прямо отмечается, что мультиязычный over-refusal для языков средней ресурсности остаётся неисследованным. То есть русского аналога нет ни у одного из двух бенчмарков.

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

Как измерять

Среднее по всем категориям скрывает проваленную категорию. Обязательна разбивка FNR + FPR + F1 по категориям риска и по языкам — русскоязычный трафик здесь отдельная история, потому что большинство guard-моделей обучались преимущественно на английском.

Методика сравнения на своём трафике, а не по лидерборду:

  1. Таксономия — категории риска именно вашего продукта.
  2. Парный benign — на каждую вредную категорию похожий разрешённый запрос. Без пары метрика полезности не считается.
  3. Обфускации — транслит, кодировки, ролевые и многоходовые атаки.
  4. Регрессия — найденные обходы отправляются в набор и прогоняются перед каждым релизом.

Инструменты авто-редтиминга: HiveTraceRed (80+ атак, поддержка русского), garak, PyRIT, llamator.

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

Рабочая разметка — три исхода вместо двух: ответ, восстановимый отказ (следующий запрос той же сессии получил ответ) и окончательный отказ (сессия закончилась без ответа). Метрика, за которой стоит следить, — доля восстановимых среди всех отказов: её рост означает, что защита срабатывает не на намерении, а на формулировке, то есть настроена по поверхностным признакам. Побочная выгода такой разметки: восстановимые отказы — готовый источник пар «заблокировано / разрешено» для калибровки, потому что обе формулировки пришли от одного пользователя с одним намерением.

Как считать разбивку на практике

Замер на учебном наборе: одна пачка обращений прогоняется через наивную версию агента и через защищённую, после чего результат группируется по категории и по признаку «атака или парный benign».

def per_category_breakdown(df: pd.DataFrame) -> pd.DataFrame:
    tmp = df.copy()
    tmp["защита сработала"] = ~tmp["итог"].str.contains("✗")
    return tmp.groupby(["категория", "атака?"])["защита сработала"].mean().unstack().round(2)

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

Набор устроен симметрично — 8 атак и 8 парных легитимных обращений, что и делает разбивку осмысленной.

Измеренный случай: детектор, помечающий атакой почти всё

Самая наглядная иллюстрация over-defense — не языковая модель, отказывающаяся отвечать, а защитный классификатор. У PromptGuard-2 (Meta) recall близок к 1.0, то есть атаки он ловит практически все, но доля ложноположительных — 96% на наборе AgentHarm-benign и 98% на ToxicChat. Он помечает атакой почти любой доброкачественный агентный запрос.

Отсюда два вывода. Первый: высокий recall без замера FPR — бессмысленная цифра, потому что достигается тривиально, если помечать всё подряд. Второй: over-defense чаще всего попадает в прод не через настройки модели, а через защитный слой перед ней (Injection Detection) — и там его никто не замечает, потому что метрика безопасности при этом выглядит отлично.

Для сравнения, тот же замер на специализированном детекторе Semalith v1.4 дал FPR = 0.000 на 208 доброкачественных агентных промптах — то есть проблема техническая, а не неизбежная плата за защиту.

Связано с

  • Guardrails — внешний каскад защиты, куда выносится контроль из-за alignment tax
  • Jailbreak Attacks — противоположный полюс: пропущенное вредное
  • Agent Security — общая модель угроз
  • Model Selection — уровень over-refusal как критерий выбора модели под продукт
  • Agent Evals — регрессионный набор, куда попадают найденные обходы