🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 18.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks
Каждая команда разработчиков, выпускающая функции ИИ, сталкивается с одной и той же проблемой: как убедиться, что LLM обеспечивают стабильное качество в производственной среде? Решение — автоматизированные тесты.
Распространенная идея заключается в попытке зафиксировать температуру на уровне 0, чтобы получить более детерминированные результаты. Это ошибка. Температура влияет на качество выходных данных, а не только на случайность, и 0 не означает «детерминированность». Поэтому ваши тесты будут некорректными и по-прежнему нестабильными. В настоящее время нет способа получить полностью детерминированные результаты ни от одной из ведущих LLM-систем.
У вас также может возникнуть соблазн имитировать вызовы LLM. Это позволит вашим тестам пройти успешно, но сделает их бесполезными. Вы проверяете, возвращает ли ваша имитация то, что вы ей указали вернуть. Вы ничего не узнаете о том, действительно ли ваша функция работает.
Есть способ получше. Прекратите пытаться сделать недетерминированный результат детерминированным. Вместо этого разделите то, что можно проверить детерминированно, от того, что можно оценить только с помощью разумного эксперта, и используйте один и тот же язык утверждений для обоих случаев.
Комплекс Riteway был построен именно для решения этой проблемы.
Единая стратегия тестирования функций ИИ
Основная идея: большая часть кода, связанного с функцией ИИ, детерминирована. Проверка входных данных. Анализ выходных данных. Обработка ошибок. Защитные механизмы. Соблюдение схемы. Логика маршрутизации. Формирование вызовов инструментов.
Проверяйте всё это так, как вы всегда это делали: с помощью быстрых, детерминированных модульных тестов, создаваемых и запускаемых агентом ИИ по мере компиляции кода.
С другой стороны, результаты работы модели отличаются. Они носят вероятностный характер. Нельзя утверждать об абсолютном равенстве, но можно оценить качество по критериям, используя другую модель в качестве эталона.
Riteway предоставляет вам оба уровня, используя один и тот же given/should словарь для обоих, поэтому у вас есть единая ментальная модель, которая масштабируется от чистых функций до агентов искусственного интеллекта.
Почему именно Riteway?
В основе Riteway лежит простое наблюдение: каждый модульный тест должен ответить на пять вопросов :
- Что именно тестируется?
- Что оно должно делать?
- Каков был фактический результат?
- Каков был ожидаемый результат?
- Как воспроизвести ошибку?
API Riteway заставляет вас ответить на все пять вопросов. Каждое утверждение имеет следующую форму:
assert({
given: 'the current situation',
should: 'describe the expected behavior',
actual: result,
expected: expectedResult
});
Эта структура важна по трем причинам:
- Функциональные требования становятся тестами. Поля
`<description> given`и`<description> should`написаны простым языком. Они документируют то, что делает код. Если вы пишете требования в форматеgiven `<description>` should, вы можете использовать их непосредственно в своих тестах. - Эффективное использование токенов. Когда ИИ-агент пишет или читает ваши тесты, каждый токен имеет значение. Минимальная площадь поверхности Riteway означает меньше шума в контекстном окне. Меньше концепций фреймворка, которые могут запутать модель. Только один тип утверждений означает, что он всегда выбирает правильный.
- Читаемость кода заложена в самой концепции. Тесты читаются как предложения.
Given an LLM response missing a required field, should throw a SchemaError. Начинающий разработчик может понять замысел, даже не изучая фреймворк.
Уровень 1: Детерминированные модульные тесты для символического кода
Ваши модульные тесты проверяют все структурные требования, которым должны соответствовать выходные данные модели. Рассматривайте это как проверку формы и границ отклика, а не его содержания. Это чистые функции: детерминированные, без побочных эффектов и легко тестируемые.
Что следует проверять детерминистически:
- Логика программы и переходы состояний. Ваш код делает то, что должен? Условные переходы, циклы, преобразования данных, решения о маршрутизации. Протестируйте его, как любую другую функцию: при заданных входных данных он должен выдавать заданные выходные данные.
- Соответствие схеме. Проходит ли ответ проверку валидатора схемы? Вызовите функцию
validateSummaryResponseи убедитесь, что она возвращает корректный ответ. Избегайте ручной проверки типов полей. - Проверка входных данных. Проходят ли пользовательские данные проверку перед тем, как попасть в модель или базу данных?
- Возможные причины ошибок: тайм-ауты, ограничения скорости запросов, пустые ответы, некорректный JSON. Обрабатывает ли ваш код каждую из этих ошибок корректно?
- Ограничения. Отлавливает ли ваш выходной фильтр запрещенный контент? Работает ли ваш механизм контроля бюджета токенов?
- Структура вызова инструментов. Если ваш агент вызывает инструменты, содержит ли вызов инструмента правильное имя функции и схему аргументов?
Вот как выглядит модульный тест в Riteway:
import { describe, Try } from 'riteway';
import { validateSummaryResponse } from './validate';
describe('summarizeDocument', async assert => {
const result = await summarizeDocument(sampleDocument);
assert({
given: 'a valid document',
should: 'return a valid response',
actual: validateSummaryResponse(result).isValid,
expected: true
});
assert({
given: 'empty input',
should: 'throw an empty_input error',
actual: Try(summarizeDocument, '').message,
expected: 'empty_input'
});
});
Обратите внимание, что эти тесты НЕ проверяют, действительно ли краткое содержание хорошее. Они проверяют структуру и логику. Качество контента — это задача второго уровня.
Модульные тесты лучше всего подходят для чистых функций и детерминированного кода.
Чистая функция — это функция, удовлетворяющая следующим законам:
- Детерминированность: при одинаковых аргументах функция всегда возвращает один и тот же результат, и…
- Отсутствие побочных эффектов. Побочным эффектом считается любое изменение состояния, видимое вне функции, за исключением возвращаемого значения функции.
В коде следует по возможности отдавать предпочтение чистым функциям, а чистую логику не следует смешивать с такими эффектами, как сетевой ввод-вывод или задачи рендеринга для улучшения пользовательского опыта.
Код, обрабатывающий переходы состояний приложения, проверяющий форму ответа LLM, анализирующий вызовы инструментов, обеспечивающий соблюдение защитных механизмов и обрабатывающий ошибки, может состоять в основном из чистых функций и тестируется с помощью простых модульных тестов. Никакого мокирования модели. Никаких нестабильных утверждений. Только входные данные и ожидаемые выходные данные.
Эти тесты запускаются при каждом изменении. Код без операций ввода-вывода должен работать очень быстро. Набор тестов, содержащий тысячи тестов, может выполниться за 1–3 секунды. Цель — достичь примерно 80% покрытия кода модульными тестами. Выделите небольшие, чисто вспомогательные функции и тестируйте их независимо от кода, который они обслуживают. Это также поможет вам создать библиотеку многократно используемого кода.
Уровень 2: Экспресс-оценка с помощью Riteway AI
В ходе проверки с помощью подсказок оценивается фактическое содержание высказывания модели, чтобы обеспечить точность, актуальность, соответствие инструкциям, безопасность, тон и общее качество.
Интерфейс riteway ai командной строки выполняет проверку подсказок агента ИИ, используя тот же given/should шаблон утверждений, но оценивая их с помощью LLM вместо глубокой проверки на равенство. Утверждения записываются в .sudo файл:
import summarize-eval.sudo import document.md
userPrompt = """ Please summarize $document.md """ - Given a technical document, should produce a summary under 500 characters - Given a technical document, should capture all major points without fabrication - Given a technical document, should avoid filler and marketing language - Given a technical document, should use precise technical terminology
Запустите его:
riteway ai summarize-eval.sudo
По умолчанию Riteway AI выполняет 4 прохода для каждого утверждения, требует 75% успешного прохождения, использует агент Клод и отводит 300 секунд на каждый звонок агента. Каждая - Given ..., should ... строка становится независимым утверждением, подлежащим оценке. Агент-судья оценивает каждое утверждение по всем запускам.
Вы получаете отчет в формате TAP с показателями успешного прохождения каждого утверждения. Тот же формат вывода, что и у ваших модульных тестов. Та же модель мышления.
Настройте пороговое значение:
riteway ai summarize-eval .sudo --runs 10 --threshold 80
Оба слоя выдают TAP-сигнал. Оба используют given/should утверждения. Оба отвечают на одни и те же пять вопросов. Ваши модульные тесты доказывают работоспособность системы. Ваши оценки качества доказывают, что выходные данные действительно полезны.
Еда на вынос
Если вы внедряете функции ИИ, вам необходимы оба уровня. Модульные тесты доказывают работоспособность вашего кода. Оценка качества доказывает эффективность ваших запросов. Ни один из уровней сам по себе не является достаточным.
Riteway предоставляет вам и то, и другое с помощью одного словаря утверждений. Этот given/should шаблон также может использоваться в качестве документации функциональных требований. Модульные тесты и оценки ИИ говорят на одном языке.
Установите Riteway, напишите модульные тесты для одной функции ИИ, а затем создайте .sudo файл оценки для той же функции. Вы обнаружите проблемы, которые ваши текущие тесты не замечают.
Перевод статьи «Riteway: The AI-Native Testing Framework».