Projet final : instrumenter votre application LLM
Le cahier des charges
Choisissez une tâche à sortie structurée (par exemple : extraire date, montant et fournisseur d'une note de frais ; classer un e-mail client ; résumer un compte rendu en 3 champs). Livrables :
| Livrable | Fichier | Critère de réussite |
|---|---|---|
| Registre | prompts.json | au moins 2 versions, empreintes ok, alias production |
| Jeu de référence | golden.jsonl | 10 à 15 cas fictifs, variés, avec la sortie attendue |
| Wrapper | llm_wrapper.py | chaque appel produit un span gen_ai.* et une ligne JSON |
| Rapport | rapport.md | p50, p95, tokens, coût pour 1 000 appels, taux d'erreur, par version |
| Non-régression | regression.py + baseline.json | une version volontairement dégradée échoue (code de sortie 1) |
| Plan GCP | un paragraphe | métriques, tableau de bord, 3 alertes, nettoyage |
flowchart TD A["1. Écrire prompts.json et golden.jsonl"] --> B["2. pytest -q sans clé"] B --> C["3. regression.py --version v1 --save-baseline"] C --> D["4. regression.py --version v2"] D --> E["5. report.py : rapport.md"] E --> F["6. Plan de supervision Cloud Monitoring"]
Adapter le lab
- Dans prompts.json, remplacez
routerpar l'identifiant de votre tâche ; écrivez v1 (soignée) et v2 (une « optimisation » risquée). - Calculez les empreintes avec
python prompt_registry.py. - Dans regression.py, adaptez
evaluate: l'identifiant du prompt et la comparaison entre sortie obtenue et sortie attendue. - Gardez le budget : 2 versions × 15 cas = 30 appels au maximum.
cp .env.example .env # votre clé, jamais dans le code
pytest -q # hors ligne
python regression.py --version v1 --save-baseline
python regression.py --version v2; echo "exit=$?"
python report.py > rapport.mdVotre v2 passe le test de non-régression mais son p95 de latence est 3 fois plus élevé. Que faites-vous ?
La qualité n'est qu'un des quatre signaux. Une version qui génère beaucoup plus de tokens est plus lente et plus chère ; la porte de qualité peut intégrer ces critères.
La grille d'évaluation
| Critère | Points |
|---|---|
| Registre immuable, empreintes vérifiées par pytest | 3 |
Spans avec attributs gen_ai.* et version de prompt ; journaux JSON sans texte utilisateur | 4 |
| Rapport complet par version, coûts au prix officiel du jour | 3 |
| Test de non-régression qui échoue réellement sur la version dégradée | 4 |
| Plan Cloud Monitoring : métriques, tableau de bord, alertes actionnables | 4 |
| Nettoyage décrit, aucun secret dans le dépôt | 2 |
Quels éléments votre plan de supervision sur GCP doit-il contenir ? (plusieurs réponses)
Distribution par version, taux d'erreur sur une durée et budget couvrent latence, fiabilité et coût. Une alerte par erreur produit du bruit et finit ignorée.
Exercice : rédiger le plan de supervision
Rédigez en cinq points le plan de supervision du routeur du lab sur Google Cloud.
Voir la solution
- Déploiement : Cloud Run, journaux JSON sur la sortie standard,
OTEL_EXPORTER=gcp, rôleroles/cloudtrace.agentpour le compte de service. - Métriques :
lab-llmops-latence(distribution, libelléprompt_version, fichierlogmetric-latence.yaml),lab-llmops-erreurs(compteur), et une distribution surtokens_in. - Tableau de bord :
dashboard.json(p95 par version, erreurs par 5 min), complété par les tokens moyens et le coût du jour. - Alertes : taux d'erreur > 5 % pendant 10 min ; p95 > 2 × l'habitude pendant 15 min ; tokens d'entrée + 50 % sur 1 h ; budget de facturation à 80 %.
- Nettoyage en fin d'expérience :
gcloud logging metrics delete,gcloud monitoring dashboards delete,gcloud monitoring policies delete, suppression du service Cloud Run, toujours avec--project.
Résultat obtenu
Chaîne complète exécutée le 2026-10-15 sur le routeur du lab (extraits réels) :
$ pytest -q
......s [100%]
6 passed, 1 skipped
$ python regression.py --version v1 --save-baseline
Référence enregistrée dans baseline.json (exactitude 1.0, JSON valide 1.0)
$ python regression.py --version v2 ; echo "exit=$?"
RÉGRESSION : exactitude 0.00 < référence 1.00 - 0.05
RÉGRESSION : JSON valide 92% < 100 %
ÉCHEC
exit=1
$ python report.py
| router@v1 (gemini-3.5-flash-lite) | 12 | 0.0 | 797 | 1050 | 102 | 19 | 0.000937 | 0.0781 |
| router@v2 (gemini-3.5-flash-lite) | 12 | 0.0 | 763 | 1438 | 37 | 23 | 0.000834 | 0.0695 |Je sais faire
- Instrumenter une application LLM de bout en bout
- Produire un rapport de coûts et de latences par version
- Bloquer automatiquement une version de prompt qui dégrade les résultats
- Concevoir la supervision sur Cloud Monitoring et la nettoyer