MLOps Pipeline — end-to-end ML lifecycle: data validation, feature store materialization, training (Kubeflow/Metaflow), experiment tracking (MLflow/W&B), model registry, CI/CD for ML, canary/AB deployment via Istio router, prediction logging, drift monitoring (Evidently/Arize), business metric tracking, and automated retraining trigger. Includes ADRs on build-vs-managed (SageMaker/Vertex/Databricks vs self-host Kubeflow) and reproducibility (data+code+env+config+seed). Three scenarios: e2e pipeline happy-path, shadow mode + A/B test, drift-triggered auto-retrain.
MLOps — это не «давайте поставим MLflow и наймём ML-инженера», а дисциплина превращения экспериментов из ноутбуков в воспроизводимую, наблюдаемую, откатываемую production-систему. Без неё команда из 5-10 ML-инженеров производит «модель в Slack как файл model_final_v3_actual_FINAL.pkl», которую никто не может перетренировать, никто не знает на каких данных она тренировалась, никто не замечает что её AUC просел на 4% за месяц, и rollback означает «спросить Васю».
Без MLOps нельзя осмысленно ответить:
country сместилась — это нормальная сезонность или drift который убивает performance?user_recency_7d — модель деградирует тихо или pipeline упадёт явно?MLOps — это operating model, не tool stack. Можно построить отличный MLOps на Airflow + MLflow + Feast + Evidently, и можно сломать всё на Databricks. Главное — дисциплина версионирования, наблюдения и автоматизированного отката.
MLOps = DevOps ∪ Data Ops ∪ Model Ops — три набора практик, каждый со своим CI/CD-циклом и своими артефактами. Pipeline превращает sticky data science notebooks в систему, где каждое решение модели можно воспроизвести, каждая деградация замечается, и каждый rollback занимает минуты, не дни.
Три уровня версионирования, которые надо чётко разделять:
:latest!), pinned dependency lock, random seed, hyperparams, и сам артефакт модели в registry.Ключевая истина: обучение модели — это детерминированная функция от (data + code + env + config + seed). Если хотя бы один из пяти компонентов не зафиксирован, ты получаешь «почти такую же» модель с AUC отличающейся на 0.5-2%, и не можешь сказать почему. Это не academic concern — это блокер для compliance (GDPR / EU AI Act требуют lineage), и блокер для debugging («наша модель ведёт себя странно последнюю неделю» → надо повторить training на тех же входах).
Три цикла наблюдения, работающие на разных таймскейлах:
Диаграмма показывает пять групп, образующих полный жизненный цикл ML-модели от сырых данных до production-serving с автоматическим retraining при drift.
Верх-лево — Data + Features. S3 Data Lake (raw events), Data Validator на Great Expectations (schema checks, null rates, distribution drift vs baseline), Feature Store на Feast/Tecton (материализованные feature views с point-in-time correctness), DVC (data versioning — хеш S3 snapshot привязан к git commit). Эта группа — источник правды для тренировки. Без неё ты не знаешь на каких данных тренировалась модель.
Верх-право — Training + Experiment Tracking. Orchestrator (Kubeflow / Metaflow / Airflow) запускает Trainer (PyTorch / XGBoost на K8s, 4× A100 GPU). Trainer логирует всё в Experiment Tracker (MLflow / W&B): метрики, гиперпараметры, артефакт модели, lineage. Eval Suite прогоняет кандидата на held-out + adversarial subset + fairness-чеки. На Orchestrator подвешен ADR-001 (build vs buy MLOps платформу — managed SageMaker vs self-host Kubeflow).
Низ-лево — Registry + CI/CD. Model Registry (MLflow) хранит версионированные артефакты с lineage. CI/CD ML (GitHub Actions + CML) запускает integration тесты на synthetic data, schema-compat checks, latency budget verification. Deploy Gate — точка ручного или автоматического апрува. На Orchestrator же подвешен ADR-002 (что именно версионируется: code + data + env + config + seed).
Низ-право — Serving + Routing. Canary Router (Istio / Envoy) распределяет трафик между prod версией v_N (95%) и canary v_N+1 (5%). Client отправляет реальные запросы. Это место eval-driven safety: новая модель сначала идёт в shadow (получает копию трафика, ответы не возвращаются клиенту), потом в canary (реальная доля трафика с реальным impact).
Право — Monitoring + Retraining trigger. Prediction Logger собирает каждое предсказание + входные фичи. Drift Monitor (Evidently / Arize) считает PSI, KL, Wasserstein по каждой фиче в скользящем окне. Business Metric Monitor сравнивает predictions с ground truth когда тот доступен (клик/не-клик, выкуп/возврат). Retraining Trigger получает сигналы и kick-ает Orchestrator — замкнутая петля, делающая систему self-healing относительно distribution shift.
Стрелки разделены на data plane (что куда течёт по факту обучения), control plane (что кого триггерит), serving plane (live traffic), и monitoring feedback loop (drift → retrain). Это не один pipeline — это четыре независимых reconcile loop, объединённых model registry как точкой синхронизации.
End-to-end: feature → train → register → deploy. Daily batch — 12M событий за 24 часа в S3 lake — проходит Great Expectations checks: schema, null rate, value ranges, distribution drift vs week-1 baseline. Validated данные материализуются в Feast feature views (user_recency_7d, item_popularity_24h, ctr_user_item_30d) с point-in-time корректностью (нельзя feature из будущего относительно label из прошлого — это data leakage). DVC коммитит хеш S3 snapshot — теперь этот exact dataset навсегда привязан к git commit.
Kubeflow Pipeline spawn'ит 4× A100 PyTorch training job с pinned Docker image digest (не :latest!). Trainer fetch'ит 10M × 200 features из feature store, фиксирует data_hash + git_commit + docker_digest + seed=42 — все пять компонентов воспроизводимости. XGBoost 1000 trees, 2 часа, early stopping на validation loss. MLflow логирует run: AUC=0.873, log_loss=0.412, feature importance, artefact модели.
Eval Suite на held-out 1M rows: AUC 0.87 vs baseline 0.85 (+2%) → пройдено; fairness gap < 3% per subgroup → пройдено. Stamp eval_passed=true, business_metric_estimate=+1.2% CTR. Регистрация model_v42, stage=staging с полным lineage {data_hash, git, image, params} — теперь любой может через MLflow API спросить «на каких данных эта модель» и получить точный ответ.
CI runs integration tests на synthetic data, schema-compat test (новая модель ожидает те же входные фичи что и предыдущая, иначе serving сломается), latency budget < 50ms p99, rollback dry-run. Gate auto-approves (delta within thresholds) → router начинает canary 5%. Полный pipeline 6 часов end-to-end, каждый артефакт версионирован, lineage queryable в registry.
Shadow mode + A/B test — safe rollout. Новая модель v42 опасна по двум осям: (1) она может вернуть бредовые предсказания на edge cases которых не было в training set, (2) она может быть статистически лучше на offline metric и хуже на business metric. Shadow + canary разделяют эти риски.
Shadow mode: клиент шлёт запрос → router отдаёт его в prod v41 (клиент видит ответ), параллельно копия запроса идёт в shadow v42 — клиент НЕ видит ответ v42. Логгер пишет paired predictions: {request_id, v41_pred, v42_pred, features}. 24 часа → 10M paired predictions. Offline replay: paired t-test показывает что v42 коррелирует 0.91 с v41, latency p99 +4ms (acceptable). Shadow ловит latency/error баги без риска для клиента.
A/B canary: теперь router переключает 5% реального трафика на v42 — клиент видит v42 ответы. Ждём label (click/no-click) 7 дней. Результат: CTR(v42) = 4.21% vs CTR(v41) = 4.05% (+3.9%, p<0.01, sample 2M users/arm — statistically powered). Ramp: 5% → 25% → 50% → 100% за 5 дней, на каждом шаге re-check метрик. Если на 25% CTR проседает — auto-rollback к 0%, v41 остаётся в проде, v42 отправляется на investigation.
Cutover: v42 становится новым prod, v41 переходит в previous (хранится 30 дней для emergency rollback). Gotcha: в одном incident команда оптимизировала только AUC, выкатила модель с AUC 0.89 (vs 0.85 у baseline) — и проиграла по revenue из-за popularity bias (модель слишком часто рекомендовала топ-50 товаров). Pulled через 6 часов после ramp до 100%. Lesson: shadow ловит latency, A/B ловит business impact, оба нужны до 100% rollout.
Drift detected — auto-trigger retrain. Обычный prod трафик через v42. Каждое предсказание + входные фичи летит в Prediction Logger. Drift Monitor каждый час агрегирует histograms по каждой фиче и сравнивает с baseline distribution из training set: считает PSI (Population Stability Index) per feature.
Большинство фичей стабильны: country PSI=0.08 (порог 0.2 — ok), user_age PSI=0.04 — ok. Но device_country начинает дрейфить: 0.08 → 0.15 → 0.22 → 0.31. Flash error на drift монитор: PSI > 0.2 detected. Параллельно Business Metric Monitor на labeled subset за последние 7 дней видит: AUC деградирует 0.87 → 0.84 → 0.81, CTR упал с 4.2% до 3.7% (-12% relative). Regression confirmed на двух независимых сигналах.
Retraining Trigger получает два alert'а, применяет политику drift OR business_drop > 5% → auto-retrain и kick'ает Orchestrator. Важно: на retraining incidents auto-deploy без human-in-loop — это анти-паттерн (см. ниже). Pipeline тренирует model_v43 на свежих 30 днях (включая новый рынок, который стал причиной drift), на свежем held-out AUC восстанавливается до 0.86, fairness ok. Registration → staging → expedited promotion с manual approval (не auto, incident-mode) → canary 10% → 50% → 100% за 6 часов вместо обычных 5 дней. v43 в проде, CTR back to 4.1%, drift signal cleared.
Postmortem-вывод: альтерт на covariate shift в country features надо было настроить раньше — drift пойман через 4 часа после первого сигнала, а не через 4 дня когда уже бизнес пострадал. Time-to-detect — главная метрика drift monitoring, важнее чем количество сигналов.
ADR-001: Build in-house MLOps платформу vs использовать managed (SageMaker / Vertex / Databricks). MLOps-стек состоит из 8-10 движущихся частей: orchestrator, feature store, experiment tracker, model registry, CI/CD для моделей, serving, drift monitoring, data versioning. Self-host даёт полный контроль, низкий unit-cost на масштабе и отсутствие vendor lock-in, но требует 2-4 senior MLOps engineers только для поддержки платформы — это $600K-1.2M/год payroll до того, как кто-то обучил первую модель. Managed (SageMaker, Vertex AI, Databricks ML) скрывает 80% сложности за один SDK, но cost растёт сверхлинейно (Databricks unit-cost в 3-5× выше bare K8s на equivalent compute), lock-in (SageMaker pipeline на CloudFormation не переносится на GCP без переписывания), и gaps на edge cases (custom CUDA kernels, специфичный distributed training, on-prem GPU clusters).
Решающее дерево по стадии команды: (1) < 10 ML engineers, < 5 моделей в проде — берём managed end-to-end, не тратим единого FTE на инфру. Один MLOps senior стоит больше чем годовой счёт SageMaker для команды такого размера. (2) 10-50 ML, 5-50 моделей, мульти-облако или on-prem GPU — гибрид: managed orchestration (Vertex Pipelines) + open-source registry (MLflow self-host) + Feast self-host. (3) > 50 ML engineers, > 100 моделей, специфические требования (low-latency serving < 10ms, on-prem regulated data) — строим in-house на Kubeflow + MLflow + Feast + Triton/vLLM. Netflix Metaflow, Uber Michelangelo, Airbnb Bighead — все построены этим путём, но у каждой команды было > 50 ML и > $100M revenue к моменту начала строительства. Анти-паттерн: маленькая команда строит «свою платформу» — через 18 месяцев у них есть кривой MLflow-clone и ноль production моделей.
ADR-002: Что именно версионируется — code + data + env + config + seed. ML-эксперимент воспроизводим только если зафиксированы все пять компонентов. Code + training script — git commit. Data — DVC pointer / Delta time-travel snapshot / immutable S3 path с timestamp. Environment — Docker image digest (не tag :latest!), CUDA version, библиотеки на конкретных версиях с lock-файлом. Hyperparams + config — YAML в git или MLflow params. Random seed — torch.manual_seed + numpy + python random + cuDNN deterministic flags + DataLoader worker seed. Без любого из пяти — модель не воспроизводится.
Решение: каждый MLflow run автоматически логирует git_commit, docker_image_digest, dvc_data_hash, params, seed. Точка верификации: автоматический CI test «rerun last successful pipeline → AUC matches within 0.1%». Если не сходится — баг в reproducibility, фиксим до релиза следующей модели. Compliance-критично для регулируемых индустрий: GDPR / EU AI Act требуют доказательства «какая модель приняла какое решение по какому пользователю» — без полного lineage это штраф.
final_v3_actual_FINAL.pkl который никто не может перетренировать. Технический долг копится экспоненциально.user_total_purchases_lifetime посчитан на момент анализа, а не на момент label). Feature store с point-in-time correctness — обязателен для tabular ML.