DEV-AI
MLflow Python MLOps Open Source Experiment Tracking

Publié le · Lecture : 22 min

MLflow 2026 : guide complet — tracking, Model Registry et évaluation LLM en Python

Ce que vous allez apprendre : comment tracker vos expériences ML sans une ligne de config inutile, automatiser le logging avec autolog, versionner vos modèles avec le Model Registry et les alias, servir en production via l'API REST MLflow, évaluer vos LLMs avec mlflow.genai.evaluate(), et héberger votre propre serveur MLflow avec PostgreSQL + S3.

TL;DR — L'essentiel en 30 secondes

1. Pourquoi MLflow est devenu incontournable en MLOps

Imaginez la scène : vous entraînez votre dixième variante de modèle de la semaine. Vous avez modifié le learning rate, changé l'architecture, switché de SGD à Adam. Résultats ? Dans un fichier Excel quelque part, ou pire, dans votre mémoire. Deux semaines plus tard, impossible de retrouver quelle combinaison donnait les 94,2 % d'accuracy. Ce scénario, tout ingénieur ML l'a vécu.

MLflow résout ce problème fondamental. C'est une plateforme open-source créée par Databricks en 2018, aujourd'hui très largement adoptée dans l'écosystème MLOps. En 2026, avec la version 3.x, elle couvre l'intégralité du cycle de vie ML : de l'expérimentation locale jusqu'au déploiement en production, en passant par l'évaluation des LLMs.

3.13
Dernière version stable
(mai 2026)
Apache 2.0
Licence open-source
100% gratuit
2018
Créé par Databricks
standard MLOps
4 piliers
Tracking · Registry
Serving · Evaluation

2. Architecture MLflow — les 4 composants clés

MLflow est modulaire : chaque composant peut être utilisé indépendamment, ou ensemble pour une plateforme MLOps complète.

ARCHITECTURE MLFLOW CLIENT PYTHON mlflow.start_run() log_params / log_metrics HTTP TRACKING SERVER (FastAPI — MLflow 2.21+) MODEL REGISTRY Versions · Alias · Tags EXPERIMENTS Runs · Params · Metrics MLflow UI localhost:5000 · Graphes BACKEND STORE Métadonnées (runs, params) SQLite dev/test PostgreSQL production ARTIFACT STORE Modèles · Images · Datasets Local / NFS dev S3 / MinIO production AUTOLOG sklearn · PyTorch · Keras XGBoost · LightGBM MLflow 3.x · Backend FastAPI · Model Registry avec Alias · Prompt Registry · GenAI Eval

Aperçu de l'interface MLflow

Les captures ci-dessous illustrent les vues principales de l'interface MLflow 3.x (représentations fidèles à l'UI réelle).

regression-experiment + New Run Run Name Date n_estimators max_depth mse ↑ r2 ↓ RandomForest-baseline 2026-06-10 09:12 100 5 124.3 0.942 RandomForest-v2 2026-06-10 09:08 200 8 198.7 0.901 RandomForest-v1 2026-06-10 08:55 50 3 412.1 0.786 FINISHED FAILED MLflow 3.x — localhost:5000
Vue "Experiment Runs" : comparaison des runs avec métriques et hyperparamètres
Model Registry — rf-prod 3 versions · Apache 2.0 Version 3 champion Run: 9f3a2b7c r2: 0.942 · mse: 124.3 ✓ validation: approved 2026-06-10 Version 2 challenger Run: 4c8d1e9f r2: 0.901 · mse: 198.7 ⏳ validation: pending 2026-06-10 Version 1 archived Run: 2a7f5b1d r2: 0.786 · mse: 412.1 2026-06-09
Model Registry : gestion des versions avec alias champion et challenger
GenAI Evaluation — qa-evaluation 3 examples · 4 scorers Input Output Correctness Safety is_french Concise Capitale de la France ? Paris. 1.0 ✓ pass pass true Qui a inventé Python ? Guido van Rossum, en 1991. 1.0 ✓ pass pass false Qu'est-ce que MLflow ? Plateforme MLOps open-source… 0.9 ✓ pass pass true avg_correctness: 0.967 safety_pass_rate: 100% is_french_pass_rate: 100% concise_rate: 67%
Interface mlflow.genai.evaluate() : résultats par scorer et par exemple

MLflow 3.0 (juin 2025) a introduit un changement fondamental : les LoggedModels deviennent des entités de premier niveau, indépendantes des runs. Un modèle peut désormais être enregistré sans contexte de run actif, et dispose de sa propre page dans l'UI. C'est le pivot vers une plateforme centrée sur les modèles et non plus seulement sur les expériences.

3. Installation et première configuration

Installation

# Installation minimale
pip install mlflow

# Toutes les intégrations ML (sklearn, PyTorch, XGBoost...)
pip install "mlflow[extras]"

# Fonctionnalités GenAI (LLM tracing, évaluation, Prompt Registry)
pip install "mlflow[genai]"

# Vérifier la version installée
mlflow --version
# mlflow, version 3.13.0

Démarrer l'interface web

# Mode local simple (SQLite + artefacts dans ./mlruns)
mlflow ui
# [INFO] Starting gunicorn... http://127.0.0.1:5000

# Mode serveur complet (recommandé, même en local)
mlflow server --host 0.0.0.0 --port 5000
Note : depuis MLflow 2.21, le tracking server est basé sur FastAPI + Uvicorn (ASGI) au lieu de Flask. Les performances en concurrence sont significativement meilleures.

Configuration côté client

import mlflow

# Option 1 : dans le code
mlflow.set_tracking_uri("http://localhost:5000")

# Option 2 : variable d'environnement (recommandé)
# export MLFLOW_TRACKING_URI="http://mon-serveur:5000"

# Définir l'expérience (créée automatiquement si inexistante)
mlflow.set_experiment("mon-projet-classification")

4. Experiment Tracking — params, métriques et artefacts

Le tracking est le cœur de MLflow. Chaque run est une exécution de code avec ses propres paramètres, métriques et artefacts. Plusieurs runs forment une expérience.

Exemple complet avec scikit-learn

import mlflow
import mlflow.sklearn
from sklearn.datasets import make_regression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split
from mlflow.models import infer_signature

mlflow.set_tracking_uri("http://localhost:5000")
mlflow.set_experiment("regression-experiment")

# Données
X, y = make_regression(n_features=4, n_informative=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Entraînement avec tracking complet
with mlflow.start_run(run_name="RandomForest-baseline") as run:

    params = {"n_estimators": 100, "max_depth": 5, "random_state": 42}

    model = RandomForestRegressor(**params)
    model.fit(X_train, y_train)

    y_pred = model.predict(X_test)
    mse  = mean_squared_error(y_test, y_pred)
    r2   = r2_score(y_test, y_pred)

    # Paramètres (immuables une fois loggés)
    mlflow.log_params(params)

    # Métriques (peuvent évoluer avec un step)
    mlflow.log_metrics({"mse": mse, "r2": r2})

    # Tags libres
    mlflow.set_tags({"team": "data-science", "env": "dev"})

    # Signature + enregistrement au Model Registry
    signature = infer_signature(X_train, model.predict(X_train))
    mlflow.sklearn.log_model(
        sk_model=model,
        name="random-forest-reg",           # MLflow 3.x : "name" (pas "artifact_path")
        signature=signature,
        input_example=X_train[:3],
        registered_model_name="rf-prod"     # Enregistrement direct au Registry
    )

    print(f"Run ID : {run.info.run_id}")
    print(f"MSE : {mse:.4f} | R² : {r2:.4f}")

Logger des métriques par étape (training loop)

with mlflow.start_run(run_name="training-loop"):
    for epoch in range(1, 51):
        train_loss = ...  # votre logique d'entraînement
        val_loss   = ...
        mlflow.log_metrics(
            {"train_loss": train_loss, "val_loss": val_loss},
            step=epoch
        )

    # Logger un fichier comme artefact
    mlflow.log_artifact("plots/confusion_matrix.png")
    mlflow.log_artifacts("reports/")   # Dossier entier

    # Logger un dataset (traçabilité des données)
    import pandas as pd
    df = pd.read_csv("data/train.csv")
    dataset = mlflow.data.from_pandas(df, source="data/train.csv")
    mlflow.log_input(dataset, context="training")

5. Autolog — tracking automatique en une ligne

L'autolog est la fonctionnalité la plus productive de MLflow : une seule ligne capture automatiquement tous les hyperparamètres, métriques et le modèle sérialisé — sans modifier votre code d'entraînement.

import mlflow
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

mlflow.set_experiment("autolog-demo")

# Une seule ligne — tout est automatique
mlflow.sklearn.autolog()

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target, test_size=0.2, random_state=42
)

with mlflow.start_run():
    model = GradientBoostingClassifier(n_estimators=100, random_state=42)
    model.fit(X_train, y_train)

# MLflow a automatiquement capturé :
# - Tous les hyperparamètres (n_estimators, learning_rate, max_depth...)
# - Score sur le test set (accuracy)
# - Le modèle sérialisé avec sa signature
# - Les dépendances pip (requirements.txt)

Bibliothèques supportées par autolog

Bibliothèque Métriques capturées Artefacts
scikit-learn Score post-fit (accuracy, R²...) Modèle + requirements.txt
PyTorch Lightning train/val loss, accuracy par epoch Best checkpoint
Keras / TensorFlow loss, métriques custom par epoch Modèle + TensorBoard logs
XGBoost Métriques eval_set par round Modèle + feature importance
LightGBM Métriques par boosting round Modèle + importance
Statsmodels AIC, BIC, R², p-values ResultsWrapper sérialisé
HuggingFace Transformers : mlflow.transformers dispose d'un flavor dédié (mlflow.transformers.log_model(pipeline, ...)) mais n'est pas dans la liste mlflow.autolog(). Pour le tracing automatique des appels HuggingFace via API OpenAI-compatible, utilisez mlflow.openai.autolog().

6. Model Registry — versioning et cycle de vie des modèles

Le Model Registry est un catalogue centralisé de modèles versionné. Il répond à la question : "quelle version de quel modèle est en production en ce moment, et comment je la remplace ?"

Prérequis : le Model Registry nécessite un backend store de type base de données. Il ne fonctionne pas avec le backend fichier par défaut (mlruns/). En local, mlflow server --backend-store-uri sqlite:///mlflow.db suffit.

Enregistrement d'un modèle

from mlflow.tracking import MlflowClient

client = MlflowClient()

# Méthode 1 : lors du log_model (la plus simple)
mlflow.sklearn.log_model(
    sk_model=model,
    name="sklearn-model",
    registered_model_name="mon-modele-prod"   # Crée v1 automatiquement
)

# Méthode 2 : après coup depuis un run existant
mlflow.register_model(
    model_uri=f"runs:/{run_id}/sklearn-model",
    name="mon-modele-prod"
)

# Méthode 3 : via MlflowClient (contrôle maximal)
client.create_registered_model(
    name="mon-modele-prod",
    description="Modèle de classification fraude — Random Forest"
)
client.create_model_version(
    name="mon-modele-prod",
    source=f"runs:/{run_id}/sklearn-model",
    run_id=run_id
)

Alias — l'approche moderne (MLflow 2.9+ / 3.x)

Les alias remplacent les stages (Staging, Production, Archived) qui sont dépréciés depuis MLflow 2.9.0. Les alias sont des références nommées flexibles — vous pouvez en avoir autant que nécessaire par modèle.

# Définir les alias
client.set_registered_model_alias("mon-modele-prod", "champion", "1")
client.set_registered_model_alias("mon-modele-prod", "challenger", "2")

# Charger par alias — l'usage recommandé en inférence
model = mlflow.sklearn.load_model("models:/mon-modele-prod@champion")

# Promouvoir le challenger : il devient le nouveau champion
client.set_registered_model_alias("mon-modele-prod", "champion", "2")
client.delete_registered_model_alias("mon-modele-prod", "challenger")

# Taguer une version (validation, audit)
client.set_model_version_tag(
    "mon-modele-prod", "2", "validation_status", "approved"
)
client.set_model_version_tag(
    "mon-modele-prod", "2", "validated_by", "marie.dupont@company.com"
)
Ne plus utiliser : client.transition_model_version_stage(name, version, stage="Production") — cette API est dépréciée depuis 2.9.0 et sera supprimée dans une future version majeure. Migrez vers les alias.

Copier un modèle entre environnements

# Copier le modèle validé en staging vers le registry de production
client.copy_model_version(
    src_model_uri="models:/staging-model@candidate",
    dst_name="prod-model"
)

7. Serving — déployer un modèle en production

MLflow embarque un serveur d'inférence prêt à l'emploi. Il expose une API REST standardisée, compatible avec n'importe quel modèle loggé (sklearn, PyTorch, HuggingFace, custom pyfunc...).

Serveur REST local

# Depuis le Model Registry (recommandé)
mlflow models serve -m "models:/mon-modele-prod@champion" -p 5001

# Depuis un run spécifique
mlflow models serve -m "runs:/abc123def456/sklearn-model" -p 5001

# Requête de prédiction
curl -X POST http://127.0.0.1:5001/invocations \
  -H 'Content-Type: application/json' \
  -d '{"dataframe_split": {
    "columns": ["feature_1","feature_2","feature_3","feature_4"],
    "data": [[1.2, 3.4, 5.6, 7.8]]
  }}'

# Endpoints disponibles
# POST /invocations   — prédictions
# GET  /ping          — healthcheck
# GET  /version       — version MLflow

Inférence batch en ligne de commande

mlflow models predict \
  -m "models:/mon-modele-prod@champion" \
  -i input_data.csv \
  -o predictions.csv

Conteneur Docker

# Construire l'image Docker du modèle
mlflow models build-docker \
  -m "models:/mon-modele-prod@champion" \
  -n mon-modele-image:latest

# Déployer le conteneur
docker run -p 5001:5001 mon-modele-image:latest

Intégration FastAPI (pattern production recommandé)

from fastapi import FastAPI
from pydantic import BaseModel
import mlflow.sklearn
import pandas as pd

app = FastAPI(title="ML Inference API")

# Chargement au démarrage — une seule fois
model = mlflow.sklearn.load_model("models:/mon-modele-prod@champion")

class PredictionRequest(BaseModel):
    feature_1: float
    feature_2: float
    feature_3: float
    feature_4: float

@app.post("/predict")
def predict(req: PredictionRequest):
    df = pd.DataFrame([req.model_dump()])
    prediction = model.predict(df)
    return {"prediction": float(prediction[0])}

@app.get("/health")
def health():
    return {"status": "ok"}

8. MLflow pour les LLMs — Tracing et évaluation GenAI

Depuis MLflow 3.x, la plateforme inclut un outillage complet pour les applications LLM : tracing des appels (latences, tokens, coûts), évaluation automatisée via LLM-as-judge, et comparaison de prompts. C'est le concurrent direct de Langfuse dans l'écosystème MLOps.

Tracing automatique des appels LLM

import mlflow
from openai import OpenAI

# Activer le tracing automatique OpenAI
mlflow.openai.autolog()

# Activer le tracing LangChain (chains, retrievers, LLMs)
mlflow.langchain.autolog()

client = OpenAI()
mlflow.set_experiment("llm-tracing")

with mlflow.start_run():
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Tu es un assistant expert en Python."},
            {"role": "user",   "content": "Explique les décorateurs en 3 phrases."}
        ]
    )
    print(response.choices[0].message.content)

# MLflow a tracé automatiquement :
# - Input / Output complets
# - Tokens (prompt + completion + total)
# - Latence
# - Modèle utilisé
# - Coût estimé

Évaluation LLM avec mlflow.genai.evaluate()

import mlflow
from openai import OpenAI
from mlflow.genai.scorers import Correctness, Guidelines, Safety
from mlflow.genai import scorer

mlflow.set_experiment("qa-evaluation")

client_oai = OpenAI()

# Fonction à évaluer
def qa_bot(question: str) -> str:
    response = client_oai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "Réponds de façon concise et précise."},
            {"role": "user",   "content": question}
        ]
    )
    return response.choices[0].message.content

# Dataset d'évaluation
eval_data = [
    {"inputs": {"question": "Quelle est la capitale de la France ?"},
     "expectations": {"expected_response": "Paris"}},
    {"inputs": {"question": "Qui a inventé Python ?"},
     "expectations": {"expected_response": "Guido van Rossum"}},
    {"inputs": {"question": "Qu'est-ce que MLflow ?"},
     "expectations": {"expected_response": "Plateforme MLOps open-source"}},
]

# Scorer personnalisé
@scorer
def is_concise(outputs: str) -> bool:
    return len(outputs.split()) <= 15

# Lancement de l'évaluation
results = mlflow.genai.evaluate(
    data=eval_data,
    predict_fn=qa_bot,
    scorers=[
        Correctness(),      # LLM-as-judge : exactitude vs expected_response
        Safety(),           # Détection contenu problématique
        Guidelines(         # Critère custom via juge LLM
            name="is_french",
            guidelines="La réponse doit être en français correct."
        ),
        is_concise,         # Notre scorer custom
    ]
)
print(results.metrics_summary)
Juges LLM disponibles : OpenAI, Anthropic, AWS Bedrock, Mistral, TogetherAI. Le modèle par défaut est gpt-4o-mini. Depuis MLflow 3.8, DeepEval et RAGAS sont intégrés nativement (faithfulness, hallucination detection, answer relevancy et 20+ métriques supplémentaires).

9. Prompt Registry — versionner ses prompts (MLflow 2.21+)

Le Prompt Registry permet de versionner, déployer et auditer vos prompts exactement comme vous versionnez du code — avec historique, messages de commit, et chargement par alias.

import mlflow

# Créer la première version d'un prompt
prompt_v1 = mlflow.genai.register_prompt(
    name="extraction-ner",
    template="Extrais les entités nommées du texte suivant : {{ texte }}",
    commit_message="Version initiale — extraction basique",
    tags={"task": "NER", "language": "fr"},
)

# Améliorer le prompt — nouvelle version immuable
prompt_v2 = mlflow.genai.register_prompt(
    name="extraction-ner",
    template=(
        "Tu es un expert NLP. "
        "Extrais les entités nommées (PERSONNE, LIEU, ORGANISATION) : {{ texte }}\n"
        "Format de sortie : liste JSON avec type et valeur."
    ),
    commit_message="Ajout du rôle system et du format JSON",
)

# Charger par version, alias ou latest
prompt_latest = mlflow.genai.load_prompt("prompts:/extraction-ner/latest")
prompt_prod   = mlflow.genai.load_prompt("prompts:/extraction-ner@production")
prompt_v1     = mlflow.genai.load_prompt("prompts:/extraction-ner/1")

# Utiliser le prompt avec formatage Jinja2
text = "Apple a annoncé un nouveau produit à Cupertino."
formatted = prompt_prod.format(texte=text)
print(formatted)

Les prompts sont immuables une fois créés : chaque modification génère une nouvelle version avec son propre numéro. Cela garantit la reproductibilité complète de vos évaluations.

10. Intégrations — HuggingFace, LangChain, pyfunc

HuggingFace Transformers

import mlflow
import mlflow.transformers
from transformers import pipeline

# Créer un pipeline HuggingFace
sentiment_pipeline = pipeline(
    "text-classification",
    model="distilbert-base-uncased-finetuned-sst-2-english"
)

mlflow.set_experiment("hf-models")

with mlflow.start_run():
    mlflow.transformers.log_model(
        transformers_model=sentiment_pipeline,
        name="sentiment-model",
        task="text-classification",
        registered_model_name="sentiment-prod"
    )

# Chargement et inférence
loaded = mlflow.transformers.load_model("models:/sentiment-prod@champion")
result = loaded("Le film était absolument fantastique !")
print(result)  # [{'label': 'POSITIVE', 'score': 0.9997}]

LangChain — tracing et logging de chains

import mlflow
import mlflow.langchain
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# Activer le tracing LangChain (invoke, batch, stream, async)
mlflow.langchain.autolog()

mlflow.set_experiment("langchain-tracking")

llm    = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_messages([
    ("system", "Tu es un assistant expert en Python."),
    ("human",  "{question}")
])
chain  = prompt | llm | StrOutputParser()

with mlflow.start_run():
    response = chain.invoke({"question": "Qu'est-ce qu'un générateur Python ?"})
    print(response)

# Sauvegarder la chain dans MLflow
with mlflow.start_run():
    mlflow.langchain.log_model(
        lc_model=chain,
        name="python-qa-chain",
        registered_model_name="langchain-prod"
    )

Modèle custom avec pyfunc

import mlflow
import mlflow.pyfunc
import pandas as pd

class MonModeleCustom(mlflow.pyfunc.PythonModel):
    """Wrapper universel pour n'importe quel modèle ou logique métier."""

    def load_context(self, context):
        import joblib
        self.model = joblib.load(context.artifacts["model_path"])
        self.threshold = 0.5

    def predict(self, context, model_input: pd.DataFrame) -> pd.DataFrame:
        probas = self.model.predict_proba(model_input)[:, 1]
        labels = (probas >= self.threshold).astype(int)
        return pd.DataFrame({"proba": probas, "label": labels})

with mlflow.start_run():
    mlflow.pyfunc.log_model(
        name="custom-classifier",
        python_model=MonModeleCustom(),
        artifacts={"model_path": "model.joblib"},
        pip_requirements=["scikit-learn>=1.3", "joblib"],
        registered_model_name="custom-prod"
    )

11. Self-hosting en production — PostgreSQL + S3/MinIO

En production, le backend SQLite est insuffisant. L'architecture recommandée combine PostgreSQL (métadonnées) + S3 ou MinIO (artefacts).

Démarrer le serveur production

# Dépendances pour PostgreSQL + S3
pip install mlflow psycopg2-binary boto3

# Lancer le serveur (PostgreSQL + S3)
mlflow server \
  --host 0.0.0.0 \
  --port 5000 \
  --backend-store-uri postgresql://mlflow:password@db-host:5432/mlflowdb \
  --artifacts-destination s3://mon-bucket-mlflow \
  --no-serve-artifacts
--no-serve-artifacts : le client Python accède directement à S3 sans passer par le tracking server. C'est le mode recommandé en production — le serveur ne devient pas un goulot d'étranglement sur les uploads/downloads d'artefacts lourds.

Docker Compose (développement local rapide)

version: "3.8"
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: mlflow
      POSTGRES_PASSWORD: mlflow123
      POSTGRES_DB: mlflowdb
    volumes:
      - pgdata:/var/lib/postgresql/data

  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - miniodata:/data

  mlflow:
    image: ghcr.io/mlflow/mlflow:latest
    depends_on: [postgres, minio]
    ports:
      - "5000:5000"
    environment:
      MLFLOW_S3_ENDPOINT_URL: http://minio:9000
      AWS_ACCESS_KEY_ID: minioadmin
      AWS_SECRET_ACCESS_KEY: minioadmin
    command: >
      mlflow server
      --host 0.0.0.0
      --backend-store-uri postgresql://mlflow:mlflow123@postgres/mlflowdb
      --artifacts-destination s3://mlflow-artifacts
      --no-serve-artifacts

volumes:
  pgdata:
  miniodata:

Variables d'environnement client

# Tracking server
export MLFLOW_TRACKING_URI="http://mon-serveur:5000"
export MLFLOW_TRACKING_USERNAME="user"
export MLFLOW_TRACKING_PASSWORD="pass"

# Stockage artefacts (S3 AWS)
export AWS_ACCESS_KEY_ID="AKIA..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_DEFAULT_REGION="eu-west-1"

# Stockage artefacts (MinIO local)
export MLFLOW_S3_ENDPOINT_URL="http://localhost:9000"
export AWS_ACCESS_KEY_ID="minioadmin"
export AWS_SECRET_ACCESS_KEY="minioadmin"

Kubernetes (MLflow 3.13+)

Depuis MLflow 3.13.0, un Helm chart officiel est disponible pour déployer le tracking server sur Kubernetes.

Exemple indicatif : les paramètres du chart évoluent avec chaque version. Consultez la documentation officielle avant tout déploiement production.
helm repo add mlflow https://mlflow.org/helm
helm install mlflow mlflow/mlflow \
  --set backendStore.postgresql.uri="postgresql://..." \
  --set artifactStore.s3.bucket="mon-bucket"

12. Cas d'usage réels

Hyperparameter Search

Comparez des dizaines de runs GridSearch/Optuna en parallèle dans l'UI. Filtrez par métrique, visualisez les courbes d'apprentissage et identifiez le meilleur run en un clic.

CI/CD ML Pipeline

Chaque PR déclenche un run MLflow en CI. Si les métriques régressent vs le modèle champion, la PR échoue automatiquement. Le nouveau modèle ne passe en production que s'il est meilleur.

A/B Testing de modèles

Alias champion et challenger dans le Model Registry. En production, 80% du trafic va au champion, 20% au challenger. Quand le challenger gagne, un alias swap suffit — sans redéploiement.

Évaluation de chatbots LLM

Chaque version de prompt → un run d'évaluation mlflow.genai.evaluate(). Comparez la correctness, la concision et la sécurité entre les versions. Rollback immédiat si une nouvelle version régresse.

13. MLflow vs W&B vs DVC vs Comet — comparaison honnête

Critère MLflow W&B DVC Comet
Open source Apache 2.0 SaaS MIT SaaS
Installation pip install mlflow pip install wandb + compte pip install dvc pip install comet-ml + compte
Qualité UI Fonctionnelle Excellente ★ Limitée Bonne
Model Registry Complet ★ Artifact Registry Non natif Oui
Data versioning Hash seulement Partiel Natif Git ★ Non
LLM / GenAI Majeur (3.x) ★ W&B Weave Limité En cours
Self-hosting Natif ★ Enterprise payant Natif Enterprise payant
Prix Gratuit (infra) Payant / SaaS selon plan Gratuit (infra) Freemium
Choisir MLflow si...
  • Souveraineté des données / air-gapped
  • Budget limité, infra maîtrisée
  • Besoin d'un Model Registry robuste
  • Applications GenAI + LLM eval en 2026
  • Stack Databricks / Apache Spark
Choisir W&B si...
  • Deep learning intensif (vision, NLP)
  • Collaboration équipe (rapports, Sweeps)
  • Visualisation temps réel prioritaire
  • Budget disponible pour un outil SaaS payant
  • Onboarding rapide sans ops
Neptune.ai : n'est plus une option SaaS viable en 2026 — le service hébergé a été arrêté le 6 mars 2026 après son acquisition par OpenAI. Si vous êtes encore sur Neptune, migrez vers MLflow ou W&B.

14. Limites et points d'attention

Scalabilité avec SQLite : SQLite devient lent au-delà de quelques milliers de runs. Pour les équipes avec des volumes importants, passez à PostgreSQL dès le début — la migration est simple, n'attendez pas que la base devienne un point de blocage.
MLflow 3.x breaking changes : artifact_pathname dans log_model(), MLflow Recipes supprimé, flavors fastai et mleap supprimés. Le serveur 3.x lit les ressources 2.x, mais pas l'inverse — vérifiez la compatibilité avant de migrer.
Stages dépréciés : Staging, Production, Archived sont dépréciés depuis 2.9.0. Migrez vers les alias (champion, challenger) dès maintenant — les stages seront supprimés dans une prochaine version majeure.
UI moins riche que W&B : MLflow UI est fonctionnelle mais manque des visualisations avancées de W&B (heatmaps, media panels, collaboration comments). Pour la recherche en deep learning, W&B reste supérieur sur ce point.
genai.evaluate() OSS vs Databricks : La suite d'évaluation GenAI est plus complète sur Databricks Managed MLflow. Certaines fonctionnalités avancées (Judge Builder UI, monitoring continu, MLflow Assistant) peuvent nécessiter Databricks en 2026.

15. MLflow dans l'écosystème MLOps complet

MLflow est le pivot central d'une stack MLOps moderne, mais il ne fait pas tout. Voici comment l'intégrer avec les autres outils couverts sur ce blog :

Langfuse

Observabilité LLM spécialisée (traces, spans) — à combiner avec MLflow pour le tracking d'expériences.

vLLM

Serving LLM haute performance — logguez vos modèles dans MLflow, servez-les via vLLM en production.

LangGraph

Agents stateful — tracez vos graphs LangGraph dans MLflow avec mlflow.langchain.autolog().

Fine-tuning LoRA/QLoRA

Trackez chaque run de fine-tuning (loss, perplexity, config PEFT) et versionnez les adapters dans le Registry.

MLflow vs Langfuse

MLflow et Langfuse sont souvent confondus car tous deux tracent des appels LLM — mais leurs périmètres sont très différents.

Critère MLflow Langfuse
Périmètre principal MLOps complet (tracking, registry, serving) Observabilité LLM spécialisée (traces, coûts, latences)
Tracing LLM Oui (MLflow 3.x, via mlflow.tracing) Natif — cœur du produit
Model Registry ✓ Complet (alias, staging, serving) ✗ Absent
Évaluation LLM mlflow.genai.evaluate() Scores LLM-as-judge, annotations humaines
Prompt management Prompt Registry (MLflow 3.x) Prompt management natif et historique
Modèle classique (sklearn, PyTorch…) ✓ Très complet ✗ Hors périmètre
Hébergement Self-hosted ou Databricks Cloud (EU/US) ou self-hosted
Recommandation : Pour une stack LLM en 2026, utilisez les deux ensemble : MLflow pour versionner les modèles, logguer les expériences d'évaluation et gérer le cycle de vie MLOps ; Langfuse pour l'observabilité en production (traces par requête, coûts par token, sessions utilisateur). Les deux sont open-source et se complètent sans redondance.

MLflow vs LangSmith

LangSmith (Langchain Inc.) est souvent mentionné par les équipes qui utilisent LangChain ou LangGraph. Voici les différences clés avec MLflow.

Critère MLflow LangSmith
Licence Apache 2.0 (OSS) SaaS + self-hosted payant
Intégration LangChain mlflow.langchain.autolog() ✓ Native (même éditeur)
Model Registry + Serving ✓ Complet ✗ Absent
Frameworks ML classiques ✓ sklearn, PyTorch, XGBoost… ✗ LLM/agents uniquement
Évaluation mlflow.genai.evaluate() Evaluators LangSmith, feedback humain
Souveraineté des données ✓ 100% self-hosted possible Self-hosted payant (LangSmith Enterprise)
Recommandation : Si vous êtes déjà sur LangChain/LangGraph, LangSmith offre une intégration sans friction — mais il vous enferme dans l'écosystème LangChain et ne couvre pas le cycle MLOps complet. MLflow est le meilleur choix si vous avez des modèles classiques en parallèle, des contraintes de souveraineté, ou si vous ne voulez pas dépendre d'un SaaS payant pour votre infra de tracking.

FAQ — Questions fréquentes sur MLflow

Qu'est-ce que MLflow ?
MLflow est une plateforme open-source (Apache 2.0) pour gérer le cycle de vie complet du machine learning : experiment tracking (params, métriques, artefacts), Model Registry (versioning, alias, déploiement), serving de modèles et évaluation LLM. Depuis MLflow 3.0 (juin 2025), la plateforme s'est recentrée sur les cas d'usage GenAI avec un Prompt Registry, mlflow.genai.evaluate() et le tracing LLM.
Comment installer MLflow en Python ?
Installez MLflow avec pip install mlflow. Pour toutes les intégrations ML : pip install "mlflow[extras]". Pour les fonctionnalités GenAI : pip install "mlflow[genai]". Démarrez ensuite l'interface web avec mlflow ui et configurez MLFLOW_TRACKING_URI pour pointer vers votre serveur.
MLflow est-il gratuit ?
Oui, MLflow est entièrement open-source sous licence Apache 2.0 — gratuit à utiliser, héberger et modifier. Le coût réel est l'infrastructure : un VPS avec PostgreSQL et stockage objet (S3 ou MinIO) suffit pour la plupart des équipes. Databricks propose une version managée payante avec des fonctionnalités supplémentaires, mais l'OSS couvre une grande partie des besoins d'une équipe ML classique.
Quelle est la différence entre MLflow 2.x et MLflow 3.x ?
MLflow 3.0 (juin 2025) introduit les LoggedModels comme entité de premier niveau (indépendants des runs), supprime MLflow Recipes, et apporte une suite complète pour les LLMs (mlflow.genai.evaluate, Prompt Registry, tracing structuré). L'API de tracking classique reste compatible. Les stages du Model Registry (Staging/Production/Archived) sont dépréciés depuis 2.9.0 en faveur des alias — migrez vers client.set_registered_model_alias().
MLflow vs Weights & Biases : lequel choisir ?
Choisissez MLflow si vous avez des contraintes de souveraineté des données, un budget limité, ou besoin d'un Model Registry complet. MLflow est open-source et self-hostable. Choisissez W&B si votre équipe fait du deep learning intensif avec besoin de visualisation temps réel, de collaboration (rapports, Sweeps) et et que le coût d'un outil SaaS payant est acceptable. MLflow est plus complet pour la production ; W&B est plus agréable pour la recherche.

Restez à jour sur le MLOps

DVC, Grafana, W&B... la prochaine ressource MLOps arrive bientôt. Inscrivez-vous pour la recevoir.

S'inscrire à la newsletter

Articles liés sur DEV-AI