Passer au contenu
megapromotingDiscutons

Solutions · Services financiers

Un agent qui classe des mouvements d’argent en choisissant dans une liste fermée, au lieu d’écrire une phrase qu’ensuite quelqu’un interprète.

Dans une organisation financière, un agent utile ne donne pas de conseils et n’approuve rien : il lit des documents et des transactions, les classe dans une catégorie d’un ensemble fixe, indique son niveau de certitude et a le droit de répondre « je ne sais pas ». Le reste — la décision, l’approbation, la politique — reste entre les mains des humains.

Offre, avec conditionsNu scriem „livrat”, pentru că nu avem un agent de acest fel pus în producție la un client din sectorul financiar. Ce avem, și arătăm exact ca atare, e o conductă proprie de ingestie care rulează pe datele noastre: cinci module Python, 1.526 de linii, care citesc notificări bancare din e-mail și extrase în PDF, clasifică fiecare tranzacție prin unelte și o scriu în PostgreSQL cu dedublare, plus patru fluxuri de automatizare pentru webhookuri de la trei procesatori de plăți. Starea reală, spusă în aceeași frază: depozitul nu e sub git, directoarele `tests/` și `webhook-server/` sunt goale, iar potrivirea aproximativă a numelor de contrapartidă folosește o euristică de n-grame marcată în cod ca „de înlocuit cu un serviciu de înglobare înainte de producție”. Partea de platformă financiară în producție — flux de cerere, contract, grafic de plăți, audit — e o lucrare separată, cu dovezile ei, și acolo scriem „livrat”.

Les demandes d’agents AI dans les services financiers prennent presque toujours la forme « répondre aux clients à des questions sur nos produits ». C’est une demande légitime, mais ce n’est pas là que l’on gagne du temps. Le temps se perd ailleurs : quelqu’un ouvre chaque jour des dizaines de notifications bancaires et de relevés, regarde une description du type une chaîne de majuscules avec un code et décide si c’est un encaissement client, un salaire, un impôt, une échéance vers un créancier ou une dépense d’exploitation. Ce travail est répétitif, ennuyeux et, précisément pour cela, plein d’erreurs.

Un modèle linguistique y est bon, à une condition : qu’on ne lui demande pas d’écrire une réponse en texte libre. Si vous lui demandez une phrase, vous la parserez vous-même, et vous la parserez mal. Dans notre conduite, le modèle n’écrit pas : il reçoit sept outils et doit en appeler exactement un — encaissement client, salaire, impôt, paiement vers un créancier, dépense d’exploitation, commission bancaire ou inconnu. Chaque outil demande, en plus du nom de la contrepartie ou de la catégorie, un score de confiance entre 0 et 1. « Inconnu » demande une raison écrite. La sortie est une structure, pas un avis.

La deuxième règle est que rien n’entre deux fois. Chaque transaction extraite d’une notification ou d’un relevé reçoit un identifiant externe calculé comme un préfixe de 16 caractères d’une empreinte SHA-256 sur ses champs, la colonne est unique dans la table, et l’insertion se fait avec `ON CONFLICT (external_id) DO NOTHING`. Conséquence pratique : la boîte mail peut être relue autant de fois que vous voulez, et le solde ne double pas. Sans cette règle, toute conduite d’ingestion financière finit, à la troisième semaine, par produire des doublons que quelqu’un nettoie manuellement.

Ce qu’un tel agent ne fait pas, et pourquoi il est important de l’écrire sur la page : il n’approuve pas un paiement, ne prend pas de décision de crédit, ne donne pas de recommandations d’investissement et ne répond pas au client au nom de l’institution. Le score de confiance qu’il renvoie est l’évaluation du modèle sur lui-même, pas une mesure de l’exactitude faite par nous — cette distinction est la différence entre un outil et une illusion de contrôle.

Ce que cela comprend

Ce qui change concrètement dans les services financiers

Le document entre une seule fois, même si nous le lisons dix fois

Les notifications sont lues depuis la boîte mail via IMAP, les relevés depuis des PDF. Chaque transaction reçoit un identifiant externe à partir de l’empreinte SHA-256 sur ses champs, la colonne `external_id` est `NOT NULL UNIQUE` dans la table, et l’insertion se fait avec `ON CONFLICT (external_id) DO NOTHING`, avec un journal séparé pour la ligne insérée et pour celle sautée comme doublon. La relecture de la même boîte ne produit aucun doublon.

La classification se fait par outils, avec une liste fermée de résultats

Sept outils, pas de texte libre : encaissement client, salaire, impôt, paiement vers un créancier, dépense d’exploitation, commission bancaire, inconnu. Le modèle doit en appeler un seul. Les six premiers exigent obligatoirement, en plus du nom ou de la catégorie, un score de confiance entre 0,0 et 1,0, déclaré dans le schéma de l’outil ; le septième demande une raison. Le modèle utilisé est déclaré dans le code, pas caché dans la configuration.

« Inconnu » est une sortie légitime, avec raison

Un classificateur qui n’a pas le droit de dire « je ne sais pas » va mal classer, avec une grande confiance, exactement les transactions inhabituelles — c’est-à-dire celles qui comptent. C’est pourquoi l’outil d’inconnu est disponible au même titre que les autres et demande une raison écrite, qui arrive dans la ligne. Les lignes inconnues sont la liste de travail de l’humain, pas un échec du système.

L’appariement approximatif des noms de contrepartie, avec son état réel

La même société apparaît dans les relevés sous trois orthographes. Au-dessus de la classification, il existe un appariement par similarité cosinus entre vecteurs. Nous disons exactement ce que sont ces vecteurs aujourd’hui : une heuristique de n-grammes de caractères, écrite dans le code avec le commentaire qu’en production elle doit être remplacée par un appel réel à un service d’embedding. Elle fonctionne pour des variations d’écriture ; ce n’est pas un appariement sémantique.

Les webhooks des processeurs de paiement entrent dans la même table

Quatre flux d’automatisation, un pour chacun de trois processeurs de paiement et un de rapprochement quotidien, avec 7 à 10 nœuds chacun. L’idée d’architecture est que les sources différentes — e-mail, PDF, webhook — ne produisent pas trois tables qu’il faut ensuite réconcilier, mais des lignes dans la même table, avec la même règle de déduplication.

La consommation du modèle reste sous budget par clé, pas sous facture

Les appels passent par une passerelle propre vers `api.megapromoting.com/v1`, avec 44 modèles configurés, chacun avec un coût par token et une limite de contexte. La clé de projet a une liste blanche de modèles, un budget et une période, elle peut être renouvelée en conservant l’historique, et la consommation est consolidée quotidiennement par utilisateur × clé × modèle. Le détail qui surprend tout le monde : les modèles de raisonnement produisent des étapes internes que le système de suivi ne voit pas, mais que le fournisseur facture — donc le budget brut par clé est fixé sous le plafond souhaité.

Ce qui peut être exécuté sans que les données quittent la machine

Pour les étapes qui ne nécessitent pas un grand modèle — l’extraction des champs d’un format connu, la mise en correspondance de noms, les vérifications de cohérence — aucun fournisseur externe n’est nécessaire ; c’est du code ordinaire. Le modèle n’est appelé que pour l’étape de cadrage. Quand votre politique interdit la sortie des données, la question est de savoir ce qui est envoyé au modèle, pas si l’IA est utilisée : on peut envoyer la description de la transaction sans les identifiants de compte.

Ce qu’un agent de ce type ne fait pas et ne fera pas

Il n’approuve pas un paiement et n’exécute pas un transfert. Il ne prend pas la décision de crédit — les règles, les seuils et l’approbation relèvent de la politique de l’institution. Il ne donne pas de recommandations d’investissement et ne répond pas au client en votre nom sans un circuit d’approbation séparé. Et il ne vous garantit pas l’exactitude : le score de confiance est la sortie du modèle sur lui-même, pas une mesure indépendante.

Traseul

Comment une demande passe par le système.

01

Nous fixons la liste fermée des résultats, avant tout code

La première livraison n’est pas un agent, mais une liste : les catégories dans lesquelles il est autorisé à classer, quels champs obligatoires chaque catégorie exige, et ce que signifie « inconnu » chez vous. Si la liste ne peut pas tenir sur une page, la tâche ne convient pas à un agent — et il est moins coûteux de le découvrir maintenant.

02

Nous construisons l’ingestion et la déduplication, sans modèle

La lecture depuis un e-mail, un PDF ou un webhook, l’extraction des champs, le calcul de l’identifiant externe et l’écriture dans la base se font et se vérifient sans aucun appel à un modèle. Nous livrons une chaîne qui ingère correctement et ne duplique pas. Si cette étape n’est pas solide, un modèle au-dessus ne produit que des erreurs plus convaincantes.

03

Nous ajoutons le cadrage et le mesurons sur vos cas

Au-dessus de la chaîne qui fonctionne, nous ajoutons les outils de classification et exécutons sur un ensemble de transactions réelles les vôtres, avec le résultat correct établi par la personne qui fait aujourd’hui ce travail. Nous livrons le tableau des accords et des désaccords, pas une affirmation sur l’exactitude. Le seuil à partir duquel la ligne passe à un humain est choisi à partir de ce tableau.

04

Nous mettons le budget, le journal et les portes

Clé de projet avec liste blanche de modèles et budget, consolidation quotidienne de la consommation, journal avec l’outil appelé et le score, et une gate qui envoie à un humain tout ce qui est sous le seuil ou inconnu. Nous livrons les accès, le document de mise en production et la liste écrite de ce que l’agent fait seul et de ce qu’il ne fait pas.

1E-mail, PDF sauwebhook2extragerea câmpurilor3amprentă SHA-2564scriere cu ONCONFLICT DO NOTHING5încadrare prin unadin șapte unelte, cuscorrândurile„necunoscut” către om
Traseul, în 6 pași

Les données

Ce que nous touchons, où elles sont et combien de temps elles restent

Les règles diffèrent d’un secteur à l’autre. Voici celles qui s’appliquent aux services financiers.

Quel type de données elle touche, concrètement
Mouvements d’argent, avec date, montant, devise, description et contrepartie. Une partie des contreparties sont des personnes physiques — un salaire porte le nom de l’employé — donc le tableau contient des données à caractère personnel des employés, et pas seulement des données commerciales. Cela change qui a le droit d’ouvrir le tableau.
Ce qui arrive au modèle et ce qui reste à la maison
Le modèle reçoit le texte de la description de la transaction et le montant. Les identifiants de compte, les IBAN et le reste des champs n’ont pas leur place dans la requête pour que la catégorisation fonctionne, donc ils peuvent être laissés en dehors. La règle que nous appliquons en général : ce qui n’est pas nécessaire pour l’étape respective n’est pas envoyé, car ce qui ne part pas ne peut pas être retenu par qui que ce soit.
Où sont stockées les données extraites
PostgreSQL, avec `external_id` unique et un index dessus. La base reste la vôtre, sur votre infrastructure ou sur une infrastructure que nous exploitons pour vous. Il n’existe pas de dépôt commun entre clients, car il n’y a aucune raison technique pour qu’il en existe un.
La trace de la décision automatique
Chaque ligne conserve l’outil qui a été appelé, avec quel score et, le cas échéant, le motif de « inconnu ». C’est le minimum nécessaire pour que, dans six mois, quelqu’un puisse répondre à la question « pourquoi cette transaction a-t-elle été classée en charges d’exploitation » — avec une réponse, pas avec un haussement d’épaules.
Le délai de conservation, que vous ne choisissez pas seul ici
Les documents financiers ont des délais de conservation établis par la législation comptable et fiscale, et non par notre préférence ou la vôtre. Dans un projet financier, le délai est pris dans ces règles, il est inscrit dans le registre des traitements, et seulement ensuite la suppression est implémentée. L’ordre inverse — implémenter d’abord, vérifier après — produit des systèmes qui suppriment ce qui devait être conservé.

Un cas

Une conduite d’ingestion qui peut être redémarrée sans crainte

La situation

Les notifications bancaires et les relevés mensuels arrivaient dans une boîte mail et étaient lus par une personne, qui les classait par catégories. La première variante évidente — un script qui lit la boîte et écrit dans la base — a un problème qui n’apparaît qu’à la troisième semaine : à chaque redémarrage ou relecture, les mêmes transactions entrent à nouveau.

Ce que nous avons construit

Nous avons écrit cinq modules, 1.526 lignes de Python : deux analyseurs de notifications via IMAP, un extracteur de relevés PDF, le classificateur par outils et l’écriture dans PostgreSQL. La règle centrale est l’identifiant externe — un préfixe de 16 caractères issu d’une empreinte SHA-256 des champs de la transaction — avec la colonne unique dans la table et l’insertion `ON CONFLICT DO NOTHING`. La classification ne renvoie pas de texte : le modèle appelle l’un des sept outils, avec un score de confiance obligatoire, et « inconnu » exige un motif.

Ce qui en est sorti

La boîte mail peut être relue à tout moment, et les lignes déjà traitées sont ignorées et notées comme doublon dans le journal. Les transactions que le modèle ne peut pas catégoriser apparaissent comme liste de travail, avec leur motif à côté, au lieu d’être poussées dans une catégorie pour donner l’impression que tout s’est bien passé.

Ce que le cas ne dit pas

C’est une conduite interne, pas un système livré à un client financier : ce n’est pas sous git, les répertoires de test sont vides, et la correspondance approximative des noms utilise une heuristique de n-grammes que le code marque explicitement comme provisoire. Nous l’avons décrite ici parce qu’elle montre la méthode, et non parce que c’est un produit.

Questions

Ce qu’une personne des services financiers demande

L’agent approuve-t-il des paiements ou des crédits ?

Non, et ce n’est pas une limitation technique que nous dépasserons dans la prochaine version. L’approbation est une décision aux conséquences juridiques, qui appartient à une personne autorisée de l’institution. L’agent prépare : il catégorise, complète, signale ce qui ne correspond pas. Un système qui approuve seul devrait pouvoir répondre devant un contrôleur, et un score de confiance n’est pas une réponse.

Comment savoir qu’il a correctement catégorisé ?

Pas à partir du score de confiance — celui-ci est l’évaluation du modèle sur lui-même, pas une mesure. On le sait grâce à la comparaison avec les décisions de la personne qui fait aujourd’hui le travail, sur un ensemble de transactions réelles, effectuée avant de lancer quoi que ce soit en mode automatique. Le résultat de cette comparaison est un tableau que nous livrons, y compris les lignes où l’agent s’est trompé.

Que se passe-t-il quand il n’est pas sûr ?

Appelez l’outil « inconnu » et écrivez le motif. La ligne arrive dans la liste de travail de l’humain, pas dans une catégorie choisie au hasard pour donner l’impression que le système a fonctionné. Un classificateur sans sortie « je ne sais pas » se trompe précisément là où l’erreur coûte : sur les transactions inhabituelles.

Si nous lisons deux fois la même notification, le montant est-il doublé ?

Non. Chaque transaction a un identifiant externe calculé comme une empreinte sur ses champs, la colonne est unique, et l’insertion utilise `ON CONFLICT (external_id) DO NOTHING`. La ligne sautée est notée dans le journal comme doublon, donc on voit qu’elle a été relue.

Nos données partent-elles chez un fournisseur de modèle ?

Pour l’étape de classement, oui : la description de la transaction et le montant partent vers le modèle choisi, via notre passerelle, avec une clé de projet, une liste blanche de modèles et un budget. Le reste des étapes — lecture, extraction, déduplication, appariement des noms — est du code ordinaire et ne sort nulle part. Ce qui a le droit de partir est fixé par écrit à l’avance, pas découvert dans les journaux après coup.

Pouvez-vous lire des relevés PDF, pas seulement des notifications par e-mail ?

Oui, c’est l’un des modules du pipeline. Ce qu’il faut savoir, c’est qu’un relevé PDF est un format fragile : il se lit selon la structure produite par cette banque, et quand la banque change de modèle, le module doit être ajusté. C’est pourquoi il est écrit avec des vérifications qui échouent bruyamment, pas qui devinent.

Pourquoi est-il écrit sur cette page « offre » et pas « livré » ?

Parce que notre règle exige au moins deux implémentations propres pour écrire « livré », et le pipeline décrit ici fonctionne sur nos données, pas en production chez un client du secteur financier. Il a aussi des manques que nous nommons : il n’est pas sous git, il n’a pas de tests, et l’appariement des noms utilise une heuristique marquée dans le code comme provisoire. Quand nous pourrons citer deux implémentations chez des clients, nous changerons le mot.

De quoi avons-nous besoin de notre côté pour que le travail commence ?

Trois choses : la liste fermée des catégories dans lesquelles il a le droit de classer, un ensemble de transactions réelles avec la bonne réponse donnée par la personne qui fait aujourd’hui le travail, et la décision écrite sur les champs autorisés à sortir de votre réseau. Sans le troisième point, nous ne commençons pas, car c’est le seul qu’on ne peut pas réparer ensuite.

Qu'est-ce que vous voudriez voir mieux fonctionner ?

Racontez-nous votre processus. Ensemble, nous décidons ce qui vaut la peine d'être construit, ce que nous pouvons connecter et comment nous vérifions le résultat.

Discutons