Если в компании появился ИИ‑помощник, чат‑бот или поиск по внутренней базе знаний, следующий логичный шаг – убедиться, что он работает надёжно. LLM часто выдают ответы уверенно, но это не гарантия точности: ошибка может возникнуть на любом этапе RAG‑пайплайна: при поиске контекста, его подготовке или при генерации итогового ответа.

Важно регулярно тестировать RAG-системы с пристрастием, чтобы минимизировать риски некорректной выдачи данных.
Читайте, чтобы узнать на что обратить внимание в первую очередь, какие метрики отражают реальную картину и как выстроить регрессионную и нагрузочную проверку так, чтобы изменения в модели, промптах или базе знаний не приводили к деградации качества.
Поскольку материал объёмный, советуем добавить страницу в закладки, чтобы возвращаться к нужным местам. Руководителю проекта хватит разделов 1, 2, 8 и 13 – они дадут понять, во что он ввязывается и сколько времени это займёт. Тест‑инженерам пригодятся и все остальные.
Вот приборная панель одного корпоративного ассистента за неделю до того, как его пришлось отключить. Все автоматические метрики зелёные, но проект провалился.
Три из четырёх метрик вводили в заблуждение.
Ассистент работал с внутренней базой банка. Говорил гладко, не придумывал цифры, всегда ссылался на документы – поэтому метрика faithfulness показывала хорошие 0,94. Но была проблема: в индексе лежали сразу две версии тарифного сборника – старая и новая. Ретривер то и дело вытаскивал старую версию, и модель честно пересказывала её – то есть, по сути, неправду.

На бумаге всё выглядело идеально. А на деле каждый шестой ответ сбивал клиента с толку. При этом метрика этого не показывала: она проверяла, насколько ответ соответствует тому, что попало в контекст, а не тому, насколько он правдив.
Такие ситуации встречаются сплошь и рядом. Команда собирает RAG за полтора месяца, а потом полгода не может запустить его в полноценную работу и сама не понимает, в чём загвоздка.
Давайте разберёмся: какие показатели действительно важны, какими инструментами их измерять, какие значения считать нормой – и что делать, когда метрики друг другу противоречат.
Раздел 1. Почему привычное тестирование не подходит для RAG-систем
Когда QA‑специалист, привыкший к обычному бэкенду, берётся за тестирование ИИ‑системы, он сразу упирается в одну проблему: тут нельзя просто сравнить ответ с эталоном. Нет одного чёткого ожидаемого результата – есть целый набор допустимых вариантов. Один и тот же запрос может трижды выдать разные тексты – и все три будут правильными. А может быть так: два ответа верные, а третий выглядит правдоподобно, но при этом с ошибкой.
Дальше всплывают ещё три неприятные проблемы:
- Локальная правка ломает то, чего вы не касались. Например, подкрутили промпт, чтобы система перестала выдумывать сроки, – и она вдруг начала отказываться отвечать на половину обычных вопросов.
- Качество и производительность тесно связаны. Увеличили top‑k с 5 до 15, чтобы охватить больше вариантов, – а в итоге латентность выросла вдвое, да и точность, скорее всего, упала: модель начала «тонуть» в лишнем шуме.
- Система может деградировать сама по себе. Индекс пополняется, документы со временем устаревают, а вендор тихо обновляет модель под тем же именем эндпоинта. Вы ничего не меняли, а качество всё равно снижается.
Отсюда главный организационный вывод, который Barnett и соавторы сформулировали жёстко: валидацию такой системы нельзя сделать до релиза. Она возможна только в эксплуатации, а устойчивость не проектируется заранее, а накапливается со временем1 . Это не отговорка, а требование к процессу. Нет замкнутого цикла: продакшен, датасет, регрессия – нет тестирования LLM. Есть приёмка демо.
Тестирование LLM – это не про проверку отдельных ответов. Это про создание надёжной системы измерений, которая останется полезной, даже если поменяется модель, изменится промпт или база знаний вырастет в десять раз.
Раздел 2. RAG-система по слоям
Самая частая ошибка – оценивать RAG как единое целое. В итоге вы получаете одну цифру, которая потихоньку падает, а понять, в чём проблема, невозможно. Качество снизилось – и что с этим делать? Между вопросом пользователя и готовым ответом скрывается восемь разных компонентов, и на каждом из них могут быть сбои по разным причинам.

Если оценивать систему целиком, все эти проблемы перемешиваются, и понять, где именно прячется сбой, становится невозможно.
| # | Что ломается | Как выглядит снаружи | Метрика | Инструмент |
|---|---|---|---|---|
| 1 | Ответа нет в базе | Уверенный ответ на вопрос, ответа на который в документах не существует | coverage датасета, доля «нет данных» | ручной аудит корпуса |
| 2 | Парсинг | Таблицы превратились в кашу, сноски приклеились к тексту, из сканов ничего не извлеклось | доля распарсенных блоков, ошибка на таблицах | сверка с эталонной разметкой, Docling, Unstructured |
| 3 | Чанкинг | Ответ в базе есть, но разрезан пополам между чанками | chunk attribution, доля «разорванных» ответов | эталонная привязка вопрос — чанк |
| 4 | Запрос | Ломается на местоимениях, аббревиатурах, опечатках, многошаговых вопросах | дельта recall до и после переписывания | A/B на слайсе «грязных» запросов |
| 5 | Поиск | Нужный чанк не попал в top-k вообще | recall@k, hit rate | ranx, ruMTEB, свой прогон |
| 6 | Ранжирование | Чанк в top-k, но на 14-й позиции — модель его не увидела | MRR, nDCG@k, context precision | RAGAS, TruLens |
| 7 | Сборка промпта | Контекст обрезан, релевантное ушло в середину, лимит съел половину | доля усечённых промптов, позиция релевантного чанка | трассировка: Langfuse, Phoenix |
| 8 | Генерация | Контекст правильный, ответ всё равно неверный или неполный | faithfulness, correctness, completeness | RAGAS, DeepEval, LLM-судья |
Пример: производственная компания, поиск по техрегламентам.
Recall@10 держался на уровне 0,52. Полгода перебирали модели генерации: две коммерческие, три открытые, пробовали дообучение. Разница – единицы процентов. И неудивительно: лечили точку 8, а сломаны были точки 2 и 3. Разметили 60 вопросов с привязкой к местам в документах.
Оказалось, что 40% эталонных фрагментов физически отсутствовали в индексе: таблицы допусков из PDF парсер разложил в бессмысленную строку чисел. Часть ответов разрывалась между кусками – резали по 800 символам без оглядки на структуру документа. Починили парсинг таблиц, стали резать по разделам, добавили BM25 и реранкер на кросс-энкодере. Recall@10 вырос до 0,87, faithfulness подтянулась сама – с 0,71 до 0,89. Модель не трогали вообще.

Отсюда правило: прежде чем винить модель, убедитесь, что нужная информация вообще попала в промпт. Две трети жалоб решаются на этапе парсинга, разбивки на фрагменты и поиска.
Раздел 3. Без золотого датасета надстройки не работают
Без размеченного набора вопросов с эталонными ответами вы не сможете ни отследить ухудшение качества, ни сравнить разные модели, ни нормально обсудить с заказчиком, насколько хорошо работает система. Вместо фактов будет просто спор, где побеждает тот, кто громче говорит.
Что должно быть в одной записи:
- Вопрос ровно в той форме, как его мог бы задать реальный человек – с опечатками, сокращениями и всеми «а если по‑другому».
- Эталонный ответ от эксперта. Не какой‑то безупречный текст, а чёткий список фактов, которые обязательно должны прозвучать.
- Ссылки на конкретные куски источников. Они помогают понять, в чём проблема: система не нашла нужную информацию или нашла, но плохо её пересказала. Без таких ссылок не получится разобраться, где именно случился сбой.
- Срез: тип вопроса, подразделение, уровень сложности.
- Ожидаемое поведение: ответить, запросить уточнение или честно сказать, что такой информации нет. Это очень важно: если в наборе нет вопросов, на которые правильный ответ – «в базе этого нет», весь набор почти бесполезен.
Сколько нужно записей?
Допустим, вы хотите понять, насколько хорошо система отвечает: скажем, примерно в 80% случаев, плюс‑минус 5%, и чтобы результат был надёжным (с вероятностью 95%). Для этого понадобится около 250 примеров. Опыт с бенчмарками это подтверждает: стабильная картина появляется где‑то на 250–500 кейсах. А если взять меньше сотни – вы будете видеть случайные колебания и принимать их за реальный прогресс.
Только не надо думать, что нужно собрать по 250 кейсов для каждого среза – так вы просто утонете в разметке. Держать точность в ±5% дорого и трудоёмко. Для того чтобы вовремя замечать, когда качество падает, вполне хватает ±10% – а для этого достаточно около 60 примеров.
Срезы бывают двух видов. По крупным срезам вы смотрите общую долю удачных ответов и оцениваете её с учётом погрешности. А редкие, но очень важные случаи лучше вообще не мерить статистикой: сделайте их обязательными (must‑pass) и проверяйте вручную. Тут всё просто: либо ответ верный, либо нет.
| Этап | Объём | Что этим можно делать | Чего делать нельзя |
|---|---|---|---|
| Разведка | 20–50 | Понять, куда смотреть; отловить очевидное | Сравнивать модели, отчитываться о качестве |
| Пилот | 100–200 | Первые пороги, регресс на критичных сценариях | Резать по срезам — в каждом окажется по 10 записей |
| Прод | 300–600 | Пороги по срезам, приёмка релизов, выбор модели | Считать, что он не устареет |
| Зрелый | 1000+ | Дельты в 2–3 п.п., длинный хвост, редкие сценарии | Гонять целиком на каждый коммит — разоритесь |
Срезы важнее объёма
Средняя оценка по датасету – почти бесполезная цифра в отчёте. Показатель 0,86 может значить разное: либо везде стабильно 0,86, либо, например, 0,95 на простых фактах и всего 0,41 на вопросах с расчётами. Это два совершенно разных уровня качества продукта.
Разбивать данные стоит минимум по четырём параметрам: тип вопроса (факт, сравнение, расчёт, процедура, отсутствующая информация), раздел базы, «грязность» формулировки и цена ошибки. Отдельно держите список must‑pass – 20–40 вопросов, провал по любому из которых сразу блокирует релиз, без обсуждений.
Откуда брать данные?
Есть три источника, и они дополняют друг друга, а не заменяют:
- Реальные обращения из тикетов и поисковых логов – так вы увидите, как пользователи формулируют запросы на самом деле.
- Экспертные сценарии – то, что обязано работать всегда, даже если таких вопросов ещё никто не задавал.
- Синтетические данные (например, с помощью RAGAS) – они помогают закрыть объём и обеспечить покрытие базы документов.

Важное про синтетику: она часто создаёт вопросы, которые почти дословно повторяют текст документа. Такие легко решаются простым совпадением и сильно завышают показатель recall – иногда на десятки процентных пунктов. Обязательно перефразируйте такие вопросы и вручную проверьте хотя бы 10%. Лучше подстраховаться сразу.
Признаки, что ваш датасет не отражает реальность:
- В нём нет вопросов, на которые правильный ответ – «не знаю».
- Все вопросы написал один человек за один вечер.
- Эталонные ответы готовил тот же человек, который писал системный промпт.
- Датасет три месяца не обновляли, хотя в базу добавили 4000 документов.
- Он хранится в Google‑таблице без версий – никто не может сказать, какая версия использовалась для какого релиза.
Раздел 4. Метрики поиска – база для оценки RAG
Хорошая новость: ретривер (тот самый каталог данных) тестируется как обычная поисковая система, тут за нас всё придумали ещё в девяностые. Метрики детерминированные, дешёвые, считаются за секунды и не требуют ни одного вызова LLM.
| Метрика | Что отвечает | Ориентир | О чём говорит просадка |
|---|---|---|---|
| Recall@k | Доля нужных фрагментов, попавших в top-k | ≥ 0.90 при k=10 |
Потолок всей системы. Ниже recall модель не прыгнет никогда — ответ просто не из чего собрать |
| Hit rate@k | Доля запросов, где в top-k попал хотя бы один нужный фрагмент | ≥ 0.95 | Мягкая версия recall; удобна для быстрых прогонов и мониторинга |
| MRR | Насколько высоко стоит первый релевантный фрагмент | ≥ 0.75 | Слабое ранжирование: ответ есть, но лежит глубоко и тонет в шуме |
| nDCG@k | Качество порядка с учётом градаций релевантности | ≥ 0.80 | Главная метрика для оценки реранкера |
| Context precision | Какая доля отданного в промпт контекста реально нужна | ≥ 0.70 | Мусор в контексте: растут токены и TTFT, падает точность |
| Context recall | Вся ли информация из эталона нашлась в контексте | ≥ 0.80 | Частичные ответы: верно, но неполно |
Три эксперимента, которые реально улучшают показатели. Сделайте их до того, как начинать возиться с моделью.
- Гибридный поиск. Векторный поиск плохо ловит точные обозначения – артикулы, номера ГОСТов, коды услуг, редкие термины. Зато с этим отлично справляется BM25. Если объединить результаты (обычно используют RRF), на корпоративных базах на русском языке recall стабильно растёт. Причина простая: в половине реальных запросов люди указывают точные идентификаторы.
- Реранкер. Поставьте кросс‑энкодер поверх первых 50 результатов – это самый недорогой способ поднять nDCG. Обработка занимает всего десятки миллисекунд и почти всегда себя оправдывает.
- Метаданные и права доступа. Добавляйте фильтры по дате, версии, подразделению. Параллельно проверьте, нет ли утечек: обязательно включите в обязательные тесты ситуацию, когда пользователь с одной ролью пытается получить доступ к документам другой роли.
И про длину контекста. Хочется добавить побольше текста в запрос – вроде как модель лучше разберётся. Это частая ошибка. Ещё в 2023 году описали эффект «потерянного в середине»2: информация из середины длинного контекста хуже учитывается. А исследование context rot от Chroma подтвердило: чем длиннее входной текст, тем ниже качество ответов – это верно для всех проверенных моделей. Даже миллион токенов не убирает проблему, а лишь сдвигает момент, когда качество начинает падать3. Подбирайте количество фрагментов (k) опытным путём: почти всегда есть граница, после которой лишние куски только ухудшают и точность, и скорость работы.
Раздел 5. Пять типов галлюцинаций: чем они отличаются и как их ловить

Слово «галлюцинация» в требованиях к проекту – верный признак, что требования ещё не проработаны. За этим термином скрывается как минимум пять разных дефектов, и для каждого нужно своё решение.
| Тип | Как выглядит | Чем ловится | Чем лечится |
|---|---|---|---|
| Фабрикация | Придуманы факты, которых нет ни в контексте, ни в реальности: несуществующий пункт регламента, выдуманный срок | NLI-энтейлмент, декомпозиция на утверждения | Требование цитаты, жёсткая инструкция «только из контекста», постфильтр |
| Противоречие контексту | В документе «до 30 дней», в ответе «до 14 дней» | faithfulness / groundedness | Понижение температуры, реранкер, отсев противоречивых чанков |
| Верно, но не по делу | Ответ фактически корректен и полностью бесполезен для заданного вопроса | answer relevancy | Переписывание запроса, работа с промптом |
| Неполнота | Из трёх обязательных условий названо одно: формально не ложь, по факту вводит в заблуждение | completeness, context recall | Рост k, чанкинг по смыслу, требование перечислить все условия |
| Устаревшая правда | Ответ идеально соответствует контексту, но контекст протух | свежесть источника, correctness против эталона | Версионирование документов, фильтр по дате, регламент переиндексации |
Пятый тип – самый коварный: его не видят метрики без эталона. Именно он был в примере из начала статьи. Если ваша база обновляется чаще раза в квартал, добавьте отдельную метрику – «доля ответов на неактуальной редакции». Это простая проверка на метаданных – она не требует ни одного вызова модели и обходится недорого.
Пример: банк, ассистент оператора контакт-центра
Это тот самый случай, с которого началась статья. Когда базу переиндексировали, новые версии тарифов загрузили рядом со старыми, а старые не удалили. В итоге около 17% фрагментов в поиске относились к уже недействующим редакциям. Векторный поиск спокойно их выдавал: по тексту они даже лучше подходили к запросам – ведь написаны более официальным, «казённым» языком.
Проставили valid_from и valid_to в метаданных, ввели жёсткий фильтр по дате на этапе поиска, добавили в датасет 45 вопросов с изменившимися формулировками и метрику свежести. Доля ответов по устаревшим источникам за две недели упала с 17% до 0,4%. Faithfulness не изменилась – и это нормально: она и не должна была меняться, ведь проблема была не в искажении фактов, а в том, что система брала данные из старых документов.
Раздел 6. Четыре способа бороться с галлюцинациями
В индустрии выделяются четыре основных подхода. Они отличаются по стоимости – разница может быть в два раза и больше. Выбирать стоит тот, который укладывается в ваш бюджет при нужном объёме прогонов.
| Подход | Как работает | Стоимость | Сильная сторона | Где ломается |
|---|---|---|---|---|
| NLI-энтейлмент
офлайн-модель |
Небольшая обученная модель проверяет, следует ли ответ из контекста. Классика — HHEM от Vectara, всего 110M параметров | ≈0 | Быстро, дёшево, детерминированно, живёт в закрытом контуре | Русский — нужна многоязычная или дообученная модель; длинные ответы приходится резать |
| Декомпозиция на утверждения
гибрид |
Ответ разбивается на атомарные факты, каждый проверяется против контекста отдельно (логика FActScore, RefChecker) | средняя | Даёт не «плохо», а какое именно утверждение не подтверждено. Лучшая диагностика | Само разбиение ошибается; дороже прямой оценки в 3–5 раз |
| Самосогласованность
без эталона |
Генерируем N ответов при t>0 и смотрим, расходятся ли они. Расходятся — модель не знает (идея SelfCheckGPT) | высокая | Не нужен ни контекст, ни эталон. Хороший онлайн-сигнал неуверенности | N-кратная стоимость генерации; уверенно врущая модель проходит проверку |
| LLM-судья
требует калибровки |
Сильная модель оценивает ответ по рубрике. Основа RAGAS, DeepEval, G-Eval | $0.001–0.003 за кейс |
Любой критерий, включая тон, полноту, соответствие политике | Смещения, нестабильность, дрейф при обновлении судьи |
Рабочая схема, которая применима почти везде, – каскад: дешёвое и предсказуемое впереди, дорогое позади.
- Программные проверки. Смотрим ссылки на источники, формат, числа и даты, которых нет в контексте. Например, модель пишет «1,5 млн», а в документе – «1 500 000». Простая проверка тут не сработает: нужно сначала привести оба варианта к одному виду – одинаково записать числа, единицы измерения, даты, проценты. Такой фильтр стоит использовать как сигнал для дальнейшей проверки, а не как повод сразу отбраковать ответ. У этого этапа хорошая полнота, но точность средняя.
- NLI‑модель на каждый ответ. Она быстро показывает, насколько ответ соответствует контексту.
- LLM‑судья. Его подключаем только к тем ответам, где первые два этапа дали неоднозначный результат, плюс берём контрольную выборку.
- Человеческая проверка. Достаточно 50–100 кейсов в месяц: это помогает следить, чтобы судья не начал ошибаться и выдавать не те оценки.
Если прогонять все 500 записей через одного судью, получится сотни вызовов LLM и десятки минут работы. Каскад как раз и нужен, чтобы большую часть задач решать простыми и бесплатными тестами.
Раздел 7. Ловушки LLM‑судьи: почему метрики врут и что с этим делать
Тут ошибаются чаще всего и обходится это очень дорого. Получается твёрдая уверенность в неправильных цифрах. Что говорят исследования. Хороший LLM‑судья на тестах MT‑Bench и Chatbot Arena совпадает с мнением людей больше чем в 80% случаев. Это примерно столько же, сколько люди совпадают друг с другом4.
Но есть и минус: позиционное смещение доходит до 75%, судья систематически предпочитает длинные ответы, а модели предпочитают собственные (GPT-4 завышал себе win rate примерно на 10 п.п., Claude-v1 – примерно на 25). И здесь важный момент: процент совпадений с человеком выглядит слишком оптимистично, потому что не учитывает случайное совпадение. Поэтому правильнее использовать показатель каппы. На реальных данных разница между ним и простым «процентом согласия» бывает очень большой.
| Смещение | Проявление | Противоядие |
|---|---|---|
| Позиционное | В парном сравнении выигрывает тот, кто идёт первым | Прогонять оба порядка и усреднять. Расхождение между прогонами само по себе индикатор ненадёжности |
| Многословность | Длинный ответ получает балл выше при том же содержании | Явный пункт рубрики про краткость; контроль корреляции балла с длиной |
| Самопредпочтение | Судья хвалит ответы своего же семейства моделей | Судья и генератор — из разных семейств. Без исключений |
| Дрейф | Вендор обновил модель — история оценок перестала сравниваться | Пиннинг версии судьи; при смене — переоценка эталонной выборки и пересчёт порогов |
| Размытая рубрика | «Оцени качество от 1 до 5» даёт разброс ±1.5 балла на одном и том же ответе | Бинарные критерии с обязательным обоснованием и цитатой из контекста |
Калибровка: настраиваем один раз, потом проверяем каждый месяц
- Возьмите 150–300 реальных ответов. Делайте упор на спорные случаи – их должно быть больше.
- Раздайте эти ответы нескольким экспертам (пусть оценивают независимо друг от друга) и посмотрите, насколько их мнения совпадают. Тут важно не ошибиться с расчётом: каппа Коэна годится только для двух оценщиков. Если экспертов трое или больше, берите каппу Флейса или альфу Криппендорфа – альфа удобнее: она учитывает пропуски и разные уровни оценок.
- Если согласие ниже 0,6 – остановитесь. Проблема не в судье, а в том, что у вас пока нет чёткого понимания, что считать качественным ответом.
- Дальше помогите экспертам прийти к общему мнению (консенсусу) и прогоните тот же набор ответов через LLM‑судью. Теперь у вас снова два оценщика: судья и консенсус, – поэтому тут как раз подходит каппа Коэна.
Смотрим на результат:
- каппа ниже 0,5 – нужно переписать критерии (рубрику);
- от 0,6 до 0,8 – система работает нормально;
- выше 0,8 – можно смело доверять автоматике для таких задач.
Проверку повторяйте каждый месяц. И обязательно делайте её заново, если поменяли модель‑судью или переписали критерии.
Лучше всего работает простая рубрика с двумя вариантами ответа (бинарная), но с обязательным условием – в ответе должна быть цитата. Пятибалльная шкала выглядит солиднее, но на практике люди по ней оценивают менее одинаково.
# Рубрика groundedness. Бинарно, с обязательной опорой на текст. # Судья — модель другого семейства, чем генератор. temperature=0. Ты проверяешь, опирается ли ОТВЕТ исключительно на КОНТЕКСТ. 1. Выпиши из ОТВЕТА все проверяемые утверждения (факты, числа, даты, названия, условия). Мнения и вводные фразы пропусти. 2. Для каждого найди в КОНТЕКСТЕ дословный фрагмент, который его подтверждает. Не нашёл — помечай "не подтверждено". 3. Верни JSON: {"claims": [{"claim": "...", "supported": true|false, "quote": "дословная цитата или null"}], "verdict": "grounded" | "not_grounded"} verdict = "grounded" только если ВСЕ утверждения supported. Не оценивай стиль, длину и полноту. Только опору на текст.
Главное – обязательно требовать цитату. Так не получится отделаться расплывчатым «да, в целом подходит». Модели куда сложнее придумать точный фрагмент текста, чем просто отметить галочкой.
Пример: как LLM-судья полгода нас обманывал
У нас был внутренний ассистент: он сам придумывал ответы и сам же их оценивал – на той же самой модели. Оценка шла по пятибалльной шкале: «насколько ответ полезный». В среднем выходило 4,4 балла – на дашборде всё горело зелёным, все были довольны. Потом решили проверить, насколько эта оценка похожа на человеческую. Взяли 200 ответов и отдали на разбор трём экспертам. Между собой эксперты сошлись на уровне 0,71 – это нормально. А вот «судья» совпадал с их общим мнением только на 0,31. То есть почти не попадал.
Выяснилось, в чём подвох: судья любил длинные ответы и щедро ставил им высокие баллы. А ошибки почти не замечал: если модель уверенно что‑то придумывала, это звучало это очень убедительно. Как исправили: заменили судью на другую модель, а вместо пяти баллов сделали простую проверку по трём чётким критериям – по принципу «да/нет». И главное: по каждому критерию обязательно нужно было привести цитату из текста.
Результат не обрадовал сразу: каппа выросла до 0,74, а общий показатель «качества» рухнул с 0,89 до 0,72. Было неприятно – словно всё, чем гордились, оказалось ненастоящим. Но именно с этого начался настоящий рост. Через три месяца показатель поднялся до 0,86 – и теперь за этим числом уже стояла реальная картина.
Раздел 8. Три уровня защиты качества: как выбрать правильные пороги
Гонять всё на каждый коммит дорого и долго. Разложите проверки по трём контурам с разной частотой и ценой.
# Ворота качества в CI. DeepEval работает как обычный pytest. import pytest, json from deepeval import assert_test from deepeval.test_case import LLMTestCase from deepeval.metrics import FaithfulnessMetric, ContextualRecallMetric MUST_PASS = json.load(open("golden/must_pass.json")) # Пороги — в конфиге, версионируются вместе с датасетом. # Для must-pass они выше, чем для основного набора. @pytest.mark.parametrize("item", MUST_PASS, ids=lambda i: i["id"]) def test_must_pass(item, rag_pipeline): out = rag_pipeline(item["question"]) case = LLMTestCase( input=item["question"], actual_output=out.answer, expected_output=item["reference"], retrieval_context=out.contexts, ) assert_test(case, [FaithfulnessMetric(threshold=0.90), ContextualRecallMetric(threshold=0.85)])
Теперь про пороги. По гайдам кочуют значения: faithfulness 0,75, answer relevancy 0,8, context precision 0,7, context recall 0,8. Как стартовую точку на первую неделю их взять можно, но жить по ним нельзя: они ничего не знают про цену вашей ошибки. Для подбора фильма 0,75 – прекрасно. А для ответа о дозировке или неустойке это значит, что каждый четвёртый ответ содержит непроверенное утверждение. Это не запуск, а инцидент с отложенным сроком.
Рабочий способ: возьмите 200 ответов, попросите экспертов пометить каждый – можно отдавать пользователю или нет. Потом постройте распределение метрики по двум группам и выберите порог так, чтобы доля пропущенных опасных ответов была приемлема для бизнеса.
Дальше фиксируйте не абсолют, а дельту: релиз блокируется при просадке больше 3 процентных пунктов на любом срезе относительно прода. Абсолютные значения вы будете пересматривать, а дельты – почти никогда.
# Ворота качества в CI. DeepEval работает как обычный pytest.
import pytest, json
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import FaithfulnessMetric, ContextualRecallMetric
MUST_PASS = json.load(open("golden/must_pass.json"))
# Пороги — в конфиге, версионируются вместе с датасетом.
# Для must-pass они выше, чем для основного набора.
@pytest.mark.parametrize("item", MUST_PASS, ids=lambda i: i["id"])
def test_must_pass(item, rag_pipeline):
out = rag_pipeline(item["question"])
case = LLMTestCase(
input=item["question"],
actual_output=out.answer,
expected_output=item["reference"],
retrieval_context=out.contexts,
)
assert_test(case, [FaithfulnessMetric(threshold=0.90),
ContextualRecallMetric(threshold=0.85)])
Раздел 9. Нагрузочное тестирование RAG‑систем: почему не стоит доверять RPS
Если при нагрузочном тестировании LLM опираться на привычные метрики, получится красивый отчёт, который никак не отражает реальный опыт пользователя. В отчёте всё «зелёное», а пользователи недовольны – и все недоумевают: вроде показатели хорошие, а на деле всё плохо.
Дело в том, что запрос к генеративной модели – это не одно простое действие, а два разных этапа.
Первый этап – prefill. Модель сразу считывает весь промпт целиком. Тут главная нагрузка приходится на вычисления: чем длиннее ввод, тем дольше длится этап.
Второй этап – decode. Модель выдаёт токены по одному. Здесь основная нагрузка – на память: чем длиннее ответ, тем больше времени уходит.
А средний RPS складывает оба этапа в одну цифру. Из‑за этого она ничего толком не показывает – ни про первый этап, ни про второй.

Один запрос — четыре разные метрики. Средняя латентность не показывает ни одной из них.
| Метрика | Смысл | Ориентир p95 | Что означает нарушение |
|---|---|---|---|
| TTFT | Время до первого токена: очередь плюс prefill | < 1.5 с | Пользователь смотрит в пустой экран. Главный вклад в ощущение «тормозит» |
| ITL (inter-token latency) |
Задержка между каждой парой соседних токенов — распределение, а не число | p95 < 60 мс | Текст ползёт рывками. Смотреть надо именно хвост: джиттер живёт в нём и в среднем не виден |
| TPOT | Среднее время на выходной токен: (E2E − TTFT) / N | < 40 мс | Скорость генерации. Может быть отличной при рваном ITL — не заменяет его |
| E2E | Полное время до последнего токена | < 8 с | Критично для не-стриминговых интеграций и API, который дальше кто-то вызывает |
| Output TPS | Токенов в секунду на систему | по железу | Метрика ёмкости, а не пользовательского опыта. Не путать местами |
| Goodput | Доля запросов, уложившихся во ВСЕ пороги сразу | ≥ 95% | Единственная метрика, которую стоит показывать бизнесу |
| Queue wait | Время ожидания планировщика | < 200 мс | Растёт неограниченно — вы за точкой насыщения, добавляйте реплики |
| KV-cache util | Занятость кэша ключей и значений | < 85% | Упёрлись — пойдут вытеснения и пересчёты, латентность прыгнет ступенькой |
Goodput – самая полезная метрика в современном тестировании. Вы задаёте набор условий, например: TTFT меньше 1,5 секунды, p95 ITL – меньше 60 миллисекунд, E2E – меньше 8 секунд. Потом считаете, какая доля запросов удовлетворяет всем этим условиям одновременно.
Интересно вот что: когда нагрузка растёт, обычный throughput ещё увеличивается, а goodput уже падает. Точка, где кривые расходятся, – это и есть реальный предел системы. Не тот момент, когда она полностью ломается, а тот, когда качество обслуживания начинает ухудшаться.

Классическая ловушка ёмкостного планирования: отчёт по пиковому throughput показывает правую часть графика, а пользователи живут в левой.
Пять обязательных сценариев для нагрузочного теста
- Степ-тест. Постепенно наращиваем нагрузку – от одного запроса до значения выше максимального батча. Строим график, находим рабочую точку и обязательно оставляем запас минимум 30 %. Так система выдержит неожиданные скачки.
- Спайк-тест. Имитируем резкий, многократный рост нагрузки. Смотрим, как ведёт себя очередь: система плавно снижает скорость или сразу начинает выдавать таймауты. Это покажет, насколько она устойчива к внезапным пикам.
- Тест на выносливость. Держим стабильную нагрузку 4–8 часов. Такой тест ловит то, что не видно за 10 минут: утечки памяти, фрагментацию KV‑кэша, накопление контекста в диалогах. Это скрытые проблемы, которые со временем сильно портят работу.
- Смешанный трафик. Прогоняем вместе короткие чаты и длинные RAG‑запросы – так, как это бывает в реальной жизни. Это самый важный сценарий, но его часто пропускают. Он показывает, как система справляется с разнородной нагрузкой.
- Деградация зависимостей. Специально «ломаем» внешние компоненты: замедляем векторную БД, отключаем эмбеддер, заставляем реранкер выдавать таймауты. Проверяем, сработает ли запасной вариант (fallback) или система начнёт массово возвращать ошибки 500. Это помогает понять, насколько сервис отказоустойчив.
| Инструмент | Для чего годится | Ограничения |
|---|---|---|
| vLLM benchmark_serving |
Эталонный прогон движка: TTFT, TPOT, ITL, goodput из коробки, разные бэкенды | Мерит движок, а не ваш пайплайн с поиском и реранком |
| NVIDIA AIPerf | Профилирование под нагрузкой, воспроизведение трасс реального трафика, временные ряды | Ориентирован на инференс-эндпоинт; лучше запускать внутри кластера |
| GuideLLM | Повторяемые сценарии с реалистичными формами запросов, развёртки по конкурентности | Фокус на серверах с OpenAI-совместимым API |
| Locust / k6 | Полный пользовательский сценарий: авторизация, история диалога, вызовы инструментов, паузы на «подумать» | Потоковые метрики придётся считать самому — код ниже |
| Яндекс.Танк, JMeter, Gatling |
Если стенд и мониторинг уже стоят — переиспользуйте. Профили нагрузки описываются штатно | Из коробки не понимают SSE и потоковые токены; нужны свои обработчики |
Частая ошибка в отчётах – неправильный замер TTFT. Его нужно считать по первому видимому токену, который реально видит пользователь, а не по самому первому событию от сервера.
Дело в том, что сначала сервер отдаёт служебный кадр: там есть роль, но нет полезного текста. Потом могут идти пробельные чанки, tool_calls, а reasoning‑модели ещё и вываливают свои внутренние рассуждения. Если взять за точку отсчёта самое первое событие, получится вроде бы хорошие 80 мс – но пользователь в этот момент ещё ничего не видит. Из‑за такой ошибки цифры в отчётах нередко завышают втрое.
С reasoning‑моделями тут вообще нужно держать в голове два показателя. Если в интерфейсе есть индикатор, что система думает, – важен момент появления этого индикатора. Если такого индикатора нет – считаем время до первого символа ответа. Эти значения порой отличаются в разы. Лучше замерять оба, а в SLA закладывать тот, который реально соответствует вашему интерфейсу.
Пример: ритейл, ассистент по каталогу и заказам
Отчёт выглядел отлично: 420 запросов в минуту, средняя латентность – 2,4 секунды, ошибок нет. Но пользователи жаловались, что в час пик сервисом невозможно пользоваться.
Дело в том, что тест прогоняли только по одному сценарию – короткие вопросы о статусе заказа. А в реальной работе рядом шли тяжёлые RAG‑запросы по каталогу: промпты на 8–12 тысяч токенов. Из‑за этапа prefill они забивали батч, и короткие запросы уходили в очередь. В итоге p95 TTFT в пиковые моменты доходил до 11 секунд – при средней латентности в 2,4 секунды. Goodput по порогам (TTFT < 1,5 с и p95 ITL < 60 мс) составлял всего 61 %.
Что сделали: развели два пула инференса – с разными лимитами контекста и приоритетами. Сократили top‑k с 12 до 6 (предварительно убедившись, что recall не падает). Включили префиксное кэширование системного промпта. В результате goodput вырос до 94 % – и это на том же оборудовании.
Ещё одна ловушка, в которую попадают почти все, – это кэш. Если гонять по кругу 50 одинаковых вопросов, вы на самом деле измеряете работу кэша, а не реальную производительность системы.
Чтобы тест был честным, берите профиль повторяемости запросов из логов поиска. Там обычно видна такая картина: небольшое частотное ядро – это самые популярные запросы, а остальное – длинный хвост из множества уникальных. Именно такой микс и нужно закладывать в нагрузку, чтобы понять, как система ведёт себя в реальных условиях.
Раздел 10. Куда уходят деньги: почему половина расходов на LLM впустую
Цена за миллион токенов не отражает реальную картину для бизнеса. Она не учитывает, сколько раз пользователь переспрашивает, сколько генераций запускается повторно и сколько обращений уходит в поддержку из‑за неудачного ответа.
Считайте стоимость одного успешного ответа: сложите затраты на инференс, эмбеддинги, реранк и оценку, а потом разделите на количество ответов, которые соответствуют вашим критериям качества. Так получится честная метрика. Например, дорогая модель с точностью 0,91 нередко обходится дешевле, чем дешёвая с точностью 0,68. Причина простая: у второй модели каждый третий диалог приходится передавать оператору – а это дополнительные расходы.
Ещё полезно разбить траты по разным типам запросов. Часто оказывается, что всего 8 % запросов «съедают» 40 % бюджета. Обычно это длинные документы или вопросы, на которые система не может дать нормальный ответ и запускает повторную обработку. Такие случаи лучше сразу маршрутизировать в обход LLM – это сэкономит ресурсы.
Раздел 11. Безопасность LLM в российском контуре: что реально тестировать, если идеальных защит нет
Промпт‑инъекция стоит на первом месте в OWASP Top 10 для LLM5, и полного решения у неё пока нет. По разным оценкам, доля успешных атак на фронтир‑модели держится от 50 до 80% – даже при штатных средствах защиты. Поэтому задача теста – не убедиться, что защита работает, а измерить, насколько она дырявая, и проверить, что последствия пробоя ограничены.
Для RAG опасен непрямой вектор: вредоносная инструкция прячется не в запросе пользователя, а внутри проиндексированного документа. Пользователь ничего подозрительного не делает, а система сама подтягивает отравленный фрагмент. Классический пример – EchoLeak (CVE‑2025‑32711): утечка данных вообще без действий пользователя. Если в вашу базу знаний может что‑то загружать внешний контрагент, этот тест обязателен.
В России за последний год серьёзно поменялись правила работы с данными и ИИ. С 1 марта 2026 года вступил в силу приказ ФСТЭК № 117 – он пришёл на смену предыдущему (№ 17) и обновляет требования к защите информации в государственных системах. Теперь системы с ИИ проверяют так же строго, как и остальные.
Но этот приказ про другое: он говорит про защиту периметра, безопасность данных и надёжность технологий, а не про то, как оценивать качество ответов ИИ.
Как именно проверять модели, описано в других документах: в линейке стандартов ТК 164 «Искусственный интеллект», профильных ГОСТах, а также в международных стандартах ISO/IEC 42001 и NIST AI RMF.
Важно смотреть актуальную версию правил в первоисточнике: нормы быстро меняются, и любые пересказы, даже в профессиональных блогах, устаревают за несколько месяцев. При этом общий вывод остаётся неизменным: если вы работаете с госзаказчиком или в регулируемой отрасли, вам придётся открыто показывать, как вы измеряете качество работы ИИ. Лучше заложить это в процессы сразу – потом выйдет дороже.
Что нужно сделать, чтобы оценка была прозрачной
- Зафиксируйте методику так, чтобы её можно было повторить: какая версия датасета использовалась, какая модель‑судья, какие параметры запуска были заданы, а также сохраните все исходные результаты тестов.
- Не берите пороговые значения «с потолка» или из статей в блогах – их нужно обосновать. Например, подойдёт такой протокол: «Эксперты разметили 200 ответов, порог выбран по такому‑то критерию». Это сразу снимает вопросы проверяющих.
- Если система работает в закрытом контуре, нельзя оценивать её через внешние API. Модель‑судья тоже должна находиться внутри периметра. Это влияет на выбор самой модели и на то, какое оборудование вам понадобится.
- Отдельно обсудите с юристами, как обрабатывать персональные данные в промптах и логах. В 2026 году штрафы за утечки очень серьёзные – проще и дешевле сразу обезличивать данные.
Есть русскоязычные инструменты, которые можно использовать внутри периметра:
- MERA – с отраслевой и кодовой ветками;
- gigaragas – это адаптация RAGAS с промптами на русском языке;
- ruMTEB – помогает выбрать подходящий эмбеддер;
- LLM Arena – позволяет быстро сравнить разные модели.
Эти инструменты не заменят собственный датасет, но помогут сильно сэкономить время на старте.
Раздел 12. Какие метрики в проде реально говорят о качестве
Офлайн‑метрики показывают, улучшились ли результаты на вашем тестовом наборе данных. Но они не говорят о том, насколько хорошо система работает для пользователей прямо сейчас. Чтобы понимать реальную картину, нужны косвенные сигналы – их можно собирать автоматически, без ручной разметки.
Смотрите на то, что происходит в реальном трафике. Например, если пользователь переформулирует тот же вопрос – скорее всего, первый ответ его не устроил. Важны и другие моменты: сколько запросов уходит к оператору, как часто система выдаёт отказ, сколько ответов даётся без ссылок на источники, насколько сильно различается длина ответов. Каждый из этих показателей сам по себе не очень надёжен – в нём много «шума». Но если смотреть их вместе, складывается довольно чёткая картина того, как система ведёт себя в бою.

Ещё важно следить за тем, как меняется поток запросов – это называют дрейфом входа. Для этого раз в неделю группируйте запросы по их смысловому сходству (через эмбеддинги).
Если появляется крупный новый кластер запросов, а в вашем датасете под него нет примеров – это сигнал, что пора пополнять данные. Не стоит ждать, пока начнут поступать жалобы.
И обязательно закрепите простое правило: каждый разобранный инцидент сразу же превращайте в пример для золотого датасета – в тот же день. Это самый надёжный способ делать систему устойчивее с каждым днём. Без такой привычки вы будете снова и снова сталкиваться с одними и теми же проблемами и чинить их по кругу.
Пример: как «улучшение» сломало половину сценариев
Мы заменили эмбеддер на более свежий – по публичному лидерборду он выглядел сильнее. Проверили на сотне вопросов: средний recall вырос с 0,81 до 0,84 – и выкатили обновление.
Через неделю выяснилось, что на срезе «номера регламентов и артикулы» recall рухнул с 0,88 до 0,53. Новая модель лучше улавливала смысл, но хуже справлялась с точными идентификаторами. В общей статистике это выглядело как рост – ведь таких запросов в датасете было всего 12 из 100.
Вывод, который стоил трёх недель работы: ориентироваться только на средний показатель нельзя. Гейт релиза должен проверять каждый срез отдельно и блокировать выкатку, если хоть по одному есть просадка – даже если общий результат вырос.
В итоге добавили в датасет 60 запросов с идентификаторами и включили гибридный поиск – его стоило задействовать сразу.
Раздел 13. Пошаговый план тестирования RAG-системы
Команда: тест‑инженер, инженер данных, эксперт предметной области. По несколько часов в неделю на человека. Дополнительные люди помогут, но не сильно: главный ограничитель – доступность эксперта.
| Срок | Шаг | Что именно |
|---|---|---|
| Неделя 1 | Договориться, что такое «хорошо» | Собрать PO, эксперта и инженера в одной комнате и разобрать 30 реальных ответов вручную. Не в переписке — вживую. На выходе список критериев и понимание, где вы расходитесь. Самая ценная встреча проекта, её почти всегда пропускают |
| Недели 1–2 | Трассировка | Сквозные трейсы: запрос → переписанный запрос → найденные чанки с позициями → промпт → ответ. Langfuse или Phoenix ставятся за день, разворачиваются локально. Без этого работать нельзя — вы не увидите, где ломается |
| Недели 2–4 | Датасет | 150–200 записей с привязкой к источникам: половина из реальных обращений, треть — экспертные сценарии, остаток — синтетика с ручной проверкой. Обязательно вопросы, ответа на которые нет |
| Неделя 4 | Метрики поиска | recall@k, MRR, nDCG. Идут первыми: детерминированные и бесплатные. Скорее всего, здесь найдётся первая крупная проблема, и она окажется в парсинге |
| Недели 5–6 | Судья и калибровка | Рубрика, разметка 150–300 ответов экспертами, каппа Коэна. Не двигаться дальше, пока не получите 0.6 |
| Неделя 6 | Быстрый контур в CI | must-pass, программные проверки, метрики поиска. Пять минут на прогон, блокирует мердж |
| Недели 7–8 | Нагрузка | Ступенька, всплеск, смешанный трафик. Рабочая точка по goodput, зафиксированные SLO, мониторинг TTFT и хвоста ITL |
| Недели 8–9 | Безопасность | Прямые и непрямые инъекции, утечки, ПДн. Результаты — в регресс |
| Недели 9–10 | Прод-контур | Прокси-метрики, алерты на дельты, ежемесячный ритуал калибровки судьи и пополнения датасета из инцидентов |
В среднем на тестирование систем ИИ нужно потратить от двух с половиной месяцев, чтобы понять, стало ли лучше. Иногда получается быстрее – чаще всего за счёт работы с датасетом. Но такая спешка нередко выходит боком: потом приходится тратить ещё больше времени и ресурсов.
Раздел 14. Проверьте себя за 5 минут: типичные антипаттерны в тестировании ИИ
Вывод
Что по-настоящему важно? Если оставить только самое главное из статьи – получится четыре пункта.
- Разбивайте систему на части и оценивайте каждую отдельно. Если смотреть только на одну общую цифру, непонятно, где искать проблему и что исправлять.
- Главный инструмент – золотой датасет со ссылками и разными срезами. Без него любое тестирование превращается просто в обсуждение впечатлений. Всё остальное – это уже дополнения к этой основе.
- Проверяйте модель‑судью с помощью людей. Сама по себе она может показывать «красивые» цифры, которые просто приятно видеть. Чтобы этого избежать, считайте, насколько оценки модели совпадают с мнением людей: для двух экспертов подойдёт каппа Коэна, для группы – Флейсс или Криппендорф. Используйте разные типы моделей и делайте такую проверку каждый месяц.
- Оценивайте нагрузку правильно: смотрите TTFT, ITL и goodput на реальном смешанном трафике. Не стоит опираться только на RPS или среднюю задержку – они не дают полной картины.

И ещё про ожидания. Нельзя выстроить весь контур за один спринт. Часто первые честные замеры показывают результаты хуже тех, к которым команда привыкла. Не пугайтесь: это не значит, что качество упало. Просто раньше вы не видели всей картины, а теперь видите. Именно с этого обычно и начинается реальный прогресс.
Если у вас уже работает LLM-агент или RAG-система, самое время проверить её на реальных сценариях. Мы поможем разобраться, где именно возникают ошибки: в данных, поиске, промпте, генерации или под нагрузкой. Оценим качество вашей ИИ-системы, найдём слабые места и поможем выстроить понятный процесс тестирования. Первая консультация — бесплатно.
- Barnett S. et al. Seven Failure Points When Engineering a Retrieval Augmented Generation System, CAIN 2024 — arxiv.org/abs/2401.05856 ↩︎
- Liu N. et al. Lost in the Middle: How Language Models Use Long Contexts — arxiv.org/abs/2307.03172 ↩︎
- Chroma Research. Context Rot: How Increasing Input Tokens Impacts LLM Performance — research.trychroma.com/context-rot ↩︎
- Zheng L. et al. Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena — arxiv.org/abs/2306.05685 ↩︎
- OWASP Top 10 for LLM Applications — genai.owasp.org. Инструменты red team: garak, PyRIT, promptfoo ↩︎
Дополнительный список литературы:
- Фреймворки оценки: RAGAS, DeepEval, TruLens (RAG Triad), Giskard. Трассировка — Langfuse, Arize Phoenix
- Детекция галлюцинаций: HHEM и лидерборд Vectara, SelfCheckGPT, FActScore, RefChecker, G-Eval
- Производительность: vLLM benchmark_serving, NVIDIA AIPerf, GuideLLM, Яндекс.Танк
- Русскоязычный контур: MERA (включая MERA Industrial и MERA Code), gigaragas, ruMTEB, LLM Arena
- Регулирование: приказ ФСТЭК России от 11.04.2025 № 117 (в силе с 01.03.2026); стандарты ТК 164 «Искусственный интеллект»; ГОСТ Р 56939-2024; ISO/IEC 42001; NIST AI RMF. Формулировки проверяйте по действующим редакциям
Тренды и фишки из мира IT,
экспертные статьи и всё о тестировании.










