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
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.
321 lines
14 KiB
Markdown
321 lines
14 KiB
Markdown
# 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)
|
|
|
|
<a id="citations-non-verifiees"></a>
|
|
|
|
#### 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).
|
|
|
|
<a id="reponse-503"></a>
|
|
|
|
#### 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 ».
|
|
|
|
<a id="panne-authentification"></a>
|
|
|
|
#### 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 ».
|
|
|
|
<a id="api-regles-erreur"></a>
|
|
|
|
#### 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 ».
|
|
|
|
<a id="sujet-panne"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="intention-panne"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="bypass"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="service-injoignable"></a>
|
|
|
|
#### 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 ».
|
|
|
|
<a id="purge-arretee"></a>
|
|
|
|
#### 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).
|
|
|
|
<a id="limite-atteinte"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="tours-p90"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="citations-inventees"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="latence"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="fidelite"></a>
|
|
|
|
#### 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.
|
|
|
|
<a id="refus-authentification"></a>
|
|
|
|
#### 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
|
|
|
|
<a id="mesures-sans-seuil"></a>
|
|
|
|
#### 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`.
|