Хороший RAG отвечает не всегда

Корпоративный помощник часто выглядит уверенно даже тогда, когда поиск вернул только соседнюю тему, устаревший регламент или половину нужного условия. Фраза в системном промпте «если не знаешь — скажи, что не знаешь» полезна, но это не архитектура контроля.

Исследование Google о достаточности контекста разделяет две причины ошибки: нужных доказательств нет среди найденных документов или модель не смогла правильно использовать достаточный контекст. Для бизнеса это разные инциденты и разные способы исправления.

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

Три исхода вместо двух

Обычный чат знает два состояния: ответ или ошибка. Рабочему RAG нужны минимум три:

1. **Ответить.** Доказательств достаточно, источники допустимы, а ключевые утверждения можно связать с конкретными фрагментами.
2. **Уточнить.** Вопрос неоднозначен: неизвестны подразделение, версия договора, дата, клиент или тип операции.
3. **Передать человеку.** Доказательства отсутствуют, противоречат друг другу, устарели или цена ошибки выше допустимого порога.

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

Почему similarity score недостаточно

Оценка близости в векторной базе отвечает на узкий вопрос: похож ли фрагмент на запрос в пространстве embedding-модели. Она не доказывает, что:

  • документ разрешён этому пользователю;
  • он действует на нужную дату;
  • найден полный набор условий;
  • источник является нормативным, а не обсуждением;
  • два документа не противоречат друг другу;
  • ответ можно вывести только из найденных фактов.

Порог вида `score > 0,78` удобен, но его нельзя переносить между embedding-моделями, коллекциями и типами вопросов. Он также не различает один сильный источник и пять почти одинаковых копий слабого текста.

Шлюз достаточности доказательств

Практичная схема ставит между retrieval и генерацией отдельный answerability gate. Он получает вопрос, найденные фрагменты и метаданные, но ещё не формирует красивый ответ.

Шаг 1. Детерминированные правила

Сначала проверяются условия, которые не стоит отдавать LLM:

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

Например, вопрос о возврате товара может требовать одновременно актуальные правила продаж, категорию товара и дату покупки. Один релевантный абзац без даты не делает пакет доказательств достаточным.

Шаг 2. Оценка пакета доказательств

Затем отдельный классификатор или LLM с жёсткой структурированной схемой оценивает не ответ, а доказательства:

  • `sufficient` — можно ответить;
  • `needs_clarification` — не хватает параметра запроса;
  • `conflicting` — источники расходятся;
  • `insufficient` — подтверждения нет;
  • `restricted` — источник найден, но недоступен пользователю.

Вместе с классом полезно возвращать список недостающих предпосылок и идентификаторы фрагментов. Свободное объяснение без структуры трудно проверять и использовать в маршрутизации.

Шаг 3. Генерация только после допуска

Генератор получает контекст лишь после решения шлюза. Он обязан создавать утверждения со ссылками на evidence ID. После генерации отдельная проверка сопоставляет ключевые утверждения с найденными фрагментами.

Документация LangSmith предлагает разделять оценку RAG на четыре части: корректность ответа, релевантность ответа вопросу, groundedness относительно документов и качество retrieval. Для рабочего шлюза к ним добавляется пятая: была ли сама задача ответима на основе допустимого пакета доказательств.

Порог выбирают по цене ошибки

У шлюза нет универсального значения уверенности. Порог зависит от процесса.

Для навигации по внутреннему порталу можно принять больше ответов и мягко показать предупреждение. Для расчёта выплаты, юридического условия или изменения записи в ERP лучше чаще передавать запрос человеку.

Нужны две связанные метрики:

  • **coverage** — доля запросов, на которые система отвечает автоматически;
  • **selective risk** — доля ошибок среди тех запросов, которые она решила принять.

Если поднять порог, coverage снизится, а качество принятых ответов обычно вырастет. Руководителю нужен не максимальный процент автоматизации, а точка, где стоимость ручной очереди ниже ожидаемого ущерба от неверных ответов.

Пример модельного расчёта. За месяц приходит 10 000 запросов. При покрытии 80% система ошибается в 3% принятых случаев — это 240 ошибок. После ужесточения шлюза покрытие падает до 55%, а риск — до 0,7%: около 39 ошибок и 4 500 ручных или уточняющих маршрутов. Выбор зависит от стоимости одной ошибки и обработки одного исключения; сами проценты нужно получить на собственном наборе данных.

Как собрать тестовый набор

Набор только из вопросов с готовыми ответами не проверит воздержание. Минимум треть примеров стоит посвятить ситуациям, где правильное действие — не отвечать.

Добавьте пять групп:

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

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

Проверяйте retrieval и generation отдельно. Иначе система может получить хороший итоговый балл случайно: слабый поиск компенсируется знаниями модели, а правильный поиск портится генератором.

Не доверяйте одному судье

LLM-as-judge полезен для groundedness и смысловой корректности, но не должен быть единственным предохранителем. Он тоже может ошибиться, особенно если оценивает ответ моделью того же семейства.

Сочетайте:

  • детерминированные правила по метаданным и доступу;
  • эталонные ответы для критических сценариев;
  • проверку наличия обязательных evidence ID;
  • LLM-судью для смысловых сравнений;
  • ручную разметку случайной выборки;
  • отдельный набор сложных отрицательных примеров.

Microsoft Foundry описывает groundedness как соответствие ответа предоставленному контексту и использует пороговый pass/fail. Это полезная проверка после генерации, но она не отвечает на вопрос, был ли контекст достаточным и допустимым до начала ответа.

Что показать пользователю

Воздержание не должно выглядеть как техническая ошибка. Хороший интерфейс сообщает:

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

Не показывайте внутренний similarity score как процент уверенности: пользователь легко примет его за вероятность правильного ответа. Лучше использовать понятные статусы: «не найдена действующая версия», «нужна дата договора», «источники противоречат».

Минимальный пилот за две недели

Выберите один процесс и 100–200 реальных вопросов. Разметьте достаточность доказательств и ожидаемый маршрут. Затем:

1. добавьте детерминированные проверки доступа, версии и обязательных источников;
2. реализуйте структурированный answerability gate;
3. разрешите генерацию только для класса `sufficient`;
4. измерьте coverage и selective risk;
5. разберите все ложные допуски отдельно от лишних отказов;
6. установите порог по стоимости ошибки;
7. запустите неделю в теневом режиме рядом с сотрудником.

Цель пилота — не научить чат чаще говорить «не знаю». Цель — сделать решение отвечать или передавать запрос наблюдаемым, воспроизводимым и экономически управляемым.