Files
qualicheck/docs/exploitation.md
T
david 5112c2aa7c
Evals au push — seules celles dont un fichier sensible est touché / tri (push) Successful in 14s
Evals au push — seules celles dont un fichier sensible est touché / evals (push) Skipped
CI / ci (push) Skipped
Revue — preuve d'approbation / revue-ok (pull_request_review) Successful in 9s
Gate — evals et acceptance réelles / revue (push) Successful in 8s
Gate — evals et acceptance réelles / evaluation (push) Successful in 4m54s
CD — Staging / build (push) Successful in 32s
CD — Staging / deploy (push) Successful in 34s
docs(vigie): dedicated Gitea account for the vigie token
Mise en service de la vigie faite le 23/10 côté Gitea et serveur : compte
dédié `vigie` (restreint, Écriture sur le seul dépôt qualicheck), jeton à
la seule portée « tickets », secrets du dépôt, étiquette `simulation`,
entrée DNS et bloc Caddy du sous-domaine. La procédure de mise en service
le dit désormais.
2026-10-23 14:46:58 +02:00

14 KiB

Exploitation : surveiller, réagir, revenir en arrière

Page d'entrée de l'exploitation de QualiCheck (staging). Elle dit où regarder, quoi faire quand une alerte arrive et comment revenir en arrière. Elle renvoie aux documents existants au lieu de les recopier. Conception de la vigie : conception/5_exploitation/vigie.md.

1. Où regarder

  • La page « Santé du service » : https://vigie.qualicheck.koabana.fr (en local : http://localhost:8884). Mise à jour par la vigie toutes les 15 minutes, lisible sans compte. Elle donne l'état de chaque signal. Si l'heure du dernier passage date de plus de 30 minutes, la vigie ne tourne plus : voir docker compose logs vigie sur le serveur. La pastille « i » de chaque ligne dit en une phrase ce que mesure le signal (survol ou touche Tab).
  • Les tickets « incident » du dépôt Gitea : un ticket par signal en alerte, ouvert par la vigie, accompagné d'un e-mail.
  • Langfuse (projet du staging) : les traces en temps réel, pour comprendre une alerte.
  • make traces-agent ARGS="--depuis AAAA-MM-JJ" : les mesures de l'agent (tours, statuts, citations) lues dans les traces. Détail de la chaîne : docs/developpement/surveillance.md.
  • Les journaux du serveur : docker compose logs <service> sur le serveur de staging.

2. Mise en service

La vigie est un service du docker-compose : elle démarre avec le premier déploiement qui la contient. À faire avant ce déploiement :

  1. Créer le compte Gitea dédié vigie, restreint (il ne voit que les dépôts où on l'ajoute) et collaborateur du seul dépôt qualicheck avec le droit Écriture (la Lecture ouvre un ticket mais n'y pose pas d'étiquette). Connecté en vigie, créer son jeton à la seule portée « tickets » (write:issue) : il ne peut pas pousser de code, et la portée d'un jeton Gitea valant pour tous les dépôts de son propriétaire, un jeton du compte principal aurait pu écrire partout. Puis, connecté en administrateur du dépôt, les secrets du dépôt VIGIE_GITEA_TOKEN (ce jeton) et VIGIE_DESTINATAIRE (les secrets LANGFUSE_*, SMTP_* et DEPLOY_* existent déjà). Les tickets apparaissent signés vigie.
  2. Vérifier que les étiquettes incident et simulation existent dans le dépôt.
  3. Sur le serveur, deux gestes : l'entrée DNS vigie.qualicheck.koabana.fr chez Infomaniak, puis le bloc Caddy du sous-domaine (voir docs/developpement/deploiement_staging.md, « Page de la vigie »). Sans eux, la vigie tourne mais sa page n'est pas joignable de l'extérieur.

3. Déployer

Voir docs/developpement/deploiement_staging.md (déploiement, Caddy, page de santé) et make gate puis make staging pour la mise en service.

4. Une fiche par signal

Le ticket, l'e-mail et la page renvoient ici, vers l'ancre du signal. Chaque fiche dit ce que le signal veut dire, comment le vérifier, l'action à mener et quand fermer le ticket. Les seuils sont dans docs/developpement/metriques_seuils.md (section 6) et dans la section vigie de app/observability/config.yml.

Les pannes (alerte dès la première occurrence, sur 30 minutes)

Citations non vérifiées

  • Sens : une réponse a cité une règle que la vérification n'a pas pu confirmer. Le garde-fou de la réponse a laissé passer ou signalé un doute.
  • Vérifier : dans Langfuse, chercher les traces questions_libres dont l'attribut citations_non_verifiees est non vide (liste de numéros).
  • Action : lire la réponse et les règles citées ; si la règle existe bien, la vérification est trop stricte, sinon le modèle invente et le prompt ou le garde-fou est à corriger.
  • Fermer : quand la cause est comprise et que la page est revenue à « normal » (30 minutes sans nouvelle occurrence).

Réponse 503 de POST /questions

  • Sens : l'API a répondu « service indisponible » à une question d'un auditeur.
  • Vérifier : dans Langfuse, le span racine api_business avec http.status_code égal à 503 ; ses spans enfants montrent l'étape en cause. docker compose logs api-business donne l'erreur côté serveur.
  • Action : si un fournisseur de modèle est en panne, attendre son rétablissement ; sinon corriger le composant fautif.
  • Fermer : service rétabli et page revenue à « normal ».

Panne de l'authentification

  • Sens : la vérification du compte a échoué pour une raison technique (et non parce que le jeton est invalide).
  • Vérifier : span api_business.authentification au niveau ERROR dans Langfuse ; la base de données est le premier suspect (docker compose ps, docker compose logs).
  • Action : rétablir la base ; si elle est saine, lire l'erreur du span.
  • Fermer : une connexion réussie est visible et la page est « normal ».

API des règles en erreur ou jeton de l'agent refusé

  • Sens : l'agent n'arrive plus à interroger l'API des règles ; ses réponses perdent leur source.
  • Vérifier : span tools.appel_api_regles au niveau ERROR ou api_regles.statut supérieur ou égal à 500. Un jeton de l'agent refusé apparaît en 502 avec le message « jeton de l'agent refusé ».
  • Action : redémarrer ou corriger l'API des règles ; pour un jeton refusé, vérifier celui configuré pour l'agent (voir docs/developpement/creation_cle_api_regles.md).
  • Fermer : un appel réussi est visible et la page est « normal ».

Contrôle du sujet en panne

  • Sens : le contrôle qui écarte les questions hors sujet n'a pas pu répondre ; la question est traitée sans lui ou refusée.
  • Vérifier : traces dont l'attribut sujet.categorie vaut panne.
  • Action : vérifier le fournisseur du modèle de ce contrôle et sa configuration.
  • Fermer : plus de trace en panne sur 30 minutes.

Contrôle de l'intention en panne

  • Sens : même chose pour le contrôle qui détecte les demandes malveillantes.
  • Vérifier : traces dont l'attribut intention.categorie vaut panne.
  • Action : comme pour le contrôle du sujet.
  • Fermer : plus de trace en panne sur 30 minutes.

Composant court-circuité

  • Sens : un composant de protection est désactivé par configuration (l'attribut bypass du span racine est renseigné). Normal pour une mesure en local, jamais en staging.
  • Vérifier : lire l'attribut bypass sur la trace, puis les variables d'environnement du staging.
  • Action : retirer le réglage qui court-circuite et redéployer.
  • Fermer : plus de trace avec bypass sur 30 minutes.

Service injoignable

  • Sens : la route /health de l'API a échoué deux fois de suite, à 30 secondes d'écart.
  • Vérifier : ouvrir https://api.qualicheck.koabana.fr/health ; docker compose ps sur le serveur.
  • Action : relancer le conteneur ; si un déploiement vient d'avoir lieu, envisager le retour arrière (section 5).
  • Fermer : /health répond et la page est « normal ».

Purge des comptes arrêtée

  • Sens : la dernière ligne du journal de la purge date de plus de 26 heures ; la purge quotidienne des comptes ne tourne plus.
  • Vérifier : lire la fin de logs/purge_comptes.log sur le serveur et la tâche planifiée qui la lance.
  • Action : relancer la purge (make purge-comptes) et corriger la tâche planifiée.
  • Fermer : une ligne récente apparaît dans le journal.

Les dérives (alerte sur une fenêtre, au moins 20 questions)

Sous 20 questions dans la fenêtre, la page affiche « pas assez de questions » et rien ne sonne (voir les limites, section 9).

Questions coupées par la limite de tours

  • Sens : plus de 5 % des questions des dernières 24 heures n'ont pas abouti parce que l'agent a atteint le nombre maximal de tours.
  • Vérifier : make traces-agent ARGS="--depuis <hier>", puis dans Langfuse les traces questions_libres dont limite_atteinte est vrai.
  • Action : regarder si ce sont des questions nouvelles (le jeu de questions a changé) ou une dégradation (outil lent, modèle qui boucle).
  • Fermer : la part repasse sous le seuil ou la cause est traitée.

90e centile du nombre de tours

  • Sens : 10 % des questions demandent plus de 4 tours à l'agent ; il cherche plus longtemps qu'avant, souvent avant de dériver vers la limite.
  • Vérifier : comme pour la limite de tours.
  • Action : même analyse ; relire le prompt et les sorties d'outils.
  • Fermer : le centile repasse à 4 ou moins.

Citations inventées avant correction

  • Sens : plus de 10 % des questions contenaient, avant correction par le garde-fou, une citation de règle inexistante. Le garde-fou rattrape l'erreur, mais le modèle se dégrade.
  • Vérifier : make traces-agent, colonne des citations inventées.
  • Action : vérifier si le modèle ou son prompt a changé chez le fournisseur ou dans le dépôt.
  • Fermer : la part repasse sous le seuil.

Latence de POST /questions (sans page et avec page)

  • Sens : le 95e centile du temps de réponse dépasse son seuil (13 s sans page, 24 s avec page, carte #83). Deux signaux, deux tickets possibles : les deux groupes n'ont pas la même durée normale.
  • Vérifier : dans Langfuse, la durée du span racine api_business ; make mesure-latence rejoue la mesure.
  • Action : chercher l'étape lente (modèle, API des règles, base).
  • Fermer : le centile repasse sous son seuil.

Fidélité des réponses

  • Sens : la moyenne des 20 dernières notations du juge de fidélité est sous 0,90 : les réponses s'écartent des règles citées.
  • Vérifier : attribut fidelite du span questions_libres.juge.
  • Action : lire les réponses les moins bien notées ; vérifier si le modèle de réponse a changé.
  • Fermer : la moyenne remonte à 0,90 ou plus.

Refus d'authentification

  • Sens : plus de 10 refus d'authentification en une heure : jeton expiré distribué par erreur, ou tentative de force brute.
  • Vérifier : spans api_business.authentification avec un motif de refus, sur la dernière heure (sans noter d'identité dans le ticket).
  • Action : si c'est un client légitime, corriger son jeton ; sinon vérifier les limites de débit.
  • Fermer : 10 refus ou moins sur l'heure suivante.

Les mesures sans seuil

Part refusée par les contrôles, provenance, questions par compte

  • Sens : mesures affichées, sans alerte. Elles restent « à mesurer d'abord » (docs/developpement/metriques_seuils.md).
  • Vérifier : la page de santé ; make traces-agent pour le détail.
  • Action : aucune pour l'instant ; un seuil sera proposé après plusieurs semaines de traces réelles.
  • Fermer : sans objet, aucun ticket n'existe pour ces mesures.

5. Revenir en arrière

make rollback-staging RUN=<numéro> rejoue un déploiement réussi précédent (64 secondes mesurées le 14/10). Aucune migration de base n'est défaite. Procédure : docs/developpement/rollback_staging.md.

6. Le cycle d'un incident

  1. Ouvert : la vigie ouvre un ticket [vigie] <signal> : <libellé> (étiquette incident) et envoie un e-mail, une seule fois par incident.
  2. Rétabli : quand le signal redevient normal, elle ajoute un seul commentaire « rétabli à HH:MM » et un e-mail. Une panne n'est déclarée rétablie qu'après 30 minutes sans nouvelle occurrence. Si le signal repart avant la fermeture du ticket, un commentaire « revenu à HH:MM » et un e-mail le signalent (rechute).
  3. Fermé : à la main, après avoir mené l'action de la fiche. La vigie ne ferme jamais un ticket.

Si Gitea ou le relais d'e-mails ne répond pas, la page est écrite quand même et l'échec est consigné dans les journaux de la vigie.

7. Changer un seuil

Les valeurs sont dans la section vigie de app/observability/config.yml (jamais dans le code). Modifier la valeur, passer les tests, puis fusionner sur dev puis déployer : la vigie lit ses seuils dans l'image déployée. Reporter le changement dans docs/developpement/metriques_seuils.md.

8. Rejouer la démo de la dérive simulée

Dans Gitea, onglet Actions, choisir « Vigie — démo » puis « Run workflow ». Un fichier de 25 questions, dont 4 coupées par la limite de tours, remplace Langfuse ; tout le reste est réel. Résultat attendu : deux tickets [simulation] (limite de tours et 90e centile du nombre de tours), un e-mail par ticket, la page de santé montrant les deux dérives en alerte. Fermer ensuite les tickets de la démo.

La démo a besoin des secrets VIGIE_* (jeton Gitea, destinataire) du staging. Sans le jeton, elle tourne à blanc : ni ticket ni e-mail, et le workflow reste vert.

En local, sans ticket ni e-mail : make vigie.

9. Limites connues

  • Volume du staging : environ 8 questions par jour (107 en 14 jours). Avec un minimum de 20 sur 24 heures, les dérives affichent presque toujours « pas assez de questions » : aujourd'hui, seules les pannes et la simulation sonnent réellement. C'est voulu.
  • La vigie lance la version dev du code, qui peut avoir un peu d'avance sur le staging.
  • La fidélité se lit sur le span du juge : le Langfuse du staging refuse la lecture des scores par son API publique.
  • Pas d'e-mail de secours : si la vigie s'arrête, rien n'écrit à personne. Une page dont l'heure de passage a plus de 30 minutes signale une vigie arrêtée ; la cause se lit avec docker compose logs vigie.
  • Langfuse injoignable : le passage échoue avant d'écrire la page. Elle n'est plus mise à jour (son heure vieillit) et aucune alerte ne part, pas même pour une panne de l'API. Seule trace : docker compose logs vigie.