Publié le · Lecture : 22 min
MLflow 2026 : guide complet — tracking, Model Registry et évaluation LLM en Python
mlflow.genai.evaluate(), et héberger votre propre serveur MLflow avec PostgreSQL + S3.
TL;DR — L'essentiel en 30 secondes
- Installer :
pip install mlflow+mlflow ui→ interface surlocalhost:5000 - Tracker :
with mlflow.start_run():+mlflow.log_params(),log_metrics(),log_model() - Autolog :
mlflow.sklearn.autolog()— zéro code supplémentaire, tout est capturé - Versioning : Model Registry + alias (
champion,challenger) au lieu des stages dépréciés - LLM :
mlflow.openai.autolog()pour tracer,mlflow.genai.evaluate()pour évaluer - Prod : serveur MLflow + PostgreSQL + S3/MinIO, Helm chart officiel dès MLflow 3.13
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.
(mai 2026)
100% gratuit
standard MLOps
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.
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).
champion et challengermlflow.genai.evaluate() : résultats par scorer et par exempleMLflow 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
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é |
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 ?"
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"
)
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)
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.
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
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.
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.
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.
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 |
- 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
- 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
14. Limites et points d'attention
artifact_path → name 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.
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.
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 :
Observabilité LLM spécialisée (traces, spans) — à combiner avec MLflow pour le tracking d'expériences.
Serving LLM haute performance — logguez vos modèles dans MLflow, servez-les via vLLM en production.
Agents stateful — tracez vos graphs LangGraph dans MLflow avec mlflow.langchain.autolog().
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 |
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) |
FAQ — Questions fréquentes sur MLflow
Qu'est-ce que MLflow ?
mlflow.genai.evaluate() et le tracing LLM.
Comment installer MLflow en Python ?
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 ?
Quelle est la différence entre MLflow 2.x et MLflow 3.x ?
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 ?
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