Интеграция DeepEval для тестирования LlamaIndex Workflow

3139c0d7304e7676736a34787bc2f42a.png

Введение

Тестирование сложных систем, таких как LlamaIndex Workflow, включающих несколько шагов, извлечение данных и генерацию текста с помощью LLM, является нетривиальной задачей. Стандартные методы тестирования не всегда могут оценить семантическое качество и релевантность генерируемых ответов. DeepEval предоставляет набор инструментов и метрик, специально разработанных для оценки LLM-приложений, что делает его подходящим решением для тестирования LlamaIndex Workflow.

В ходе исследования были рассмотрены два основных подхода к интеграции DeepEval:

  1. Прямое использование DeepEval:  Оценка результатов Workflow с помощью функции deepeval.evaluate () в обычном Python-скрипте.

  2. Интеграция с Pytest:  Использование deepeval.assert_test () в рамках тестового фреймворка Pytest для автоматической проверки соответствия метрик заданным порогам и интеграции с CI/CD.

В качестве примера использовался тестовый Workflow на базе LlamaIndex, реализующий простой RAG Workflow с моками Retriever и LLM, и оценивающий финальный результат с помощью метрик AnswerRelevancy и Faithfulness.

Подход 1: Прямое использование DeepEval (evaluate)

Этот подход фокусируется на получении оценок и их анализе без привязки к стандартным тестовым фреймворкам.

  • Процесс:

    1. Запускается LlamaIndex Workflow для конкретного входного запроса (await workflow.run (input_query=…)).

    2. Из финального события Workflow (например,  RagWorkflowOutput) извлекаются необходимые данные:  input (исходный запрос),  actual_output (сгенерированный ответ),  retrieval_context (извлеченный контекст).

    3. Создается экземпляр deepeval.test_case.LLMTestCase, заполненный этими данными.

    4. Определяются необходимые метрики DeepEval (например,  AnswerRelevancyMetric,  FaithfulnessMetric) с их порогами.

    5. Вызывается функция deepeval.evaluate (test_cases=[test_case], metrics=[list_of_metrics]).

  • Пример кода:

    # ... (после получения final_event из workflow.run)
    test_case = LLMTestCase(
        input=final_event.original_query,
        actual_output=final_event.final_answer,
        retrieval_context=final_event.retrieved_context
    )
    answer_relevancy_metric = AnswerRelevancyMetric(threshold=0.7)
    faithfulness_metric = FaithfulnessMetric(threshold=0.8)
    evaluation_results = evaluate(
        test_cases=[test_case],
        metrics=[answer_relevancy_metric, faithfulness_metric]
    )
    print(evaluation_results) # Вывод результатов
    # ... (добавлен код для детальной распечатки evaluation_results.test_results)
  • Результат:

    • В консоль выводится прогресс-бар, сводка по метрикам (название, оценка, порог, статус ✅/❌, причина) и общие показатели Pass Rate.

    • Если пользователь залогинен (deepeval login), результаты оценки (включая детали тест-кейса и метрик) автоматически отправляются на дашборд Confident AI для хранения, визуализации и сравнения между запусками.

    • Функция evaluate возвращает объект EvaluationResult, содержащий структурированные данные по всем оценкам.

  • Преимущества:

    • Простота реализации в обычном скрипте.

    • Наглядный вывод результатов в консоль.

    • Автоматическая отправка данных на дашборд для анализа.

    • Хорошо подходит для исследовательских целей, ручной проверки качества и первоначальной настройки метрик.

  • Недостатки для автоматизации:

    • Функция evaluate не прерывает выполнение скрипта и не возвращает код ошибки, даже если какие-то метрики не прошли проверку по порогу (success=False).

    • Для интеграции с CI/CD (автоматического определения «сборка прошла/не прошла») требуется дополнительная логика в скрипте: нужно вручную анализировать возвращенный объект evaluation_results, проверять поле success у каждой метрики и явно завершать скрипт с ненулевым кодом выхода (sys.exit (1)) или вызывать исключение при обнаружении проваленной метрики.

Подход 2: Интеграция с Pytest (assert_test)

Этот подход встраивает оценку DeepEval в стандартный процесс тестирования с использованием фреймворка Pytest, что идеально подходит для автоматизации и CI/CD.

  • Процесс:

    1. Тестовая логика (запуск Workflow, подготовка LLMTestCase, определение метрик) оборачивается в тестовую функцию Pytest (например,  async def test_workflow_evaluation (…), помеченную @pytest.mark.asyncio).

    2. Вместо evaluate (…) используется функция deepeval.assert_test (test_case, [list_of_metrics]).

    3. Тесты запускаются через команду deepeval test run <имя_файла_с_тестами>.py (которая использует Pytest под капотом).

  • Пример кода:

    import pytest
    
    @pytest.mark.asyncio
    async def test_rag_workflow_with_deepeval(): # Название функции для pytest
        # ... (код запуска Workflow и создания test_case - как раньше) ...
    
        answer_relevancy_metric = AnswerRelevancyMetric(threshold=0.7)
        faithfulness_metric = FaithfulnessMetric(threshold=0.8)
    
        # Вместо evaluate используем assert_test
        assert_test(test_case, [answer_relevancy_metric, faithfulness_metric])
    
        # Если assert_test не вызвал ошибку, тест считается пройденным
        print("DeepEval assert_test evaluation completed successfully!")
  • Результат:

    • assert_test вычисляет все переданные метрики.

    • Она сравнивает score каждой метрики с ее threshold.

    • Ключевое отличие:  Если хотя бы одна метрика не проходит проверку по порогу (score < threshold), assert_test вызывает исключение AssertionError.

    • Pytest перехватывает это AssertionError и помечает тест как проваленный (FAILED).

    • Если все метрики прошли проверку,  AssertionError не вызывается, и Pytest помечает тест как пройденный (PASSED).

    • При запуске через deepeval test run, результаты (статус PASS/FAIL, детали метрик) также отправляются на дашборд Confident AI в виде «Test Run».

  • Преимущества:

    • Полная автоматизация CI/CD:  Проваленный тест (из-за AssertionError) автоматически приводит к ненулевому коду выхода, что сигнализирует CI/CD системе о проблеме без необходимости писать дополнительную логику проверки результатов.

    • Использование возможностей Pytest:  Легко применять фикстуры (для инициализации Workflow, LLM, Retriever), параметризацию (для запуска одного теста на множестве входных данных), маркировку тестов и т.д.

    • Структурированное тестирование:  Позволяет организовать тесты в понятную структуру.

    • Единый запуск и отчетность:  Команда deepeval test run запускает все тесты и формирует единый отчет на Confident AI.

  • Недостатки:

    • Требует базового понимания Pytest.

    • Стандартный вывод Pytest фокусируется на статусе PASS/FAIL, а не на немедленной детальной распечатке метрик (хотя они доступны в отчете на дашборде).

Сравнение и рекомендации

Характеристика

Подход 1 (evaluate)

Подход 2 (assert_test + Pytest)

Основная цель

Оценка, логирование, анализ результатов

Автоматическая проверка Pass/Fail

CI/CD Интеграция

Требует доп. логики для Pass/Fail

Встроенная (через AssertionError)

Запуск

python script.py

deepeval test run script.py

Вывод в консоль

Подробная сводка метрик

Статус PASS/FAIL (детали — в отчете)

Отправка на дашборд

Да (как Evaluation Run)

Да (как Test Run)

Структура тестов

Отсутствует (обычный скрипт)

Предоставляется Pytest

Простота

Выше для простых сценариев

Требует знания Pytest

Рекомендации:

  • Используйте Подход 1 (evaluate), когда вы:

    • Только начинаете интегрировать DeepEval и хотите исследовать метрики.

    • Проводите ручную оценку или отладку конкретных кейсов.

    • Не используете CI/CD или готовы написать свою логику для определения Pass/Fail статуса пайплайна.

  • Используйте Подход 2 (assert_test + Pytest), когда вы:

    • Хотите построить автоматизированный набор регрессионных тестов.

    • Нуждаетесь в интеграции с CI/CD для автоматической проверки качества при изменениях.

    • Хотите использовать возможности тестовых фреймворков (фикстуры, параметризация) для организации тестов.

    • Планируете регулярно запускать тесты и сравнивать результаты прогонов на дашборде.

Заключение

DeepEval предоставляет мощные возможности для оценки качества LlamaIndex Workflow, выходя за рамки традиционного тестирования. Прямое использование функции evaluate удобно для анализа и логирования, в то время как интеграция с Pytest через assert_test и запуск с помощью deepeval test run открывают путь к полной автоматизации тестирования и интеграции в CI/CD пайплайны, что является предпочтительным подходом для поддержания качества сложных LLM-систем в долгосрочной перспективе.

© Habrahabr.ru