Confiance et revue humaine
Le principe : automatiser le sûr, relire le douteux
Aucune extraction n'est juste à 100 % sur la durée. L'objectif n'est donc pas « zéro erreur », mais zéro erreur non vue : les cas douteux partent dans une file de revue humaine (une personne valide ou corrige), les autres passent directement.
flowchart LR
E["Extraction validée"] --> S1{"Réparée ?"}
S1 -->|"oui"| H["File de revue humaine"]
S1 -->|"non"| S2{"confiance < 0.8 ?"}
S2 -->|"oui"| H
S2 -->|"non"| S3{"champs_incertains non vide ?"}
S3 -->|"oui"| H
S3 -->|"non"| A["Traitement automatique"]
X["Invalide après réparation"] --> H
Les signaux du lab
raisons = []
if reparations: # une réparation peut rendre valide en supprimant de l'information
raisons.append(f"réparé {reparations} fois")
if objet.confiance < SEUIL_CONFIANCE:
raisons.append(f"confiance {objet.confiance} < {SEUIL_CONFIANCE}")
if objet.champs_incertains:
raisons.append("champs incertains : " + ", ".join(objet.champs_incertains))
return {"donnees": donnees, "reparations": reparations, "a_revoir": bool(raisons), "raisons": raisons}| Signal | D'où il vient | Fiabilité observée dans le lab |
|---|---|---|
confiance (0 à 1) | le modèle s'auto-évalue | faible : 0.95 ou 1.0 sur la plupart des documents, y compris faux |
champs_incertains | le modèle nomme ce qu'il a deviné | meilleure : désigne souvent le bon champ |
| Réparation | votre validation | fiable : la réponse initiale violait une règle |
| Règle métier non vérifiable par schéma | votre code | fiable, à ajouter selon le métier (montant élevé, client inconnu…) |
Mesurer l'utilité de la revue
Une file de revue se juge sur deux chiffres : combien d'erreurs elle attrape (rappel) et combien de documents elle envoie (charge de travail). evaluer.py les calcule en croisant les décisions avec le jeu annoté :
def revue_utile(annotes, resultats):
_, erreurs = evaluer(annotes, resultats)
faux = {e[0] for e in erreurs}
revue = {i for i, r in resultats.items() if r.get("a_revoir")}
return {"docs_avec_erreur": len(faux), "envoyes_en_revue": len(revue),
"erreurs_attrapees": len(faux & revue), "erreurs_manquees": sorted(faux - revue)}Un modèle renvoie confiance = 0.95 et aucun champ incertain, mais la date d'échéance est fausse. Que montre ce cas ?
C'est exactement le cas de cr-02 avec gemini-3.5-flash-lite : faux, mais sûr de lui. Seule une évaluation sur données annotées révèle ce type d'erreur, et une règle (par exemple : toute action citant un jour de la semaine doit avoir une échéance) peut l'attraper.
Votre file de revue reçoit 100 % des documents. Quel est le problème ?
Une revue systématique coûte autant que le travail manuel, et une personne qui valide 200 fiches justes d'affilée finit par valider sans lire. Le but est d'envoyer peu de documents, mais les bons.
Exercice : une règle qui attrape cr-02
Dans le compte rendu cr-02, « Léa relance le prestataire vendredi » a donné une échéance null avec flash-lite. Écrivez une règle, dans extraire, qui envoie en revue tout compte rendu dont une action a une échéance null alors que le texte contient un jour de la semaine.
Voir la solution
JOURS = ("lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche")
if type_doc == "compte_rendu":
sans_date = [a["responsable"] for a in donnees["actions"] if a["echeance"] is None]
if sans_date and any(j in texte.lower() for j in JOURS):
raisons.append("action sans échéance alors que le texte cite un jour : " + ", ".join(sans_date))Elle attrape cr-02, mais enverra aussi en revue des comptes rendus justes (Hugo n'a vraiment pas d'échéance) : c'est le compromis rappel / charge de travail. Relancez evaluer.py pour mesurer l'effet : erreurs_manquees ne doit plus contenir cr-02.
Résultat obtenu
Décisions de revue réelles sur les 15 documents, le 2026-10-15, pour trois modèles (extrait de evaluer.py) :
gemini-3.5-flash (API) Revue humaine : {'docs_avec_erreur': 0, 'envoyes_en_revue': 2, 'erreurs_attrapees': 0, 'erreurs_manquees': []}
gemini-3.5-flash-lite (API) Revue humaine : {'docs_avec_erreur': 3, 'envoyes_en_revue': 5, 'erreurs_attrapees': 1, 'erreurs_manquees': ['cr-02', 'cr-04']}
gemini-2.5-flash (Vertex) Revue humaine : {'docs_avec_erreur': 3, 'envoyes_en_revue': 7, 'erreurs_attrapees': 3, 'erreurs_manquees': []}Confiances déclarées (nombre de documents par valeur) :
gemini-3.5-flash [(0.85, 1), (0.95, 6), (1.0, 8)]
gemini-3.5-flash-lite [(0.9, 1), (0.95, 6), (1.0, 8)]
gemini-2.5-flash [(0.7, 1), (0.8, 1), (0.9, 4), (0.95, 2), (0.98, 2), (1.0, 5)]Avec flash-lite, cr-02 est faux mais déclaré à 0.95 sans champ incertain : la revue le manque. Avec gemini-2.5-flash sur Vertex AI, les trois documents faux sont tous partis en revue, au prix de 4 documents justes relus en plus. Le seuil de 0.8 n'a déclenché qu'une fois sur 45 extractions : ce sont les champs incertains et la réparation qui font le travail.
Je sais faire
- Combiner plusieurs signaux pour décider d'une revue humaine
- Expliquer pourquoi la confiance déclarée par un LLM ne suffit pas
- Mesurer erreurs attrapées, erreurs manquées et charge de revue
- Ajouter une règle métier ciblée sur une erreur observée