Aller au contenu principal

Récapitulation et examen final

Dix modules pour passer d'un modèle enregistré sous l'alias @champion dans MLflow à un service FastAPI qui tient 300 requêtes par seconde, journalise chaque prédiction avec un identifiant unique, refuse les appels sans jeton valide et se déploie en une commande. Voici la carte complète du cours, les fils qui la traversent et la liste de contrôle d'une API de modèle en production.

Le cours d'un coup d'œil

ModuleL'essentiel à retenir
1. Routes, types et documentationAnnotations Python standard = OpenAPI vivant à /docs ; GET pour lire, POST avec corps JSON pour prédire ; --reload en local seulement
2. Validation PydanticModèle de requête et de réponse ; contraintes ge, le, Literal[...], validateurs métier ; 422 automatique et exemple visible dans Swagger
3. Chargement du modèlelifespan charge une seule fois, alias @champion depuis MLflow, échec au démarrage plutôt qu'à la première requête
4. Prédiction unitaire et par lotsUne fonction de prétraitement unique partagée entre entraînement et service ; borne à 5 000 dossiers, réponse 413 au-delà
5. Gestion des erreurs422 pour un schéma faux, 400 pour une règle métier violée, 500 pour un défaut interne, 503 pour l'indisponibilité ; jamais de trace exposée
6. Async et tâches de fonddef par défaut, async def seulement s'il y a await ; BackgroundTasks pour du court, file externe (Celery, RQ) pour du long
7. Authentification par jetonClé d'API dans un en-tête X-API-Key, comparaison secrets.compare_digest, rotation avec chevauchement, HTTPS non négociable
8. Journalisation et sondesJournaux JSON avec X-Request-Id, sonde de vie triviale, sonde de disponibilité qui teste les dépendances, métriques RED sur Prometheus
9. Conteneurisation et déploiementDockerfile en plusieurs étages, base slim, utilisateur non privilégié, image < 500 Mo, .dockerignore obligatoire
10. Tests de charge et dimensionnementLocust en sans-interface, lire p95 et p99 (jamais la moyenne), diagnostiquer modèle / sérialisation / pool de fils, deux réplicas au minimum

Les fils qui traversent le cours

Le contrat public est plus étroit et plus stable que l'interne. Le module 2 le pose avec DossierAbonne ; le module 4 le protège avec la fonction de prétraitement unique ; le module 5 le tient avec les codes 4xx bien classés. Une API dont le schéma public change en même temps que le modèle est une API que personne n'ose intégrer.

Un service ML est d'abord un service, pas d'abord un modèle. Les neuf modules qui suivent le chargement — validation, prédiction, erreurs, async, jeton, journaux, image, dimensionnement — passent autant de temps sur le tuyau que sur le calcul. Un modèle brillant derrière un tuyau bancal donne un service que personne n'utilise ; un modèle correct derrière un tuyau propre est un actif que l'équipe maintient dix ans.

Trois séparations fondamentales structurent le code. Contrat public / objet interne (modules 2 et 4). Sonde de vie / sonde de disponibilité (module 8). Erreur du client / erreur du service (module 5). Chaque confusion coûte cher : le client déboussolé qui rejoue en boucle, l'orchestrateur qui redémarre alors qu'il devrait retirer du trafic, le tableau de bord qui affiche 500 pour un champ mal orthographié.

Chaque décision a un chiffre. Le module 10 chiffre le débit et le coût par million de prédictions ; le module 9 chiffre la taille de l'image et la mémoire par travailleur ; le module 3 chiffre le chargement du modèle. Un service ML sans chiffres est un service qu'on ne peut ni faire évoluer, ni facturer, ni comparer.

Liste de contrôle d'une API de modèle en production

À imprimer et à cocher avant chaque promotion.

Contrat public.

  • Modèle Pydantic pour la requête, modèle Pydantic pour la réponse.
  • Exemple concret dans model_config visible dans /docs.
  • Un champ nouveau est optionnel avec valeur par défaut ; jamais de suppression sans passer par /v2/.

Modèle et prétraitement.

  • Chargement unique au démarrage via lifespan, alias @champion.
  • Version du modèle exposée dans chaque réponse et sur /model/info.
  • Fonction de prétraitement importée depuis un paquet partagé, jamais réécrite dans le service.

Erreurs et journaux.

  • 422 pour un schéma faux, 400 pour une règle métier, 500 avec trace_id renvoyé mais jamais de trace Python.
  • Gestionnaire d'exceptions global, debug=False en production.
  • Journaux JSON structurés avec X-Request-Id, une ligne INFO par requête, ERROR uniquement pour ce qui exige une intervention.

Sécurité.

  • Clé d'API dans un en-tête, comparaison secrets.compare_digest.
  • Rotation avec chevauchement, secrets hors du dépôt Git.
  • HTTPS obligatoire, limitation de débit par appelant avec 429 et Retry-After.

Sondes et métriques.

  • /health/live triviale, /health/ready teste les dépendances.
  • /metrics Prometheus, alertes sur latence p95, taux d'erreur, saturation CPU.

Image et déploiement.

  • Dockerfile en plusieurs étages, base slim, image sous 500 Mo.
  • Utilisateur non privilégié, .dockerignore complet, scan de vulnérabilités avant push.
  • Deux réplicas au minimum, échelle automatique à partir de 70 % d'usage CPU.

Dimensionnement et coût.

  • Nombre de travailleurs mesuré par Locust, pas déduit de la formule 2 × cœurs + 1.
  • p95 tenu sous la valeur promise dans l'accord de niveau de service.
  • Coût par million de prédictions calculé et suivi mois après mois.

Un service qui coche ces vingt cases répond à 95 % des reproches qu'un comité d'architecture ou une équipe SRE peut lui adresser. Les 5 % restants sont des sujets d'ingénierie plus profonds (mise en cache distribuée, GPU partagé, service mesh) qui relèvent d'autres cours.

L'examen final

L'examen comporte 40 questions couvrant les dix modules : construction d'une application FastAPI minimale, validation Pydantic et messages 422, chargement au démarrage plutôt qu'à la requête, prédiction unitaire et par lots avec prétraitement cohérent, distinction fine entre 400, 422, 500 et 503, choix entre def et async def, sécurisation par clé d'API et limitation de débit, journaux structurés avec identifiant de requête, séparation des sondes de vie et de disponibilité, image Docker en plusieurs étages, lecture des percentiles Locust et dimensionnement en travailleurs et réplicas.

Plusieurs questions présentent des situations à diagnostiquer : un service qui recharge le modèle à chaque requête, une clé d'API glissée dans l'URL par un tutoriel ancien, une sonde de santé qui répond ok alors que le modèle est cassé, une route async def qui embouteille la boucle d'événement avec un calcul CPU, un lot qui fait exploser la mémoire, un 422 renvoyé pour une règle métier qui aurait dû être un 400, une image Docker de 3 Go qui bloque les déploiements. C'est le jugement qui est évalué, pas la récitation de définitions.

En cas de réussite, votre attestation d'achèvement est délivrée immédiatement ; son numéro est vérifiable par tout tiers sur la plateforme.

Avant de commencer

Reprenez le tableau ci-dessus et, pour chaque ligne, demandez-vous « quelle serait la signature d'un bogue ici ? ». Si vous savez décrire pourquoi un async def sans await divise le débit par dix, pourquoi la sonde de vie ne doit pas tester la base de données, pourquoi la p99 compte plus que la moyenne, et pourquoi la fonction de prétraitement doit vivre dans un seul dépôt, vous êtes prêt. Bonne chance !

Examen final

Prêt à valider ce cours ?

40 questions tirées au hasard dans la banque du cours · seuil de réussite 70 % · certificat PDF vérifiable délivré immédiatement en cas de réussite.

Commencer l'examen

Connexion à votre compte InSkillML et abonnement actif requis. Vous pouvez aussi lancer l'examen depuis Mes cours.