Copilote de conformité qui branche l'IA sur des données de risque en désordre, avec autocontrôle déterministe, réponses sourcées et refus motivés.
Démo en ligne : regard-wine.vercel.app · Code : github.com/heykelh/regard
Construire un modèle d'IA est devenu une commodité. Le mur, aujourd'hui, c'est de le faire fonctionner sur les données réelles, sales et régulées d'une organisation, sans jamais produire un chiffre faux. REGARD est une démonstration de ce passage : de la donnée brute à une réponse gouvernée, vérifiable et tracée.
Un reporting d'expositions de risque bancaire : les montants qu'une banque risque de perdre sur ses contreparties. Un responsable conformité, non-technique, pose une question en français : « quelle est notre exposition sur telle banque ? », « qui dépasse la limite de concentration ? », et obtient une réponse fiable et sourcée, ou un refus motivé si la donnée ne permet pas de répondre honnêtement.
Le cadre métier de référence est BCBS239 (qualité des données de risque et reporting) et DORA (résilience opérationnelle).
⚠️ Données synthétiques. La vraie donnée d'exposition bancaire est confidentielle. Le jeu de données est généré par un script seedé, conçu pour reproduire fidèlement le désordre du réel, ce qui permet aussi d'en contrôler la démonstration et de la rendre reproductible.
- Exposition sur une contrepartie : total par devise, équivalent euros, et test de dépassement de limite.
- Top N des plus exposées : classement des contreparties en équivalent euros.
- Exposition totale du portefeuille : en équivalent euros, avec répartition par devise.
- Contreparties en dépassement : celles au-dessus de la limite de concentration.
- Expositions au-dessus d'un montant : filtrage par seuil.
- Liste globale : répartition du portefeuille par devise.
- Fraîcheur des données : la donnée est-elle encore à jour ?
Hors de ce périmètre (contrepartie inconnue, question hors sujet), l'agent refuse explicitement plutôt que d'inventer.
Un harnais d'évaluation en Python rejoue 28 questions de référence contre l'agent et calcule les métriques réelles.
| Indicateur | Valeur |
|---|---|
| Cas de test réussis | 28 / 28 |
| Justesse des décisions (répondre vs refuser) | 100 % |
| Refus justifiés | 100 % |
| Couverture des citations (chaque chiffre sourcé) | 100 % |
| Justesse des intentions | 100 % |
| Latence médiane | ~370 ms |
| Latence p95 | ~660 ms |
| Coût | ~0,26 $ / 1000 requêtes |
| Hallucinations détectées | 0–17 % selon le run (voir Limites) |
Chiffres reproductibles : python eval/run_eval.py.
Principe central : déterministe d'abord, LLM ensuite. Le calcul, les contrôles et les décisions reviennent à du code vérifiable. Le modèle de langage ne sert qu'à comprendre une question floue et à reformuler des faits déjà calculés. Conséquence : sans clé d'API, ou si le modèle est indisponible, l'agent répond quand même, moins fluide, tout aussi fiable.
L'agent est un graphe d'états (LangGraph) :
question → plan → retrieve → crosscheck → verify → finalize
│
┌─────────┴─────────┐
▼ ▼
réponse gouvernée refus motivé
│ │
└──── journal d'audit ────┘
- plan : détecte l'intention et la contrepartie par règles déterministes ; le LLM n'intervient qu'en cas d'ambiguïté.
- retrieve : extrait les lignes pertinentes de la table « gold », avec score de confiance et fraîcheur.
- crosscheck : calcule les faits (totaux par devise, conversion en euros, dépassements) ; le LLM reformule, il ne calcule rien.
- verify : l'autocontrôle : garde-fous déterministes (fraîcheur, confiance, citations qui existent), puis un LLM-juge qui vérifie l'ancrage des chiffres. Si non → nouvel essai ou refus.
- finalize : réponse sourcée avec badges qualité, ou refus motivé. Tout est tracé.
Le pipeline transforme une donnée sale en donnée de confiance :
| Étape | Résultat |
|---|---|
| Lignes brutes générées | 207 |
| Retenues (table gold) | 140 |
| Rejetées (irréparables) | 38 |
| Doublons écartés | 29 |
| Score de qualité moyen | 0,75 |
Montants, devises et dates sont normalisés ; les doublons fusionnés ; les lignes irréparables rejetées avec leur motif ; chaque ligne reçoit un score de qualité de 0 à 1.
Next.js 15 · TypeScript strict · Tailwind 4 · shadcn/ui · LangGraph.js · Groq (Llama 3.3 70B) + repli Gemini 2.0 Flash · DuckDB-WASM (navigateur) + lecture fs (serveur) · Python + pytest pour l'évaluation.
# 1. Dépendances
npm install
# 2. Générer et nettoyer les données
npm run gen:raw # génère les données brutes synthétiques
npm run build:gold # nettoie, score, produit la table gold
# 3. Lancer le site + l'agent
npm run dev # http://localhost:3000Les clés d'API sont optionnelles : sans elles, l'agent fonctionne en mode déterministe. Pour activer la reformulation par LLM, copier .env.example en .env.local et renseigner GROQ_API_KEY (et/ou GEMINI_API_KEY).
Évaluation :
python -m venv eval/.venv
eval/.venv/Scripts/Activate.ps1 # Windows (source .../activate sur Unix)
pip install -r eval/requirements.txt
python eval/run_eval.py # serveur lancé en parallèleCe projet a été construit par itérations, chaque décision validée par le harnais d'évaluation. Quelques problèmes réels qu'il a fait remonter et leur correction :
- Totaux multidevises. Le premier calcul additionnait EUR + USD + GBP + CHF en un seul chiffre, produisant un total financièrement faux et une fausse alerte de dépassement. Corrigé en agrégeant par devise, puis en introduisant une conversion en euros à taux fixes documentés (assumés comme indicatifs).
- Sourcing incohérent. Sur les questions de type « top N », les citations affichaient des contreparties absentes de la réponse. Corrigé pour que chaque réponse ne cite que les enregistrements qui la fondent.
- Conflit de règles. L'ajout de l'intention « dépassement de limite » a détourné à tort les questions « expositions au-dessus de X millions ». Détecté par l'éval (une régression d'intention), corrigé par une condition de priorité.
- Latence. Certaines requêtes atteignaient 60 s à cause de la limitation de débit du LLM ; ajout d'un timeout et d'un repli déterministe, ramenant la latence médiane sous 400 ms.
Un système fiable connaît ses propres limites :
- Le LLM-juge est non-déterministe. Sur une réponse identique, il peut répondre « ancré » ou « non ancré » d'un run à l'autre. Le taux d'hallucinations détectées est donc une mesure bruitée (0–17 % observé), à interpréter sur plusieurs runs, pas un chiffre gravé.
- Données synthétiques. Le jeu reproduit le désordre du réel mais pas son volume (millions de lignes), ni la complexité des produits financiers, ni les corrélations entre contreparties.
- Conversion FX à taux fixes. Les taux de change sont figés et documentés, à titre indicatif, pas des taux de marché temps réel.
- Périmètre volontairement restreint. L'agent répond à un type de questions précis et refuse le reste, par conception.