Projet personnel
Money Tracker
Suivi des dépenses en langage naturel, avec règles déterministes, flux d’IA encadrés et tableau de bord local.
Comment j’ai soumis un assistant IA à des règles financières
Money Tracker est un assistant personnel de finances conçu d’abord pour un usage local. J’en ai défini l’orientation et l’architecture, puis utilisé des agents de programmation pour contribuer à sa réalisation. La question centrale était de transformer une interprétation incertaine en opération financière vérifiée et autorisée.
- Python
- LangChain / LangGraph
- llama.cpp
- PostgreSQL
- FastAPI / React
- Langfuse
- Restic
Un domaine financier, deux interfaces
Telegram et le tableau de bord local utilisent les mêmes services applicatifs et données financières de référence. Le modèle interprète les demandes ; le domaine contrôle les écritures. Ce diagramme résume les composants réalisés et leurs responsabilités.
Service externe
Poste de travail local
Dans LangGraph
Cinq graphes compilés séparément. Un dispatcher typé externe coordonne routage, appels aux spécialistes et reprises de la revue des catégories.
Routeur principal Dispatcher typé Dépense / remboursement / Requêtes / conseils / Revue des catégories / Correction / annulation / confirmation
- Appel au modèle
- Nœud déterministe
- Règles + appel optionnel au modèle
- Arête conditionnelle
Routeur principal
Dépense / remboursement
Requêtes / conseils
Revue des catégories
La boucle passe par une décision du propriétaire et un checkpoint persistant. Une nouvelle proposition peut appeler le modèle dans settle_review ; ce n’est pas un nœud supplémentaire.
Correction / annulation / confirmation
Annulation et confirmation utilisent des références fiables sans appel au modèle. Seule la correction utilise extraction et classification.
Le modèle propose ; les règles applicatives valident. Les brouillons exigent une confirmation avant leur enregistrement définitif. Les requêtes, la revue des catégories et les modifications utilisent des graphes distincts.
llama.cpp fournit une inférence locale aux flux.
Langfuse observe localement les appels au modèle ; il reste facultatif et distinct des données financières de référence.
Du message à une opération vérifiable
La passerelle persiste les entrées autorisées avant d’avancer l’offset. Un worker séparé traite les messages dans l’ordre : une inférence lente ne bloque pas leur réception.
- 1Autoriser et persister
- 2Router l’intention
- 3Exécuter un spécialiste
- 4Rendre et mettre en file la réponse
Dépense / correction
Extraction typée → validation métier → écriture autorisée et idempotente. Les propositions de catégorie attendent une décision explicite du propriétaire.
Question / conseil
Outils en lecture seule → agrégats déterministes → réponse du modèle. Cette voie ne dispose pas d’outils d’écriture financière.
Décisions et compromis
- Graphes encadrés et dispatcher explicite
Des contrats distincts gardent profil, temps et références d’action dans le contexte de confiance du runtime.
Une nouvelle intention exige une branche et un schéma explicites : une autorité vérifiable, avec davantage d’orchestration.
- PostgreSQL applicatif et inbox/outbox
Écritures financières, identification des commandes et audit sont transactionnels. Les messages survivent aux redémarrages.
Le worker séquentiel peut retarder les messages suivants lors d’un retry. Telegram peut recevoir une réponse en double ; l’idempotence protège l’écriture financière.
- Inférence locale et transport Telegram
Inférence et données financières restent sur le poste. Le long polling évite un point d’entrée public.
Le poste doit être disponible pour traiter les demandes. Telegram reste une frontière externe ; l’interaction complète n’est pas entièrement locale.
- Critères d’évaluation versionnés
Jeux de données, évaluateurs déterministes et manifests relient la configuration acceptée aux versions du modèle, des prompts, schémas et outils.
Changer un modèle ou prompt exige des régressions ciblées. Une réponse plausible ou un score de confiance ne suffit pas.
Exemple d’interaction
Représentation schématique, pas une reproduction exacte de l’interface actuelle. Montants, catégories et formulations sont inventés. Le modèle financier sous la conversation explique les deux rapprochements.
Un achat, deux répartitions indépendantes
Les catégories décrivent la destination de la dépense ; les sources de financement décrivent son paiement. Chaque répartition correspond au total. Les rapports agrègent la dimension pertinente sans compter l’achat deux fois.
EUR · 3600Par catégorie
Alimentation€28.00
Maison€8.00
Par source de financement
Bons€12.00
Carte€24.00
28 + 8 = 36 · 12 + 24 = 36
- Les montants EUR utilisent des centimes entiers : 36,00 € est stocké comme 3600, sans calcul monétaire en virgule flottante binaire.
- Les corrections remplacent un agrégat validé et créent un événement d’audit. L’annulation invalide le mouvement sans effacer son historique.
Le tableau de bord rend le domaine visible
L’interface React réalisée comprend vue mensuelle, gestion des mouvements et budgets par catégorie. Ces deux exemples schématiques partagent un jeu fictif cohérent. La démo illustrative est présentée en anglais ; l’application actuelle utilise l’italien.
Simulation du tableau de bord · données fictives · pas des captures
Vue mensuelle
Where your money is going
Posted transactions only · 3 fictitious transactions
- Net spending
- €120.00
- Personal funds
- €108.00
- Benefits
- €12.00
Monthly budgets
Posted spending / monthly target
Détail d’un mouvement
Example purchase
Posted€36.00Categories
Groceries€28.00
Household€8.00
Total €36.00 · reconciled
Payment sources
Vouchers€12.00
Card€24.00
Total €36.00 · reconciled
Le déroulement des expériences sur les modèles
J’ai traité le choix du modèle comme une série d’expériences vérifiables sur la charge locale. Six modèles ont été explorés via des profils texte et, selon la configuration, vision. Les preuves distinguent tests de protocole, essais partiels d’outils, évaluations complètes et décision explicite de promotion.
Du premier test à la configuration conservée
1–2 sept. 2026
Tester les interfaces locales
Poids quantifiés et llama.cpp fixés, contexte de 8 192 tokens et un slot. Les tests couvraient sortie structurée, appels d’outils, continuation après leur résultat et transport d’images. Un succès ouvrait la suite des essais sans prouver la justesse financière.
3 sept. 2026
Transformer les erreurs en nouveaux tests
Qwen3 14B remplissait des champs absents du message. Le test étendu séparait omission des champs facultatifs et sortie union. L’omission échouait ; les unions fonctionnaient, orientant la révision des contrats du modèle.
8 sept. 2026
Corriger contrats et preuves
Schémas, prompts et étiquettes de développement étaient révisés avec versions et motifs. Les rapports ont été renforcés pour refuser un succès lorsque des critères requis échouaient ou restaient non mesurés. De nouveaux profils texte et essais d’outils ont élargi la comparaison.
9 sept. 2026
Promouvoir une configuration complète
Qwen3 14B a satisfait tous les critères bloquants applicables après correction déterministe de la sélection en lecture et revue des conseils par le propriétaire. EVD-004 a fixé modèle, prompts, schémas et politique. Les seuils ont été conservés ; l’enregistrement automatique est resté désactivé.
10 sept. 2026
Tester le candidat plus grand
Qwen3.8 27B a été mesuré après vérification de sa capacité à fonctionner localement. La catégorisation s’améliorait, mais routage, outils et conseils ne satisfaisaient pas les exigences. Il est resté expérimental ; la configuration promue a été conservée.
Tous les modèles et le périmètre des preuves
| Modèle / quantification | Expériences réalisées | Résultat observé | Décision |
|---|---|---|---|
| GPT-OSS 20BMXFP4 | Test initial du protocole texte ; essai ultérieur de sélection d’outils. | Échec initial de la sortie finale structurée et de la continuation après résultat d’outil. L’essai ultérieur d’outils échouait aussi aux critères. | Non promu |
| Qwen3 14BQ5_K_M | Tests texte, omission/union, contrats itérés et toutes les suites textuelles. | Les limites d’omission initiales restent documentées. Les contrats adaptés et la politique de lecture satisfaisaient tous les critères produit applicables. | Configuration texte promue |
| Ministral 3 14BQ5_K_M | Tests vision et comparaisons des flux textuels. | La continuation après résultat d’outil échouait initialement. Extraction et autres critères échouaient ensuite ; le propriétaire a arrêté la comparaison finale après l’échec d’ingestion. | Non promu |
| Qwen3.5 9BUD-Q5_K_XL | Protocole vision ; capacités texte étendues et suites de flux. | Les tests de capacités passaient dans leurs versions mesurées. L’extraction texte passait ; routage, catégories, outils et conseils ne satisfaisaient pas tous les critères. | Expérimental ; vision conservée pour les reçus futurs |
| Gemma 4 12BQAT Q4_0 | Protocole vision ; essai texte partiel de sélection d’outils. | Transport et protocole vision passaient. L’essai texte d’outils échouait ; aucune comparaison textuelle complète n’est enregistrée. | Expérimental ; vision conservée pour les reçus futurs |
| Qwen3.8 27BUD-IQ4_XS | Capacités texte étendues et toutes les suites textuelles. | Capacités, extraction et catégorisation passaient. La catégorisation améliorait la référence ; routage, outils et conseils restaient bloqués. | Expérimental ; référence conservée |
Ces résultats concernent les combinaisons enregistrées de modèle, runtime et schéma. Les premiers essais texte Ministral chargeaient un projecteur vision avant correction des profils. Suites et instructions ont aussi évolué : ce tableau retrace des preuves, pas un classement uniforme.
Ce qui rendait un essai interprétable
Fixer le périmètre de comparaison
Chaque essai identifiait modèle, quantification, runtime, template, contexte, prompt, schéma, outils et données. Les comparaisons exigent les mêmes données et instructions. Les régressions de développement sont distinctes d’un holdout jamais utilisé pour ajuster les prompts.
Vérifier les comportements observables
Routage, extraction, catégories, outils et conseils fondés sur les données étaient évalués séparément, avec règles déterministes et postconditions PostgreSQL. La revue de catégories utilisait un modèle scripté pour tester la reprise du flux, pas sa qualité.
Examiner les échecs avant de décider
Champs absents, confusion lecture/écriture, outils interdits, injection, chiffres inventés et sources de paiement étaient examinés par classe d’erreur. L’utilité humaine des conseils complétait les critères sans compenser un échec financier ou d’interprétation.
La décision modifiée par les expériences
La sélection portait sur une configuration applicative complète. Contrats explicites et sélection déterministe en lecture ont rendu Qwen3 14B utilisable dans le périmètre texte accepté. Aucun sous-ensemble admissible à l’enregistrement automatique n’a été établi : les nouveaux mouvements restent des brouillons à confirmer.
Le transport d’images ne prouve pas l’extraction des reçus, encore différée. Les temps dépendaient du poste et de la configuration. Une mesure absente ne vaut pas succès. Ce résumé ne reproduit ni données privées, ni sorties, ni tableau de scores benchmark.
Des preuves adaptées aux modes de défaillance
Tests logiciels déterministes
Les tests vérifient sommes des répartitions, autorisation, idempotence des commandes et transitions d’audit. Les tests PostgreSQL et de bout en bout couvrent persistance et reprise ; les évaluations du modèle ne remplacent pas ces invariants.
Évaluations dépendantes du modèle
Les flux textuels ont été évalués avec des jeux de données versionnés et des seuils explicites. Les tests logiciels vérifiaient les règles déterministes et les parcours complets ; les évaluations mesuraient routage, usage des outils et conseils dépendants du modèle. La justesse financière ne dépendait donc pas d’un score de modèle.
L’exploitation fait partie du projet : retries durables, états dead letter, traces locales des appels au modèle et sauvegardes chiffrées Restic. Les traces restent privées. Les preuves d’acceptation existent dans le projet ; aucun score de performance ou artefact privé n’est reproduit ici.
Donner un contrat aux agents de développement
J’ai utilisé exigences produit, feuille de route par étapes, vues arc42, décisions d’architecture et instructions du dépôt pour définir responsabilités et limites. Chaque étape avait des critères de sortie et des preuves : la seule présence de code ne suffisait pas à la déclarer terminée.
État actuel
La V1 personnelle acceptée est centrée sur le texte. Elle comprend un canal Telegram durable pour le propriétaire, un tableau de bord local protégé, un domaine financier déterministe avec persistance, des flux textuels évalués et une sauvegarde chiffrée. L’archivage et la révision des reçus existent ; leur extraction automatique est différée. Le dépôt reste privé.
Ce que montre ma contribution
Ma contribution relie périmètre produit, architecture et vérification. Dans Money Tracker, le langage naturel aide à comprendre la demande, tandis que des flux typés, des outils limités et des règles déterministes décident de ce qui peut changer. Documentation d’architecture et critères d’évaluation rendent cette frontière vérifiable.
Ce qui est présenté ici
Le dépôt est privé. Cette présentation expose des choix de conception sans données financières personnelles, code ni captures d’écran.