Настроить RAGAS evaluation pipeline с автоматическим запуском при каждом PR
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить RAGAS evaluation pipeline с автоматическим запуском при каждом PR
1. Цель задачи
Создать CI/CD-пайплайн на GitHub Actions, который при каждом Pull Request автоматически запускает оценку качества RAG-системы с помощью библиотеки RAGAS. Пайплайн должен генерировать читаемый отчёт (HTML + markdown) с метриками (faithfulness, answer relevancy, context precision, context recall) за время не более 5 минут для набора из 20–30 тестовых примеров. Дополнительно внедрить регрессионный тест: если хотя бы одна метрика падает ниже заданного порога относительно последнего main-релиза, CI должен завершиться с ошибкой.
Ключевой результат автоматизированный evaluation-пайплайн, который блокирует PR при деградации качества и предоставляет разработчику прозрачный отчёт за 5 минут.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| RAG-приложение (на Python) | Взять из examples/rag_app внутри этого репозитория (если нет — создать минимальный RAG на LangChain с FAISS и OpenAI API) |
| Тестовый набор вопросов + ground truth ответов | Использовать встроенный датасет из RAGAS: ragas.testset.synthesizer.generate (синтезировать 30 примеров) |
| Конфигурация CI (GitHub Actions) | Файл .github/workflows/eval.yml |
| Результаты baseline (main-ветка) | Сохранить в ragas_baseline.json рядом с кодом; обновлять при мерже в main |
Если нет реального инструмента — симулируем:
- Создайте папку
rag_app/с файлом rag.py, который реализует класс RAGEngine с методом answer(question: str) -> dict (текст ответа + список контекстов). - Используйте эмбеддинги OpenAI text-embedding-3-small и LLM gpt-4o-mini (дешёво и быстро).
- Для тестовых вопросов — запустите генератор RAGAS один раз вручную, сохраните в test_data.json.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Библиотека оценки | ragas (>=0.2.0) | Вычисление метрик faithfulness, answer_relevancy, context_precision, context_recall |
| RAG-фреймворк | LangChain (>=0.3.0) + FAISS | Построение минимального RAG |
| Язык | Python 3.11 | Основной язык скриптов |
| CI/CD | GitHub Actions | Автоматический запуск оценки на каждый PR |
| Формат отчёта | HTML (jinja2 шаблон) + Markdown | Визуализация метрик |
| Хранение baseline | JSON | Сравнение с предыдущим стабильным состоянием |
| Тестирование | pytest | Проверка корректности работы пайплайна |
4. Этапы выполнения
Этап 1: Подготовка окружения и минимального RAG (оценка 45 мин)
Действия
- Установите зависимости:
pip install ragas langchain langchain-openai faiss-cpu jinja2 pytest - Создайте структуру проекта:
. ├── rag_app/ │ ├── __init__.py │ └── rag.py # RAGEngine класс ├── eval/ │ ├── __init__.py │ ├── run_eval.py # скрипт запуска оценки │ └── report_template.html # шаблон отчёта ├── test_data.json # тестовые примеры (будет сгенерирован) ├── ragas_baseline.json # baseline метрики (создать пустым) └── .github/ └── workflows/ └── eval.yml - Реализуйте RAGEngine в
rag_app/rag.py:- Используйте OpenAIEmbeddings + FAISS для векторного поиска.
- Используйте ChatOpenAI(model="gpt-4o-mini") для генерации ответа.
- Метод answer(question) -> {"answer": str, "contexts": list[str]}.
Ожидаемый результат этапа
Рабочая RAG-система, принимающая вопрос и возвращающая ответ с контекстом. Успешный тест: python -c "from rag_app.rag import RAGEngine; eng = RAGEngine(); print(eng.answer('Что такое RAG?'))".
Этап 2: Генерация тестового набора и написание скрипта оценки (оценка 1 час)
Действия
-
Создайте скрипт
eval/prepare_testset.py, который:- Использует ragas.testset.synthesizer.Synthesizer для генерации 30 вопросов на основе документации (например, статьи из Wikipedia).
- Сохраняет результат в test_data.json (формат:
[{"question": ..., "ground_truth": ..., "contexts": ...}]). - Запустите скрипт однократно, результат закоммитьте.
-
Напишите
eval/run_eval.py:- Загружает test_data.json и baseline (ragas_baseline.json, если существует).
- Для каждого вопроса вызывает RAGEngine.answer() и собирает результаты.
- Вычисляет метрики RAGAS с использованием Evaluate:
from ragas import evaluate from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall # ... подготовка dataset ... result = evaluate(dataset, metrics=[faithfulness, ...]) - Генерирует HTML-отчёт (используя jinja2 и шаблон report_template.html) и JSON с метриками.
- Сравнивает каждую метрику с baseline: если drop > 0.05 (5%), выбрасывает исключение
RegressionError. - Сохраняет последний результат в ragas_latest.json (для артефактов CI).
-
Создайте шаблон report_template.html:
- Таблица с метриками (имя, текущее значение, baseline, дельта).
- Гистограмма распределения метрик по вопросам.
- Список топ-5 худших вопросов для каждой метрики.
Ожидаемый результат этапа
Выполнение python eval/run_eval.py проходит без ошибок и генерирует файлы report.html, ragas_latest.json.
Этап 3: Настройка регрессионного сравнения (оценка 30 мин)
Действия
-
В
run_eval.pyдобавьте логику:if baseline_exists: for metric_name in ["faithfulness", "answer_relevancy", "context_precision", "context_recall"]: current = result[metric_name] baseline = baseline[metric_name] if current < baseline - 0.05: raise RegressionError(f"Drop in {metric_name}: {current:.3f} vs {baseline:.3f}") -
При успешном проходе сохраните ragas_latest.json как новый baseline (но только после мержа в main – это будет сделано на этапе CI).
-
Протестируйте: искусственно ухудшите RAG (например, удалите один из контекстов) и убедитесь, что скрипт падает.
Ожидаемый результат этапа
Скрипт корректно обнаруживает регрессии и завершается с ненулевым кодом выхода.
Этап 4: Интеграция с GitHub Actions (оценка 1.5 часа)
Действия
-
Создайте
.github/workflows/eval.yml:name: RAGAS Evaluation on: pull_request: branches: [main] jobs: evaluate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.11 uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install dependencies run: pip install -r requirements.txt - name: Run evaluation run: python eval/run_eval.py env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Upload report uses: actions/upload-artifact@v4 with: name: eval-report path: | report.html ragas_latest.json - name: Comment PR uses: actions/github-script@v7 with: script: | const fs = require('fs'); const report = fs.readFileSync('report.html', 'utf8'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `## RAG Evaluation Report\n\n<details><summary>Metrics</summary>\n\n${report.substring(0, 30000)}\n\n</details>` }); -
Добавьте шаг
pytestдля проверки работоспособности вспомогательных функций. -
Протестируйте: сделайте PR с изменением кода RAG, убедитесь, что CI запускается, падает при регрессии и публикует отчёт.
Ожидаемый результат этапа
При каждом PR в main автоматически запускается оценка, отчёт загружается как артефакт, а также публикуется в комментарии PR.
Этап 5: Обновление baseline при мерже (оценка 30 мин)
Действия
- Добавьте второй workflow
update_baseline.yml:on: push: branches: [main] jobs: update-baseline: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run eval run: python eval/run_eval.py env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Copy as new baseline run: cp ragas_latest.json ragas_baseline.json - name: Commit new baseline uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "chore: update RAGAS baseline [skip ci]" - Убедитесь, что
ragas_baseline.jsonне отслеживается в.gitignoreдля main, но обновляется только через этот workflow.
Ожидаемый результат этапа
После мержа PR baseline автоматически обновляется до метрик нового кода.
5. Критерии приемки (Definition of Done)
- При каждом PR на main запускается job
evaluateв GitHub Actions. - Полный цикл оценки (генерация ответов + вычисление метрик + генерация отчёта) занимает ≤ 5 минут для 30 вопросов.
- Сгенерированный
report.htmlсодержит все четыре метрики RAGAS, их средние значения, распределение и худшие примеры. - В случае падения любой метрики более чем на 5% от baseline CI завершается с ошибкой (красный статус).
- Отчёт в виде HTML доступен как артефакт workflow и как комментарий к PR.
- На ветке main после мержа автоматически обновляется
ragas_baseline.json. - В корне репозитория есть
README.mdс инструкцией по локальному запуску (python eval/run_eval.py).
6. Ожидаемый результат
Основной артефакт
- Файл
.github/workflows/eval.yml— готовый CI пайплайн. - Файл
.github/workflows/update_baseline.yml— автоматическое обновление baseline при мерже. - Файлы:
eval/run_eval.py,eval/prepare_testset.py,eval/report_template.html. - Файл
test_data.json— тестовый набор (30 вопросов).
Дополнительные результаты
- Локальная возможность запуска
run_eval.pyдля быстрой итерации. - Возможность расширения метрик (например,
harmfulnessилиcustom_metric). - Документирование процесса добавления новых тестовых примеров.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Время выполнения > 5 минут при 30 вопросах | Уменьшить число вопросов до 20; использовать gpt-4o-mini вместо gpt-4; кэшировать эмбеддинги вопросов. |
| OpenAI API rate limits | Добавить tenacity retry с exponential backoff; использовать ключ с достаточным TPM (>= 60k). |
| Изменчивость метрик из-за недетерминированности LLM | Выполнять каждый вопрос 3 раза и усреднять; фиксировать temperature=0. |
| Большой HTML-отчёт не помещается в комментарий PR | Урезать детализацию в комментарии (только средние метрики и список падений), полный отчёт в артефактах. |
| Сложность локального запуска из-за API ключей | Использовать .env файл, загружаемый через python-dotenv; документировать. |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Подготовка окружения и RAG | 45 мин |
| Этап 2: Генерация тестов и скрипт оценки | 60 мин |
| Этап 3: Регрессионное сравнение | 30 мин |
| Этап 4: Интеграция с GitHub Actions | 90 мин |
| Этап 5: Обновление baseline | 30 мин |
| Итого | 4 ч 15 мин |
Примечание: для первого раза заложите +30% на отладку CI триггеров и правку шаблона отчёта.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 21 | Что такое RAGAS и какие метрики он предоставляет? |
| 45 | Как синтезировать тестовые наборы для RAG? |
| 78 | CI/CD для ML проектов: best practices |
| 112 | Оценка faithfulness: принцип работы |
| 134 | Использование GitHub Actions для периодического запуска evaluation |
| 201 | Сравнение метрик до/после изменений: статистические тесты |
| 245 | Как построить дашборд для мониторинга качества RAG? |
| 267 | Регрессионные тесты для NLP-моделей |
| 311 | Кастомные метрики в RAGAS |
| 401 | Интеграция LLM-as-judge в CI pipeline |
10. Чек-лист самопроверки
- Я локально запустил
python eval/run_eval.pyи получилreport.htmlиragas_latest.json. - Я проверил, что при искусственном ухудшении RAG скрипт завершается с ошибкой и красным статусом.
- Я закоммитил
test_data.jsonи убедился, что CI использует именно этот файл. - Я протестировал полный сценарий PR: создал ветку, изменил RAG, запушил, проверил, что GitHub Actions выполнился, а отчёт отобразился.
- Я обновил
README.mdс командой для локального запуска и указал переменную окруженияOPENAI_API_KEY.