MLOps & LLMOps
Industrialiser le cycle de vie : de DevOps à MLOps puis LLMOps — CI/CD/CT, monitoring, observabilité des prompts et amélioration continue.
Construire un modèle qui marche dans un notebook, c'est une chose. Le faire tourner en production, le surveiller, le ré-entraîner quand il décroche et garantir qu'une nouvelle ligne de code ne casse rien — c'en est une tout autre. C'est précisément le rôle des opérations : l'ensemble des pratiques qui transforment une preuve de concept en un produit fiable, automatisé et amélioré en continu. Iusztin et Labonne racontent cette histoire en trois actes — DevOps, puis MLOps, puis LLMOps — chacun héritant du précédent et ajoutant ce que sa nouvelle matière (le code, puis les données et le modèle, puis le prompt) rend nécessaire.
Ce chapitre n'a pas pour but de couvrir l'intégralité de ces trois disciplines — chacune mérite son propre livre. L'objectif est de comprendre pourquoi on prend telle ou telle décision en industrialisant un système à base de LLM, en s'appuyant sur le projet fil rouge des auteurs, le LLM Twin, mais en gardant des principes transposables à n'importe quel projet. On suivra le fil DevOps → MLOps → LLMOps, on verra ce qu'apporte le CI/CD/CT, puis comment instrumenter les prompts, poser des garde-fous et boucler sur l'amélioration continue.
De DevOps à MLOps, puis à LLMOps
DevOps : automatiser la livraison du code
Livrer un logiciel à la main est lent, fragile, risqué et ne passe pas à l'échelle. Le DevOps (development operations) est né pour automatiser de bout en bout la construction, les tests, le déploiement et la surveillance du logiciel. C'est une méthodologie qui raccourcit le cycle de développement, favorise la collaboration entre développeurs et opérations, et instaure des boucles de retour rapides. Son cycle de vie enchaîne huit étapes : planifier, coder, construire (build), tester, publier (release), déployer, exploiter (operate) et surveiller (monitor).
Quelques concepts cœur qu'on retrouvera partout :
- Environnements de déploiement : pour tester avant la production, on crée des environnements miroirs — typiquement dev (les développeurs), staging (la QA et les parties prenantes), puis production (les utilisateurs finaux).
- Contrôle de version (version control) : tracer chaque changement du code pour toujours savoir quelle version est stable et prête à livrer.
- Intégration continue (continuous integration, CI) : à chaque changement, on construit l'application et on lance des tests automatisés avant de fusionner une branche de fonctionnalité dans la branche principale.
- Livraison continue (continuous delivery, CD) : une fois le code fusionné, l'infrastructure est provisionnée et l'application déployée automatiquement. CI et CD vont de pair (CI/CD).
Ces principes sont agnostiques de l'outil. Le livre s'appuie sur GitHub et GitHub Actions (gratuit pour l'open source), mais GitLab CI/CD, CircleCI ou Jenkins remplissent le même rôle. On choisit selon son écosystème, ses besoins de personnalisation et de confidentialité.
MLOps : faire des données et du modèle des citoyens de première classe
Le MLOps (machine learning operations) applique les principes DevOps au machine learning. Le hic, c'est qu'une application de ML a trois pièces mobiles au lieu d'une : le code, les données et le modèle. En DevOps, tout tourne autour du code ; en MLOps, le code peut rester inchangé pendant que seules les données évoluent — il faut alors ré-entraîner, ce qui produit une nouvelle version de dataset et de modèle. Quand l'un des trois bouge, il affecte souvent les autres.
Note
Définition officielle reprise par les auteurs : « le MLOps est l'extension de DevOps qui fait des données et des modèles des citoyens de première classe (first-class citizens), tout en préservant la méthodologie DevOps. » Comme en DevOps, isoler le développement du modèle de son déploiement nuit à la qualité, à la transparence et à l'agilité du système.
Le MLOps s'articule autour de quelques composants cœur, qu'on a déjà croisés au fil du livre :
| Composant | Rôle | Outils cités |
|---|---|---|
| Registre de modèles (model registry) | Stocker, partager et versionner les modèles entraînés | Comet ML, W&B, MLflow, ZenML |
| Magasin de features (feature store) | Préparer et stocker les features pour l'entraînement et l'inférence | Hopsworks, Tecton, Featureform |
| Magasin de métadonnées (ML metadata store) | Tracer config, données, métriques pour comparer les modèles et leur lignée | Comet ML, W&B, MLflow |
| Orchestrateur de pipelines | Automatiser l'enchaînement des étapes ML | ZenML, Airflow, Prefect, Dagster |
Au-dessus de ces composants, six principes indépendants de tout outil structurent le MLOps : automatisation (passer du manuel aux pipelines automatisés via CT et CI/CD), versionnage (du code, du modèle et des données séparément), suivi d'expériences (experiment tracking, pour comparer et choisir le meilleur modèle), tests (du code mais aussi des données et du modèle), monitoring (détecter la dégradation en production) et reproductibilité (mêmes entrées → mêmes résultats, d'où l'importance de fixer les graines aléatoires).
Astuce
Le versionnage mérite une attention particulière car il porte sur trois objets distincts. Le code se versionne avec Git (commits, releases en major.minor.patch). Le modèle se versionne dans un registre de modèles, souvent en Semantic Versioning, enrichi des métadonnées (données d'entraînement, performance, latence). Les données sont plus délicates : une colonne de version en base SQL pour du structuré, ou des outils façon Git comme DVC (Data Version Control) et des systèmes d'artefacts (Comet ML, W&B, ZenML) pour de plus gros volumes, le tout adossé à un stockage objet type S3.
LLMOps : le MLOps à l'échelle des LLM
Le LLMOps (LLM operations) est une branche spécialisée du MLOps qui se concentre sur les défis propres aux grands modèles de langage : taille gigantesque, entraînement très complexe, gestion des prompts et nature non déterministe de la génération. À sa racine, il hérite de tous les fondamentaux du MLOps ; il s'agit donc surtout de comprendre ce qu'il ajoute par-dessus.
Quand on entraîne un LLM de zéro, les dimensions « données » et « modèle » explosent : GPT-4 aurait été entraîné sur environ 13 000 milliards de tokens, sur des clusters de GPU Nvidia, avec du parallélisme de données, de modèle ou de tenseurs, pour un coût estimé autour de 100 millions de dollars. Conclusion des auteurs : seuls quelques géants peuvent se permettre d'entraîner des modèles de fondation de zéro. La tendance dominante est donc l'inverse — partir d'un modèle de fondation (Llama, GPT…) et l'optimiser pour son cas d'usage par prompt engineering, fine-tuning ou RAG. Ce sont les opérations autour de ces trois leviers qui comptent pour la plupart des projets.
Voici les briques de LLMOps spécifiques que le livre détaille :
- Retour humain (human feedback) : introduire une boucle de retour (le classique pouce haut / pouce bas) pour collecter un jeu de préférences et raffiner le modèle via RLHF ou DPO.
- Garde-fous (guardrails) : protéger entrées et sorties contre les comportements toxiques, les fuites de données et les attaques.
- Monitoring des prompts (prompt monitoring) et traçage (tracing) : journaliser et analyser chaque prompt et chaque trace complète.
- Gestion du coût en tokens : surveiller les tokens en entrée et en sortie, qui déterminent la facture.
Voici un tableau de synthèse de la filiation, qui résume ce que chaque niveau ajoute :
| Aspect | DevOps | MLOps | LLMOps |
|---|---|---|---|
| Matière versionnée | Code | Code + données + modèle | + prompts |
| Déclencheur de build | Changement de code | Changement de code, données ou modèle | + dérive de qualité, nouveau dataset |
| Automatisation | CI/CD | CI/CD + CT (continuous training) | CI/CD/CT à grande échelle |
| Tests | Code | Code, données, modèle (régression, stress) | + évaluation continue, garde-fous |
| Monitoring | Métriques système, erreurs | + dérive (drift), métriques modèle | + traces de prompts, tokens, latence (TTFT…) |
| Risques propres | Bugs, indispos | Dégradation du modèle | Hallucinations, prompt injection, fuites |
CI/CD/CT : automatiser code, données et modèle
Le CI/CD/CT est la colonne vertébrale de l'automatisation. Il faut bien distinguer ses deux moitiés :
- CI/CD s'occupe de tester, construire et déployer le code — une dimension que possède n'importe quel logiciel.
- CT (continuous training, entraînement continu) s'appuie sur le code géré par le CI/CD pour automatiser les données, l'entraînement et le service du modèle — des dimensions propres au monde de l'IA.
Le passage du manuel à l'automatisation se fait par paliers. D'abord le processus manuel (le data scientist exécute chaque étape, souvent dans des notebooks). Puis le CT, qui déclenche le ré-entraînement sur certains événements. Puis le CI/CD, qui pousse rapidement et de façon fiable le nouveau code en staging puis en production. Sur une architecture FTI (feature, training, inference) modulaire, ce passage est naturel : le CT automatise les pipelines FTI, le CI/CD construit, teste et déploie leurs nouvelles versions.
Le flux CI/CD avec GitHub Actions
Dans le projet LLM Twin, deux environnements coexistent : staging et production. On développe sur une branche de fonctionnalité issue de staging, puis on ouvre une pull request (PR). L'ouverture de la PR déclenche le pipeline CI. L'ordre des étapes compte : on commence par l'analyse statique (rapide) avant les tests automatisés (plus lents).
PR ouverte ──> CI
1. gitleaks (fuite de secrets ?)
2. lint (Ruff : erreurs potentielles)
3. format (Ruff : style, PEP 8)
4. tests (Pytest : unit + intégration)
|
v si tout passe -> merge autorisé
PR fusionnée ──> CD
build image Docker ──> push vers AWS ECR Si une étape échoue, la PR ne peut pas être fusionnée tant que le problème n'est pas réglé. Côté outillage, les auteurs utilisent Ruff (écrit en Rust, donc rapide) à la fois pour le formatage et le linting, et gitleaks pour scanner les secrets commités par mégarde. Un fichier de workflow GitHub Actions ressemble à ceci :
name: CI
on:
pull_request:
concurrency: # une seule exécution par branche
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # annule l'ancienne si une nouvelle arrive
jobs:
qa: # analyse statique, rapide
name: QA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: "3.11"
- name: gitleaks check
run: poetry poe gitleaks-check
- name: Lint check
run: poetry poe lint-check # Ruff
- name: Format check
run: poetry poe format-check # Ruff
test: # tests, plus lents
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: poetry poe test # Pytest Le pipeline CD se déclenche, lui, après la fusion sur main. Il automatise exactement les étapes Docker qu'on ferait à la main : configurer Docker Buildx, s'authentifier auprès d'AWS, construire l'image et la pousser sur ECR (Elastic Container Registry). Détail malin : l'image est taguée à la fois latest et avec le SHA du commit, ce qui permet de toujours pointer la dernière image et de retrouver le commit exact dont elle est issue.
name: CD
on:
push:
branches: [ main ] # ajouter "staging" pour étendre le flux
jobs:
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v3
- uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ secrets.AWS_ECR_NAME }}:${{ github.sha }}
${{ steps.login-ecr.outputs.registry }}/${{ secrets.AWS_ECR_NAME }}:latest
push: true À retenir
Les identifiants AWS ne sont jamais en clair : ils vivent dans les secrets du dépôt GitHub, accessibles uniquement par le pipeline. C'est exactement le genre de discipline que gitleaks fait respecter côté code. Confondre AWS_ECR_NAME (le simple nom du dépôt, ex. zenml-vrsopg) avec l'URI complète est une erreur classique de configuration.
Le pipeline CT : déclencher et enchaîner les pipelines
Pour le CT, le livre s'appuie sur l'orchestrateur ZenML. Deux choix de conception ont rendu le CT facile à atteindre : l'architecture FTI (composants modulaires aux interfaces claires) et le fait d'avoir démarré avec un orchestrateur dès le jour zéro — ce qui a forcé à découpler les pipelines et à les faire communiquer uniquement via des stockages (data warehouse, feature store, artifact store), tout en configurant l'application par fichiers YAML plutôt que par une CLI fastidieuse.
Trois types de déclencheurs (triggers) initient un pipeline :
| Type de trigger | Principe | Quand l'utiliser |
|---|---|---|
| Manuel | Une commande CLI ou un clic sur le dashboard | Démarrer tout le système d'un geste, sans risque d'ordre invalide |
| API REST | Une requête HTTP lance le pipeline | Intégrer d'autres composants (ex. un watcher qui détecte de nouveaux articles) |
| Planifié (schedule) | Une expression cron (quotidien, horaire…) | Vérifier périodiquement l'arrivée de fraîches données |
Le projet retient le déclencheur manuel : les datasets viennent de liens statiques, donc planifier n'apporterait rien. Une suite logique serait un watcher programmé qui, en détectant de nouvelles données dans Qdrant, déclencherait tout le système via l'API REST. Une fois qu'on peut tout lancer d'une seule commande, on s'adapte facilement à des scénarios plus avancés.
Pour enchaîner les pipelines, deux approches. La plus propre consiste à isoler chaque pipeline et à le faire déclencher le suivant — ce qui rend le système plus facile à comprendre, déboguer et surveiller :
from zenml import pipeline, step
from zenml.client import Client
from zenml.config import PipelineRunConfiguration
@pipeline
def digital_data_etl(user_full_name: str, links: list[str]) -> str:
user = get_or_create_user(user_full_name)
crawl_links(user=user, links=links)
trigger_feature_engineering_pipeline(user) # déclenche l'aval
@step
def trigger_feature_engineering_pipeline(user):
run_config = PipelineRunConfiguration(...)
Client().trigger_pipeline(
"feature_engineering", run_configuration=run_config
) À défaut (l'essai gratuit de ZenML limite à trois pipelines), on peut compresser toute la chaîne en un seul pipeline « maître » qui appelle ETL → features → génération de datasets → entraînement → déploiement. Les auteurs préviennent que ce monolithe n'est pas l'idéal : on le choisit ici par contrainte, mais les principes restent les mêmes.
Note
La différence cruciale, à ne jamais perdre de vue : le CI/CD pousse de nouvelles versions du code des pipelines, tandis que le CT automatise l'exécution des données et de l'entraînement par-dessus ce code. Le CT peut être déclenché par l'arrivée de fraîches données ou par une chute de performance détectée par le monitoring — c'est là que la boucle se referme.
Garde-fous : sécuriser entrées et sorties
Les systèmes LLM ne sont pas fiables : ils hallucinent, et il est difficile de l'empêcher totalement. Plus grave que l'hallucination, qui est socialement acceptée, est la fuite d'informations sensibles (clés AWS, mots de passe, numéros de téléphone…) ou la production de contenu toxique. On se souvient de l'expérience d'avril 2023 où l'on forçait ChatGPT à adopter une « mauvaise persona » pour lui faire cracher des propos haineux. La parade : encadrer le système par des garde-fous (guardrails) en entrée et en sortie.
| Garde-fou | Ce qu'il filtre | Exemples de risques |
|---|---|---|
| En entrée (input) | Prompts dangereux ou non éthiques | Fuite de données privées vers une API externe, prompt injection (jailbreak, SQL malveillant), demandes violentes |
| En sortie (output) | Réponses non conformes | Réponses vides ou hors format (JSON/YAML attendu), contenu toxique, hallucinations, fuite d'infos sensibles via le RAG |
Des outils dédiés existent : Galileo Protect (prompt injection, toxicité, fuites, hallucinations) ou l'API Moderation d'OpenAI. Mais attention au compromis : ajouter des garde-fous augmente la latence, ce qui peut nuire à l'expérience utilisateur. Il y a donc un arbitrage sûreté / latence. Pour les sorties invalides, comme le LLM est non déterministe, on peut réessayer (retry) ; mais un retry séquentiel double le temps de réponse. La stratégie courante consiste plutôt à lancer plusieurs générations en parallèle et à garder la meilleure — plus de redondance, mais une latence maîtrisée.
Attention
Un système exposé à des utilisateurs peut recevoir des entrées malveillantes et produire des sorties dangereuses. Les trois grands risques de sécurité à anticiper sont la prompt injection (détourner le comportement du modèle), la fuite de données (le LLM ou le RAG révèle des informations sensibles mémorisées) et les hallucinations. Idéalement, on retire les données sensibles du jeu d'entraînement pour que le modèle ne les mémorise pas — mais cela n'arrive pas toujours, d'où la nécessité des garde-fous.
Monitoring des prompts et observabilité des traces
Le monitoring n'a rien de neuf, mais le monde des LLM introduit une nouvelle entité à gérer : le prompt. Il faut donc des moyens spécifiques de le journaliser et de l'analyser. Les plateformes comme Opik (Comet ML), W&B ou Langfuse permettent de tracer, en production, l'entrée utilisateur, le gabarit de prompt, les variables d'entrée, la réponse générée, le nombre de tokens et la latence.
La latence justement se mesure sous plusieurs angles, car on streame la réponse token par token plutôt que d'attendre le texte complet :
- TTFT (Time to First Token) : délai avant le premier token.
- TBT (Time between Tokens) : intervalle entre deux tokens.
- TPS (Tokens per Second) : débit de génération.
- TPOT (Time per Output Token) : temps par token de sortie.
- Total Latency : temps total de la réponse.
Mais l'essentiel, c'est de journaliser la trace complète (trace) : entre la requête de l'utilisateur et la réponse finale, il y a souvent plusieurs étapes intermédiaires (réécriture de requête, récupération de documents, prompt final…). Tracer chaque étape permet de pointer exactement le maillon fautif quand quelque chose échoue ou se comporte étrangement.
Avec Opik, on instrumente les fonctions avec un simple décorateur @track, qui agrège les entrées/sorties de chaque fonction en une trace unique :
from opik import track, opik_context
@track
def call_llm_service(query: str, context: str | None) -> tuple[str, str]:
llm = LLMInferenceSagemakerEndpoint(...)
answer, prompt = InferenceExecutor(llm, query, context).execute()
return answer, prompt
@track
def rag(query: str) -> str: # point d'entrée de l'app
retriever = ContextRetriever()
documents = retriever.search(query, k=3 * 3)
context = EmbeddedChunk.to_context(documents)
answer, prompt = call_llm_service(query, context)
# Métadonnées + scores de feedback attachés à la trace
opik_context.update_current_trace(
tags=["rag"],
metadata={
"model_id": settings.HF_MODEL_ID,
"temperature": settings.TEMPERATURE_INFERENCE,
"prompt_tokens": compute_num_tokens(prompt),
"total_tokens": compute_num_tokens(answer),
},
feedback_scores=[
{"name": "user_feedback", "value": 1.0,
"reason": "Réponse utile et correcte."},
{"name": "llm_judge_score",
"value": compute_llm_judge_score(...),
"reason": "Métrique calculée par un LLM juge."},
],
)
return answer Où instrumenter ? Dans l'architecture de service du LLM Twin, deux microservices coexistent : le microservice LLM (périmètre étroit : prompt → réponse) et le microservice métier (business) qui coordonne le flux complet. C'est ce dernier — le serveur FastAPI — qui héberge le monitoring. On trace en priorité les fonctions critiques (rag(), call_llm_service()) puis on ajoute de la granularité au besoin (recherche de contexte, self-query…). Trois aspects méritent une surveillance constante :
- Configuration du modèle : identifiants du LLM et des modèles du RAG, température — tout ce qui influence fortement la génération.
- Nombre total de tokens : il pilote directement le coût de service ; une hausse soudaine de la moyenne est un signal fort de bug.
- Durée de chaque étape : pour repérer les goulets d'étranglement et localiser une latence anormale.
Piège courant
Tracer est sain, tout tracer est dangereux : trop de granularité noie le signal dans le bruit et rend les traces illisibles. La bonne règle est de tracer d'abord les fonctions les plus critiques, puis d'affiner progressivement. Le bon niveau de détail est un arbitrage que seul le développeur peut trancher selon ses besoins de débogage.
Dérive, alertes et boucle d'amélioration continue
Un logiciel classique est déterministe : une fois construit, il fonctionne comme défini. Un modèle de ML, non. Il encode une solution probabiliste à partir de données, et il se dégrade dès que les données de production s'éloignent de celles d'entraînement. On ne cherche pas à éviter ce phénomène mais à le détecter à temps pour réagir — typiquement en ré-entraînant.
Comme on n'a pas toujours accès aux vérités terrain en production, on utilise des métriques proxy : la détection de dérive (drift). Trois types coexistent :
| Type de dérive | Ce qui change | Formulation |
|---|---|---|
| Dérive des données (data drift) | Les entrées / features P(X) | P(X) ≠ P_ref(X) |
| Dérive de cible (target drift) | Les sorties / labels P(y) | P(y) ≠ P_ref(y) |
| Dérive de concept (concept drift) | La relation entrée → sortie | `P(y |
Pour mesurer une dérive, on compare une fenêtre de référence (issue du jeu d'entraînement) à une fenêtre de test (données de production) via des tests d'hypothèse. Pour une feature continue, le test de Kolmogorov-Smirnov (KS) ; pour du catégoriel, un test du chi-deux. Mais le texte — manipulé par les LLM sous forme d'embeddings — exige une distribution multivariée : on réduit la dimension puis on applique un test comme la maximum mean discrepancy (MMD).
from alibi_detect.cd import KSDrift, MMDDrift
# Feature continue unique : test univarié de Kolmogorov-Smirnov
cd_num = KSDrift(X_ref, p_val=.05, preprocess_fn=preprocess_fn,
input_shape=(max_len,))
# Texte en embeddings : distribution multivariée, test MMD
cd_text = MMDDrift(x_ref, backend="pytorch", p_val=.05)
preds = cd_text.predict(x) # dérive détectée ou non Une fois les métriques définies, encore faut-il être notifié. On déclenche une alerte (alert) quand une métrique franchit un seuil statique (ex. exactitude sous 0,8) ou quand la p-value d'un test de dérive devient assez basse. L'enjeu est de bien calibrer ces seuils : trop de faux positifs et le système d'alerte devient inutile. Les canaux usuels sont Slack, Discord, l'email ou PagerDuty. Avec ZenML, on branche un alerter sur les callbacks d'un pipeline :
from zenml import pipeline, step
from zenml.client import Client
alerter = Client().active_stack.alerter
def notify_on_failure() -> None:
alerter.post(message=build_message(status="failed"))
@step(enable_cache=False)
def notify_on_success() -> None:
alerter.post(message=build_message(status="succeeded"))
@pipeline(on_failure=notify_on_failure)
def training_pipeline(...):
... # étapes d'entraînement
notify_on_success() C'est ici que la boucle d'amélioration continue se referme : le monitoring détecte une dérive ou une chute de qualité, l'alerte prévient les humains, et le CT ré-entraîne le modèle sur des données fraîches qui capturent les nouveaux scénarios. Les retours utilisateurs (pouce haut / pouce bas) viennent nourrir un jeu de préférences pour aller plus loin (DPO, RLHF). Une nuance utile des auteurs : le monitoring collecte et visualise des données, tandis que l'observabilité (observability) va plus loin en exposant l'état interne du système pour diagnostiquer les causes racines.
La vue d'ensemble : un système FTI automatisé et surveillé
En assemblant les pièces, on obtient un système où les pipelines FTI (feature, training, inference) sont orchestrés, déclenchés, surveillés et améliorés en continu. Le CI/CD garantit que chaque fonctionnalité poussée est testée et déployée proprement. Le CT automatise la production de données et l'entraînement, déclenché par de la fraîche donnée ou par une dégradation détectée. Le monitoring des prompts, des traces, des tokens et de la dérive surveille la santé en production. Les garde-fous protègent contre les entrées et sorties dangereuses. Et les alertes plus le retour humain referment la boucle.
Le cadre vaut bien au-delà du LLM Twin : en changeant les données et en ajustant légèrement le code, on obtient une application entièrement nouvelle bâtie sur les mêmes fondations opérationnelles. C'est tout l'intérêt d'avoir des pipelines modulaires, versionnés et automatisés.
À retenir
- Les opérations se construisent par couches : DevOps (automatiser le code) → MLOps (faire des données et du modèle des citoyens de première classe) → LLMOps (le MLOps à l'échelle des LLM, qui ajoute la gestion des prompts).
- Le MLOps repose sur six principes — automatisation, versionnage (code + données + modèle), suivi d'expériences, tests (du code, des données et du modèle), monitoring et reproductibilité — et sur un socle de composants : registre de modèles, feature store, metadata store, orchestrateur.
- Il faut distinguer CI/CD (tester, construire, déployer le code) de CT (continuous training : automatiser données et entraînement) ; le CT se déclenche sur de la fraîche donnée ou sur une chute de performance détectée par le monitoring.
- Le LLMOps ajoute des briques propres aux LLM : garde-fous (filtrage entrée/sortie, anti prompt-injection) au prix d'un arbitrage sûreté/latence, monitoring des prompts et traçage complet des étapes, et surveillance du coût en tokens.
- En production, un modèle se dégrade quand les données dérivent ; on détecte la dérive (données, cible, concept) via des tests statistiques (KS, chi-deux, MMD pour les embeddings) servant de métriques proxy, et on alerte avec des seuils bien calibrés.
- L'ensemble forme une boucle d'amélioration continue : monitoring → alerte → ré-entraînement (CT) → redéploiement (CI/CD), nourrie par le retour humain, le tout orchestrant les pipelines FTI en un système automatisé et surveillé.