Тестирование приложения на LLM - проверка программы, в которой часть результата создаёт большая языковая модель (large language model, LLM): ответ пользователю, классификацию, извлечённые данные, решение вызвать инструмент. Код вокруг модели проверяют обычными тестами. Поведение модели измеряют наборами оценок: фиксированными задачами с ожидаемым итогом, которые запускают многократно и проверяют кодом, другой моделью или людьми.
Международного стандарта, который описывал бы метод тестирования приложений на LLM, нет. Понятия и практики взяты из научных статей и документации поставщиков моделей. Метод оценки ответов моделью-судьёй исследован в статье «Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena» (Zheng и соавторы, июнь 2023 года). Anthropic описывает оценку в руководстве «Define success criteria and build evaluations» и в инженерной статье «Demystifying evals for AI agents» (9 января 2026). Силлабус ISTQB Certified Tester AI Testing (CT-AI), выпущенный в октябре 2021 года, охватывает тестирование систем на основе ИИ в целом.
Какую задачу решает
Классический тест предполагает, что одинаковый вход даёт одинаковый выход, а ожидаемый результат можно записать заранее. Приложение на LLM нарушает оба допущения: два правильных ответа могут быть сформулированы по-разному, а один и тот же запрос при двух запусках может дать разные ответы.
Поведение меняется и без изменений в коде. Новая формулировка системного промпта, новая версия модели или новый документ в базе знаний могут улучшить одну группу ответов и сломать другую. Ручная проверка нескольких запросов в окне чата этого не покажет.
Тестирование приложения на LLM отделяет то, что можно проверить точно, от того, что можно только измерить. Код покрывают детерминированными тестами. Поведение модели измеряют на фиксированном наборе задач, а результаты двух версий сравнивают как доли успешных попыток.
Из чего состоит приложение на LLM
В таблице - части приложения на LLM и их типичные дефекты.
| Часть | Что делает | Типичные дефекты |
|---|---|---|
| Промпт | Системный промпт, инструкции, примеры, шаблоны | Неоднозначные инструкции, противоречащие правила, не учтённые граничные случаи |
| Модель | Создаёт ответ | Неверные факты, проигнорированные инструкции, другое поведение после обновления |
| Поиск | Находит документы для контекста | Нерелевантные или устаревшие документы, нужного документа нет |
| Инструменты | Функции, которые вызывает модель | Не тот инструмент, неверные аргументы, лишние вызовы |
| Разбор ответа | Превращает ответ в данные | Невалидный JSON, нет полей, неожиданные значения |
| Ограничители | Фильтры входа и выхода, проверки политик | Вредный контент проходит, допустимые запросы блокируются |
Поиск лежит в основе генерации с дополнением найденными данными (retrieval-augmented generation, RAG), описанной Lewis и соавторами (2020): приложение помещает найденные документы в контекст модели. Неверный ответ тогда может быть ошибкой модели или поиска, и отдельный тест поиска с ожидаемыми документами для каждого запроса показывает, что именно отказало.
Недетерминированность
Сэмплирование и температура
Языковая модель вычисляет вероятность каждого возможного следующего токена и выбирает один из этого распределения случайно. Параметр «температура» (temperature) управляет тем, насколько распределение плоское: высокая температура делает маловероятные токены вероятнее, низкая сосредотачивает выбор на самых вероятных.
В API OpenAI температура - число от 0 до 2, по умолчанию 1. Глоссарий Anthropic указывает, что даже при температуре 0 результаты не полностью детерминированы и одинаковые входные данные могут дать разные ответы при разных вызовах API.
Seed
В OpenAI Chat Completions API есть параметр seed: при одинаковых seed и параметрах система старается выбирать токены детерминированно, но без гарантии. Параметр помечен как бета-функция и как устаревший, как и поле system_fingerprint, которое сообщало об изменениях на стороне сервера. В более новом Responses API параметра seed нет.
Причины вне сэмплирования
Статья Thinking Machines Lab «Defeating Nondeterminism in LLM Inference» (Horace He, 10 сентября 2025) объясняет, почему температуры 0 недостаточно: вычисления зависят от размера пакета (batch), в котором сервер обрабатывает запрос, а размер пакета - от нагрузки со стороны других пользователей. В эксперименте из статьи с открытой моделью Qwen3-235B 1000 генераций одного промпта при температуре 0 дали 80 разных текстов. С ядрами, не зависящими от размера пакета, все 1000 совпали, ценой более медленного вывода.
Страница Anthropic об идентификаторах моделей называет ещё одну причину. Веса за идентификатором модели неизменны, но окружающая инфраструктура может меняться: маршрутизатор запросов, классификаторы безопасности, логика сэмплирования. Такие обновления могут давать небольшие различия в поведении при том же идентификаторе.
Что детерминировано
Таблица делит части приложения по тому, повторяется ли их результат.
| Детерминировано | Не детерминировано |
|---|---|
| Шаблоны промптов и их подстановка | Текст, созданный моделью |
| Парсеры, валидаторы, бизнес-правила | Выбор инструмента и его аргументов |
| Обработчики инструментов при заданных аргументах | Формулировка, длина и порядок ответа |
| Поиск по фиксированному индексу для фиксированного вектора запроса | Вердикты модели-судьи |
Левую колонку проверяют обычными тестами, правую измеряют наборами оценок.
Наборы оценок
Набор оценок (evaluation set, eval) - фиксированный набор задач с входными данными и ожидаемым итогом вместе с оценщиками, которые проверяют каждый ответ, и метриками, которые сводят результаты. Он играет роль набора тестов: на каждой версии запускается один и тот же набор.
Критерии успеха
Оценка начинается с критериев успеха. Руководство Anthropic требует критериев конкретных, измеримых, достижимых и относящихся к делу: «хорошая работа» - не критерий, «F1 не ниже 0,85 на отложенных сообщениях» - критерий. Большинству приложений нужно несколько критериев: точность выполнения задачи, согласованность, тон, сохранение конфиденциальности, задержка, цена.
Задачи и ожидаемый итог
Задача содержит входные данные, нужный ей контекст и ожидаемый итог. Ожидаемый итог - не всегда одна строка. Это может быть метка, значение, список фактов, которые ответ должен или не должен содержать, или состояние системы после запуска. Пример показывает одну задачу; имена полей произвольные.
{
"id": "returns-policy-004",
"input": "Can I return a laptop 40 days after delivery?",
"context_documents": ["policies/returns-v3.md"],
"expected": {
"label": "not_eligible",
"must_mention": ["30 days"],
"must_not_call": ["issue_refund"]
},
"graders": ["json_schema", "exact_label", "tool_calls", "rubric_judge"],
"tags": ["returns", "edge-case"]
}Руководство Anthropic даёт три принципа для набора: задачи повторяют реальное распределение запросов и включают граничные случаи, проверку можно автоматизировать, объём важнее качества.
Оценщики
Оценщик - логика, которая оценивает одну сторону ответа. Статья «Demystifying evals» делит оценщиков на три вида; в таблице - их сильные и слабые стороны, как они названы в статье.
| Оценщик | Сильные стороны | Слабые стороны |
|---|---|---|
| Код | Быстро, дёшево, объективно, воспроизводимо | Отвергает допустимые варианты, не видит нюансов |
| Модель | Гибко, масштабируется, работает со свободным текстом | Недетерминирован, дороже, нужна калибровка |
| Человек | Эталонное качество, экспертное суждение | Медленно, дорого, трудно масштабировать |
У задачи часто несколько оценщиков. Сначала идут дешёвые проверки кодом, затем оценщик-модель проверяет то, что код проверить не может: правильность по существу, полноту, тон.
Метрики
Ответы различаются, поэтому каждую задачу запускают в нескольких попытках, и результат задачи - доля успешных попыток, а не один вердикт. Метрики pass@k и pass^k для повторных попыток и статистика малых выборок описаны в статье Оценка MCP-сервера на моделях. Метрики классического тестирования, такие как доля пройденных тестов и её знаменатели, описаны в статье Метрики тестирования.
Детерминированные проверки
Ответ модели случаен, но правила, которым он должен следовать, - нет, и многие из них проверяются точно.
- Схема. Ответ - валидный JSON и соответствует JSON Schema.
- Точное совпадение. Метка, число или идентификатор после нормализации равны ожидаемому значению.
- Правила для подстрок. Ответ содержит обязательную фразу или не содержит запрещённую.
- Вызовы инструментов. Модель вызвала нужный инструмент и не вызвала запрещённый.
- Состояние. После запуска система в ожидаемом состоянии.
Пример ниже реализует несколько таких проверок на Python с библиотекой jsonschema. Функция возвращает список ошибок; пустой список означает, что задача прошла детерминированные проверки.
import json
import jsonschema
ANSWER_SCHEMA = {
"type": "object",
"properties": {
"label": {"enum": ["eligible", "not_eligible", "unknown"]},
"answer": {"type": "string"},
},
"required": ["label", "answer"],
"additionalProperties": False,
}
def check_answer(raw_output: str, expected_label: str, tool_calls: list[dict]) -> list[str]:
try:
answer = json.loads(raw_output)
except json.JSONDecodeError as error:
return [f"not JSON: {error}"]
try:
jsonschema.validate(answer, ANSWER_SCHEMA)
except jsonschema.exceptions.ValidationError as error:
return [f"schema: {error.message}"]
failures = []
if answer["label"] != expected_label:
failures.append(f"label: {answer['label']} != {expected_label}")
called = [call["name"] for call in tool_calls]
if "search_policy" not in called:
failures.append("search_policy was not called")
if "issue_refund" in called:
failures.append("issue_refund must not be called")
return failuresAPI моделей могут обеспечить часть этого уже при генерации. Структурированный вывод Anthropic использует ограниченное декодирование, чтобы ответ следовал JSON Schema из output_config.format; у OpenAI есть формат ответа json_schema. Документация Anthropic перечисляет случаи, когда ответ всё равно может не совпасть со схемой: отказ модели и ответ, обрезанный по max_tokens. Поэтому проверка схемы остаётся в тестах.
LLM-as-judge
Виды судей
LLM-as-judge (модель-судья) - проверка, при которой языковая модель оценивает ответы приложения по инструкции. Статья Zheng и соавторов описывает три варианта:
- Попарное сравнение. Судья видит вопрос и два ответа и выбирает лучший или объявляет ничью.
- Оценка одного ответа. Судья ставит оценку одному ответу.
- Оценка по эталону. Судья получает эталонный ответ; это помогает, например, с математическими задачами.
По данным статьи, GPT-4 в роли судьи согласовывался с предпочтениями людей более чем в 80 процентах случаев, на том же уровне, на каком согласуются между собой люди.
Известные смещения
Та же статья описывает систематические ошибки моделей-судей. Таблица сводит их с числами, полученными для моделей 2023 года.
| Смещение | Что происходит | Результат в статье |
|---|---|---|
| Смещение позиции (position bias) | Судья предпочитает ответ из-за его места | GPT-4 дал тот же вердикт после перестановки ответов в 65 процентах случаев |
| Смещение многословия (verbosity bias) | Судья предпочитает более длинные ответы | Ответы, раздутые повторами, обманули Claude-v1 и GPT-3.5 в 91,3 процента случаев, GPT-4 - в 8,7 процента |
| Самопредпочтение (self-enhancement bias) | Судья предпочитает ответы своей модели | GPT-4 завышал свою долю побед примерно на 10 процентов, Claude-v1 - примерно на 25; авторы считают данных недостаточно, чтобы подтвердить смещение |
| Ограниченные рассуждения | Судья неверно оценивает ответы по математике и логике | Судей сбивали с толку оцениваемые ответы |
Статья предлагает меры против этого. Пару оценивают дважды с переставленными ответами, и победа засчитывается, только если оба вердикта совпали. Примеры в промпте судьи подняли согласованность GPT-4 до 77,5 процента, а эталонный ответ снизил долю ошибок на математических вопросах с 70 до 15 процентов.
Рубрики
Рубрика (rubric) - набор критериев и допустимых вердиктов, по которым судья оценивает ответ. Руководство Anthropic даёт три правила: рубрика подробная и ясная, судья возвращает ограниченный результат, например «correct» или «incorrect» или оценку от 1 до 5, и судья рассуждает до того, как поставить оценку. Руководство также рекомендует проверять ответ другой моделью, не той, что его создала.
Статья «Demystifying evals» добавляет два правила: судья может ответить «Unknown», если информации недостаточно, и каждую сторону ответа оценивает отдельный изолированный судья.
Калибровка по оценкам людей
Судья - измерительный инструмент, и его проверяют как инструмент: люди размечают выборку ответов по той же рубрике, судья оценивает те же ответы, вердикты сравнивают. Статья требует, чтобы судьи были тщательно откалиброваны по экспертам-людям; после этого достаточно периодической проверки людьми.
В примере 200 ответов размечены людьми и судьёй.
| Судья: пройден | Судья: не пройден | |
|---|---|---|
| Люди: пройден | 120 | 10 |
| Люди: не пройден | 20 | 50 |
Простое совпадение - (120 + 50) / 200 = 85 процентов. Часть его ожидается случайно, и каппа Коэна (Cohen, 1960) делает поправку: kappa = (p_o - p_e) / (1 - p_e), где p_o - наблюдаемое совпадение, а p_e - совпадение, ожидаемое по долям каждого вердикта. Здесь p_e = 0,65 x 0,70 + 0,35 x 0,30 = 0,56, и kappa = (0,85 - 0,56) / 0,44, около 0,66.
Кроме того, судья пропустил 20 из 70 ответов, которые люди не приняли, то есть 29 процентов. Это более опасная ошибка, и рубрику дорабатывают на этих 20 ответах, прежде чем использовать судью.
Проверка людьми
Люди пишут ожидаемые итоги и рубрики, размечают выборку для калибровки и читают стенограммы. Статья «Demystifying evals» указывает, что оценкам не доверяют, пока кто-то не прочитал стенограммы попыток: неудача может быть ошибкой оценщика, а не приложения.
Проверку людьми используют и там, где других надёжных оценщиков нет, например для юридического или медицинского содержания. Руководство Anthropic называет её самым гибким методом и рекомендует по возможности обходиться без неё, потому что она медленная и дорогая.
Регресс после смены модели или промпта
Версии моделей
Поставщики публикуют модели под идентификаторами, которые фиксируют версию. Снимок модели (model snapshot) - такая зафиксированная версия модели под собственным идентификатором. На платформе Anthropic каждый идентификатор модели обозначает закреплённую версию с неизменными весами; у старых моделей идентификаторы с датой, например claude-sonnet-4-5-20250929, и псевдонимы, которые переходят на новейший снимок. OpenAI тоже указывает идентификаторы с датой, например o3-2025-04-16.
Закреплённую версию выводят из эксплуатации после срока уведомления: не менее 60 дней у Anthropic для публично выпущенных моделей, не менее 6 месяцев у OpenAI для общедоступных моделей. Вывод из эксплуатации вынуждает сменить модель, и регрессионный запуск для этого планируют заранее.
Закреплённый идентификатор модели фиксирует веса, но не всё поведение. Anthropic указывает, что изменения инфраструктуры могут давать небольшие различия при том же идентификаторе, поэтому регрессионный набор запускают и по расписанию, а не только после изменений.
Версии промптов и фиксированный набор
Промпт версионируют вместе с кодом. Каждый запуск оценки записывает всё, что влияет на ответ: версию промпта, идентификатор модели, параметры, поисковый индекс, определения инструментов и оценщиков. Без этой записи два запуска нельзя сравнить.
Статья «Demystifying evals» разделяет две цели. Оценка возможностей (capability evaluation) измеряет то, что приложение пока делает плохо, и её доля успеха поначалу низкая. Регрессионная оценка (regression evaluation) проверяет то, что уже работало, и её доля успеха держится около 100 процентов. Задачи, которые стабильно проходят, переводят из первого набора во второй.
Сравнение запусков
Изменение принимают после сравнения двух запусков на тех же задачах, с теми же оценщиками и тем же числом попыток. Сравнивают по каждой задаче: неизменный итог может скрывать десять сломанных задач и десять улучшенных. Сравнивают также токены, задержку и вызовы инструментов.
Регресс инструментов, которыми приложение пользуется через Model Context Protocol, описан в статье Регрессионное тестирование MCP-сервера. Атаки через инструкции, спрятанные во входных данных, - отдельный вид тестов, он описан в статье Prompt injection.
Классические программы и приложения на LLM
Таблица сравнивает тестирование классических программ и приложений на LLM.
| Классическая программа | Приложение на LLM | |
|---|---|---|
| Выход при том же входе | Тот же | Меняется от запуска к запуску |
| Ожидаемый результат | Точное значение | Метка, факты, рубрика, состояние |
| Вердикт теста | Пройден или не пройден | Доля успешных попыток |
| Оценщик | Проверка в коде | Код, модель, человек |
| Причина регресса | Изменение кода | Изменение кода, промпта, модели, данных |
| Стоимость запуска | Секунды, без модели | От минут до часов, расход модели |
В одном приложении сочетаются оба вида тестирования. Детерминированные части проверяют как любой код при каждом изменении. Набор оценок запускают при смене промпта, модели или данных и по расписанию.
Недетерминированный результат - не то же самое, что нестабильный тест: нестабильный тест падает из-за дефекта в тесте или окружении и его исправляют, а разброс ответов модели - свойство системы, и его измеряют. Нестабильные тесты описаны в статье Нестабильные тесты.
Термины
| Термин | Значение |
|---|---|
| Приложение на LLM | Программа, в которой часть результата создаёт большая языковая модель |
| Набор оценок (eval) | Фиксированный набор задач с ожидаемым итогом, оценщиками и метриками |
| Температура (temperature) | Параметр сэмплирования, который управляет случайностью выбора следующего токена |
| LLM-as-judge | Проверка, при которой языковая модель оценивает ответы по инструкции |
| Рубрика (rubric) | Набор критериев и допустимых вердиктов, по которым судья оценивает ответ |
| Смещение позиции (position bias) | Склонность модели-судьи предпочитать ответ из-за его места |
| Каппа Коэна (Cohen's kappa) | Мера согласия двух оценщиков с поправкой на случайное совпадение |
| Снимок модели (model snapshot) | Зафиксированная версия модели под собственным идентификатором |
Источники
- Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena, L. Zheng et al., arXiv:2306.05685, NeurIPS 2023(откроется в новой вкладке) (на английском)
- Define success criteria and build evaluations, документация Claude Platform(откроется в новой вкладке) (на английском)
- Demystifying evals for AI agents, Anthropic, 9 января 2026(откроется в новой вкладке) (на английском)
- Glossary: Temperature, документация Claude Platform(откроется в новой вкладке) (на английском)
- Model IDs and versions, документация Claude Platform(откроется в новой вкладке) (на английском)
- Model deprecations, документация Claude Platform(откроется в новой вкладке) (на английском)
- Structured outputs, документация Claude Platform(откроется в новой вкладке) (на английском)
- Create chat completion, справочник OpenAI API(откроется в новой вкладке) (на английском)
- Deprecations, документация OpenAI API(откроется в новой вкладке) (на английском)
- Defeating Nondeterminism in LLM Inference, H. He, Thinking Machines Lab, 10 сентября 2025(откроется в новой вкладке) (на английском)
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, P. Lewis et al., arXiv:2005.11401(откроется в новой вкладке) (на английском)
- A Coefficient of Agreement for Nominal Scales, J. Cohen, Educational and Psychological Measurement, 1960(откроется в новой вкладке) (на английском)
- ISTQB releases Certified Tester AI Testing (CT-AI), ISTQB, октябрь 2021(откроется в новой вкладке) (на английском)
- jsonschema: Schema Validation, документация библиотеки Python(откроется в новой вкладке) (на английском)