Как вы организуете CI/CD для RAG-пайплайна?

Краткий тезис

CI/CD для RAG-пайплайна — это не просто деплой кода, а непрерывная поставка целого набора артефактов: код пайплайна, embedding-модели, промпты и версии документов. Ключевой акцент — retrieval-метрики в CI: без них деградация поиска остаётся незаметной до момента, когда пользователи начнут жаловаться. Использование control|versioning|control|control|versioning|Data control|Version Control (DVC) для документов и blue-green deployment позволяет безопасно обновлять систему без даунтайма.


1. Термин CI/CD в контексте RAG

CI (Integration) — автоматическая сборка и тестирование при каждом изменении в репозитории. Для RAG это означает запуск юнит-тестов, интеграционных тестов на retrieval и генерацию, а также проверку метрик качества.

CD (Continuous Delivery или Continuous Deployment) — автоматический деплой протестированного артефакта в окружение (staging/production). В RAG это развёртывание новой версии API, индекса или модели.

Важность для RAG в отличие от классического ML, RAG-пайплайн включает динамическую базу знаний (документы, чанки). Ошибки в изменении документов или эмбеддингов могут незаметно ухудшить качество ответов. CI/CD с регрессионными тестами на retrieval — единственный способ гарантировать стабильность.

2. Компоненты RAG-пайплайна, требующие CI/CD

КомпонентПримеры артефактовЧто тестируется
Код пайплайнаPython-скрипты, классы RAG, цепочки LlamaIndexЮнит-тесты, линтинг
Embedding-модельВеса модели (e.g., intfloat/multilingual-e5-small)Качество эмбеддингов на калибровочном датасете
Chunking-стратегияРазмер, overlap, разделителиRecall@k на эталонных запросах
ПромптыTemplate, системное сообщение, примеры few-shotПроверка синтаксиса, faithfulness
Документы (корпус)PDF, статьи, HTML, DVC-tracked файлыПроверка на ошибки, полнота, соответствие формату
КонфигурацияYAML/JSON с параметрами (chunk size, top-k, model name)Валидация схемы, соответствие версиям

3. Организация репозитория (Git)

Рекомендуемая структура монорепозитория:

rag-project/
├── .github/
│   └── workflows/
│       ├── ci.yml            # CI на PR
│       └── cd.yml            # CD на push в main
├── src/
│   ├── pipeline/             # Основной код RAG
│   ├── retrieval/            # Эмбеддинги, поиск
│   └── generation/           # LLM-вызовы, промпты
├── data/
│   └── corpus/               # Исходные документы (DVC)
├── models/                   # Кэш эмбеддингов (DVC)
├── tests/
│   ├── unit/                 # Юнит-тесты
│   └── integration/          # Retrieval + generation тесты
├── config/
│   └── config.yaml           # Параметры пайплайна
├── eval/
│   ├── questions.json        # Датасет с золотыми документами
│   └── metrics.py            # Функции расчёта recall, hit rate
├── DVC                       # DVC-файлы
└── docker-compose.yml        # Локальное окружение

Git-ветки

  • main — стабильная версия в production
  • dev — интеграционные изменения
  • feature-ветки — разработка отдельных улучшений

Триггеры CI/CD

  • При создании/обновлении PR → CI
  • При мерже в main → CD (деплой на staging, затем manual approval на production)
  • При изменении DVC-файлов (документов) → отдельный pipeline переиндексации

4. CI этап: тестирование retrieval и generation

При каждом PR автоматически запускается пайплайн:

# .github/workflows/ci.yml
name: RAG CI
on: [pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      
      # 1. Кэширование зависимостей и моделей
      - name: Cache dependencies
        uses: actions/cache@v3
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
      
      - name: Install dependencies
        run: pip install -r requirements.txt
      
      # 2. Юнит-тесты (chunking, промпты)
      - name: Unit tests
        run: pytest tests/unit/
      
      # 3. Retrieval тесты на золотом датасете
      - name: Integration retrieval tests
        run: |
          python tests/integration/test_retrieval.py \
          --eval-dataset eval/questions.json \
          --top-k 5 \
          --threshold-recall 0.7
      
      # 4. Generation тесты (проверка faithfulness)
      - name: Generation tests (faithfulness)
        run: |
          python tests/integration/test_generation.py \
          --eval-dataset eval/questions.json \
          --threshold-faithfulness 0.8
      
      # 5. Проверка метрик (регрессия)
      - name: Compare metrics to baseline
        run: |
          python eval/metrics.py compare \
          --new-results results.json \
          --baseline baseline.json \
          --tolerance 0.05

Ключевые метрики в CI

  • Recall@k (например, Recall@5 > 0.7) — доля найденных релевантных документов
  • Hit Rate@k (например, HR@5 > 0.9) — хотя бы один релевантный документ найдён
  • MRR (Mean Reciprocal Rank) — средняя позиция первого релевантного
  • Faithfulness (верность) — доля ответов, не содержащих галлюцинаций (можно проверять с помощью NLI-модели)

Если метрики падают ниже baseline, PR блокируется и требует ручного анализа.

5. CD этап: стратегии деплоя

Для production рекомендуется blue-green deployment:

СтратегияОписаниеПодходит для RAG
Rolling updateПостепенная замена подов (Kubernetes)Да, но может быть разрыв в версиях индекса
Blue-greenДва идентичных окружения (blue = текущее, green = новое)Да, переключение трафика мгновенное
CanaryМедленный перелив небольшого процента трафикаДа, для A/B тестирования изменений

Реализация blue-green для RAG

  1. Поднять новую (green) версию API с новым индексом и моделью
  2. Прогреть кэш, запустить smoke-тесты (несколько реальных запросов)
  3. Переключить load balancer на green
  4. Держать blue на случай отката
  5. После подтверждения — утилизировать blue

Инструменты Kubernetes + Istio, или Docker Compose с Nginx, или serverless (AWS Lambda с двумя alias'ами).

6. Управление версиями документов (Data Version Control)

Документы — это не код, но их изменения напрямую влияют на retrieval. Используем DVC (Data Version Control):

# Инициализация DVC
dvc init
dvc remote add -d myremote s3://my-bucket/rag-corpus

# Отслеживание папки с документами
dvc add data/corpus/
git add data/corpus.dvc
git commit -m "add corpus v1"

# При обновлении документов
dvc add data/corpus/
git commit -m "update corpus v2"
git tag corpus_v2

Процесс при изменении документов

  1. Новые документы заливаются в data/corpus/ (через Git LFS или DVC)
  2. CI/CD триггерится на изменения corpus.dvc
  3. Пайплайн перезапускает чанкинг и эмбеддинг
  4. Генерируется новый индекс (FAISS, Qdrant)
  5. Упаковывается Docker-образ с новым индексом
  6. CD деплоит новую версию (blue-green)

Важно версионировать не только документы, но и кэш эмбеддингов (models/). Это ускоряет переиндексацию при откате.

7. Триггеры: автоматическая переиндексация

Триггеры разделяются на два типа:

  • Плановые изменения кода (PR → CI → CD). Включают обновление промптов, chunking-стратегии, модели эмбеддингов.
  • Изменение документов (push в папку data/corpus/). Запускается отдельный pipeline:
# .github/workflows/reindex.yml
on:
  push:
    paths:
      - 'data/corpus/**'
      - '**.dvc'

jobs:
  reindex:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup DVC
        run: pip install dvc-s3
      - name: Pull new data
        run: dvc pull
      - name: Reindex
        run: python src/pipeline/reindex.py
      - name: Build and push new image
        run: |
          docker build -t rag-api:latest .
          docker push registry/rag-api:latest
      - name: Deploy green
        run: kubectl set image deployment/rag-green rag-api=registry/rag-api:latest

8. Пример полного пайплайна CI/CD с GitHub Actions

# .github/workflows/deploy.yml
name: RAG CI/CD
on:
  pull_request:
    branches: [main]
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'config/**'
      - 'Dockerfile'
      - 'eval/**'

jobs:
  test:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Extract embeddings model
        run: dvc pull models/
      - name: Run retrieval tests
        run: python tests/integration/test_retrieval.py --eval eval/questions.json --recall-min 0.75
      - name: Run generation tests
        run: python tests/integration/test_generation.py --faithfulness-min 0.85
      - name: Check formatting
        run: black --check src/ tests/

  deploy:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build Docker image
        run: docker build -t rag-api:${{ github.sha }} .
      - name: Push to registry
        run: docker push registry/rag-api:${{ github.sha }}
      - name: Deploy to staging (blue)
        run: |
          kubectl set image deployment/rag-blue rag-api=registry/rag-api:${{ github.sha }}
          kubectl rollout status deployment/rag-blue
      - name: Run smoke tests
        run: python tests/smoke/test_staging.py
      - name: Promote to production (switch to green)
        run: |
          kubectl set image deployment/rag-green rag-api=registry/rag-api:${{ github.sha }}
          kubectl rollout status deployment/rag-green
          # Обновить сервис на green
          kubectl patch service rag-service -p '{"spec":{"selector":{"version":"green"}}}'

9. Мониторинг после деплоя

CI/CD не заканчивается на деплое. Необходим непрерывный мониторинг в production:

  • Retrieval-метрики в реальном времени средний recall@5 по тихим запросам (используя logged implicit feedback).
  • User feedback: кнопки "Like/Dislike", позволяющие выявить деградацию.
  • Алерты если средний score эмбеддингов (cosine similarity) резко падает — автоматический откат.

Можно добавить шаг в CD, который после переключения трафика запускает параллельный прогон baseline-запросов и сравнивает метрики с прошлой версией (A/B-сравнение на продублированном трафике).

10. Проблемы и их решения

ПроблемаРешение
Разрастание индексаУдалять старые версии индексов через политику в S3. Использовать lazy-загрузку только production-индекса.
Время сборки > 30 минКэшировать эмбеддинги и зависимости. Разделить пайплайн на отдельные jobs.
Сложность отладки регрессии метрикХранить историю метрик (MLflow, Weights & Biases) и baseline-датасет.
Рассинхрон между версией API и индексомНомер версии индекса (hash от документов) прокидывать как метку Docker-образа.

Пет-проект для закрепления

Задача создать MVP RAG-системы с CI/CD через GitHub Actions, DVC и blue-green деплой на локальном Docker или minikube.

Инструменты

  • LangChain / LlamaIndex
  • FAISS (векторная БД)
  • FastAPI + Uvicorn
  • DVC (для версионирования документов)
  • Docker + docker-compose
  • GitHub Actions (бесплатные минуты)
  • Minikube (опционально, для K8s)

Шаги:

  1. Напишите простой RAG: загрузите 3-5 статей, постройте FAISS-индекс, реализуйте API с одним endpoint /ask.
  2. Создайте датасет eval/questions.json с 10 вопросами и списком идентификаторов релевантных чанков.
  3. Напишите tests/integration/test_retrieval.py, который загружает индекс, для каждого вопроса ищет top-10 и считает Recall@5. Порог — 0.8.
  4. Инициализируйте DVC: dvc add data/corpus/ и git add data/corpus.dvc.
  5. Настройте GitHub Actions: при PR запускаются retrieval-тесты; при push в main — сборка Docker-образа и развёртывание на staging (или локальном Docker Compose).
  6. Внесите изменение в документ (например, замените статью) и закоммитьте. Убедитесь, что DVC инициирует новый pipeline, а CI ловит падение Recall@5.
  7. Разверните две версии (blue-green) с помощью docker-compose (два сервиса с разными тегами, Nginx как балансировщик).

Ожидаемый результат рабочий репозиторий с историей изменений, автоматическими тестами retrieval, версионированными документами и инструкцией по ручному переключению blue-green.


Связь с другими вопросами

ВопросТема
5Метрики retrieval, лежащие в основе CI-тестов
7Оптимизация индекса и кэширование в CD
8Тесты на отказ от ответа (no-answer detection)
10Дополнительный этап генерации, влияющий на CI
11Комплексная оценка, выходящая за рамки CI
12Chunking — центральный параметр, проверяемый в CI

Навигация