Хороший 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. запустите неделю в теневом режиме рядом с сотрудником.
Цель пилота — не научить чат чаще говорить «не знаю». Цель — сделать решение отвечать или передавать запрос наблюдаемым, воспроизводимым и экономически управляемым.
