Aller au contenu

Architecture d'un agent IA sur une plateforme métier

Un agent IA sur une plateforme métier tient sur ses outils

Un agent IA branché sur une plateforme métier tient sur trois choses, des outils typés qui bornent ce qu'il peut lire, un jeu d'outils filtré par rôle, et une validation humaine avant toute action coûteuse. Le modèle est presque la partie interchangeable. Ce qui décide de la qualité du résultat, c'est le périmètre qu'on lui donne et la façon dont ses outils lui rendent la donnée.

Cet été, sur une mission à Toulouse, j'ai construit ce genre d'agent pour un éditeur de logiciel. Sa plateforme calcule des projections d'emploi et de compétences, et affiche des tableaux de bord que les utilisateurs doivent configurer à la main. L'objectif était de rendre tout ça promptable, donc de pouvoir poser une question en français et obtenir la bonne combinaison de résultats.

Je ne vais pas détailler le produit, il y a du confidentiel. En revanche l'architecture, elle, est reproductible telle quelle sur beaucoup d'autres métiers, et c'est ce que je raconte ici. Si la notion même d'agent est encore floue pour vous, j'ai posé les bases dans c'est quoi un agent IA.

graph LR
    A["👤 Utilisateur"] --> B["🔐 Back existant<br/>auth et rôles"]
    B --> C["🧠 Agent<br/>boucle outils, 25 tours max"]
    C --> D["🔧 Outils typés<br/>chargés selon le rôle"]
    D --> E["📊 Données<br/>base, fichiers, APIs"]
    C --> F["📝 Proposition de calcul<br/>en attente"]
    F --> G["✅ Bouton Exécuter<br/>décision humaine"]

Ce que l'agent fait, et ce qu'il ne fait jamais

L'agent répond sur des résultats déjà calculés, au niveau de ce que montre un tableau de bord, et il aide l'utilisateur à cadrer son besoin. Il propose des calculs, il n'en lance aucun de sa propre initiative. Ce périmètre a été posé avant la première ligne de code, et il a plus fait pour la fiabilité que n'importe quel réglage de prompt.

La règle la plus structurante est celle-ci. Aucun chiffre ne sort du modèle. Tout nombre affiché à l'utilisateur vient d'un appel d'outil du tour en cours, le modèle choisit quoi consulter, commente, et met en forme. Cette règle ne tient pas parce qu'on l'a écrite dans le prompt, elle tient parce que les outils renvoient des valeurs calculées côté serveur et que le modèle n'a jamais la donnée brute sous les yeux.

Techniquement c'est un petit service Python en FastAPI, posé à côté de la plateforme existante. Il n'est pas exposé, il ne parle qu'au back historique qui a déjà validé l'identité de l'utilisateur, et il répond en streaming pour que l'interface affiche les outils appelés au fur et à mesure. Je m'arrête là sur la plomberie, ce n'est pas elle qui fait la différence.

Interchangeable ne veut pas dire indolore

Le modèle est appelé via une API compatible OpenAI. Les routes et le format des requêtes sont les mêmes d'un fournisseur à l'autre, donc passer d'un modèle cloud à un modèle auto-hébergé revient à changer une URL de base, sans toucher aux outils. C'est ce qui rend une bascule on-premise crédible plus tard.

Ça ne veut pas dire que tous les fournisseurs se comportent pareil. J'ai passé une bonne demi-journée sur un bug où, en streaming, les arguments d'un appel d'outil arrivaient en entier dans plusieurs morceaux successifs au lieu d'arriver par incréments. Le SDK les concaténait, et produisait deux objets JSON collés l'un derrière l'autre.

Résultat, l'outil échouait, et surtout l'appel invalide était écrit dans l'historique de la conversation. Au tour suivant le fournisseur rejetait tout le message, et la conversation devenait définitivement irrécupérable. Le correctif tient en quelques lignes, on ne garde que le premier objet JSON complet, au moment où l'appel est finalisé, pour réparer à la fois le tour en cours et la mémoire. La leçon est plus large que le bug, ce genre de correctif appartient à une couche d'adaptation du modèle, jamais aux outils.

Les outils sont le périmètre réel, pas le prompt

Avant d'écrire le premier outil, il y a un choix d'architecture à faire. Soit on donne au modèle un interpréteur et il écrit du Python pour aller chercher ce dont il a besoin, soit on lui donne une liste de fonctions typées et il n'a que celles-là.

La première option est celle des agents de code, et elle a de vrais avantages. Le modèle compose, filtre, agrège et enchaîne en une seule action ce qui demanderait cinq appels d'outils. Il répond à des questions qu'on n'avait pas anticipées, sans qu'on ait à livrer une nouvelle fonction. C'est exactement ce qui rend un agent efficace sur un dépôt de code, où l'utilisateur sait lire ce qui a été exécuté.

Ici l'utilisateur est un professionnel RH devant un chiffre qui va nourrir une décision. Il ne relira pas le code, et une jointure fausse produit un résultat crédible et faux, ce qui est pire qu'une absence de réponse. Trois raisons ont fait pencher la balance.

  • Les droits doivent tenir par construction, or un interpréteur qui ouvre un fichier court-circuite le filtrage par rôle
  • Le résultat doit être reproductible, deux exécutions de la même question doivent donner le même nombre
  • La trace doit être lisible par l'utilisateur, un nom de fonction et un compteur se comprennent, un script généré à la volée non

Donc fonctions typées d'abord. Le bac à sable Python en lecture seule, sans réseau et avec des limites de mémoire, est prévu dans la conception mais désactivé par défaut. On l'ouvrira si une famille de questions le justifie vraiment.

Le prix à payer est réel, il faut écrire et maintenir chaque outil, et une question hors périmètre reçoit un je ne peux pas au lieu d'une réponse improvisée. Sur une plateforme métier, ce compromis se défend. Sur un agent de code, il serait absurde.

L'agent dispose de 23 outils au maximum, répartis en six familles. C'est peu si on compte les fonctionnalités du produit, et c'est déjà beaucoup pour un modèle qui doit choisir le bon.

Famille Ce que l'agent peut faire
Contexte savoir qui est l'utilisateur, lister les périmètres accessibles, décrire leur paramétrage
Catalogue lire les référentiels complets, sans aucun chiffre
Résultats lister les tableaux de bord existants, en charger un, en recalculer une combinaison
Fichiers décrire un fichier, lister les valeurs d'une colonne, lire quelques lignes filtrées
Documents lister les documents déposés par l'utilisateur et en lire une tranche
Calculs estimer un calcul, préparer une proposition, suivre les calculs en cours

Le point important n'est pas la liste, c'est que tous les utilisateurs ne la reçoivent pas. Le jeu d'outils est assemblé à chaque conversation en fonction des droits de la personne. Un utilisateur en lecture seule reçoit 17 outils et aucun outil de préparation de calcul. Pas un outil désactivé, pas un outil qui refuse poliment, un outil absent.

C'est la barrière la plus solide que je connaisse pour un agent en entreprise. Un outil non chargé n'existe pas pour le modèle, donc il ne peut ni l'appeler ni halluciner qu'il l'a appelé. Le prompt système est généré à partir des mêmes droits, et il annonce explicitement à l'agent ce qui est hors de portée pour cet utilisateur, avec la consigne de renvoyer vers l'administrateur de son organisation plutôt que de faire semblant.

La faille que j'avais laissée passer

Le contrôle des droits était fait une fois, en début de conversation, sur le périmètre courant. Ça semblait suffisant. Sauf que le modèle peut passer un identifiant de projet en argument d'un outil, et rien ne l'oblige à reprendre celui de la conversation.

Un identifiant appartenant à une autre organisation, et l'outil répondait. Paramétrage, catalogues, historique de calculs, le tout depuis une conversation parfaitement légitime. Le correctif a été de faire passer chaque outil qui accepte un identifiant par un point de contrôle unique, qui recharge la ressource et revérifie les droits sur celle qui est réellement visée. Le même raisonnement que pour la sur-permission d'un RAG, avec une surface d'attaque en plus, les arguments que le modèle choisit lui-même.

Chaque résultat d'outil dit ce qu'il n'a pas regardé

Tous les outils renvoient la même enveloppe, la donnée utile plus quatre champs de contexte. Le nombre d'éléments examinés, le nombre total, la source, et un booléen qui dit si le résultat est tronqué. Le modèle voit cette enveloppe, et l'interface affiche la même chose à l'utilisateur, du type 247 métiers explorés sur 247.

Ça résout un problème que je vois dans beaucoup d'agents branchés sur de la donnée réelle. Un outil renvoie les 50 premières lignes, le modèle les résume, et rédige sa réponse comme si c'était l'ensemble. Personne ne ment, et pourtant le résultat est faux. Avec l'enveloppe, l'information manquante est explicite dans le retour d'outil, et la consigne devient vérifiable, si c'est tronqué on le dit au lieu de conclure.

L'autre effet est côté utilisateur. La liste des outils appelés, avec les compteurs, est affichée pendant la réponse. On ne demande pas à l'utilisateur de croire l'agent, on lui montre ce qui a été consulté. C'est un des patterns de confiance les plus rentables que je connaisse sur un produit IA, j'en avais listé d'autres dans les patterns de feedback utilisateur.

Dernier détail qui compte, quand un outil échoue, il renvoie un message d'erreur propre et court, jamais une trace technique. Une stacktrace dans un retour d'outil, c'est du bruit que le modèle va essayer d'interpréter, et souvent de la fuite d'information sur l'infrastructure.

Pourquoi plafonner les itérations et les volumes ?

Un agent, c'est une boucle. Le modèle appelle un outil, lit le résultat, décide s'il en appelle un autre, et recommence jusqu'à répondre. Sans plafond, cette boucle peut tourner longtemps, en général quand le modèle rappelle le même outil en espérant un autre résultat.

J'ai fixé la limite à 25 tours pour un message utilisateur. C'est confortable, un enchaînement normal en consomme trois ou quatre, décrire un fichier puis lire les lignes intéressantes puis recalculer. Et ça coupe net les boucles pathologiques avant qu'elles ne coûtent une facture et deux minutes d'attente.

Les autres bornes sont sur le volume, et elles sont tout aussi importantes.

  • 50 lignes maximum par lecture de fichier
  • 200 objets maximum par listing de stockage
  • 500 valeurs distinctes maximum pour une colonne
  • 8 Mo et 100 000 caractères de texte extrait par document
  • un seul calcul lourd en cours à la fois sur un même périmètre

Ces chiffres ne sont pas des réglages de performance, ce sont des décisions de conception. Un agent ne voit jamais un fichier en entier, il l'explore par questions successives, exactement comme un humain qui ouvrirait un tableur. Ça oblige à écrire des outils plus fins, et ça évite de payer un contexte énorme pour une réponse de trois lignes.

Soyons honnête sur ce qui manque encore. L'historique de conversation n'est pas tronqué, donc une longue session renvoie tout au modèle à chaque tour, et le coût monte avec la durée de l'échange. C'est le prochain chantier, et le sujet est plus subtil qu'il n'y paraît, j'en ai parlé dans l'article sur la mémoire des agents IA.

La validation humaine avant tout calcul coûteux

Sur cette plateforme, un calcul se compte en dizaines de minutes et en appels de modèle facturés. Laisser un agent en déclencher un parce qu'il a cru comprendre une intention, c'est non. Mais l'empêcher complètement, c'est se priver de l'intérêt de l'agent.

Le pattern retenu vient directement de ce que font Codex et Claude Code sur l'exécution de commandes, avec deux axes séparés. Ce que le rôle a le droit de faire, qui est décidé par le jeu d'outils chargé. Et le moment où on demande l'accord, qui est décidé par l'interface. Lecture libre, écriture soumise à validation.

Concrètement, les outils d'écriture s'appellent tous préparer quelque chose. Ils enregistrent une proposition, avec un résumé, une durée estimée et un coût estimé, et ils rendent la main. Rien ne démarre. L'interface affiche la proposition, l'utilisateur clique sur Exécuter, et c'est cette action-là qui lance le calcul. La proposition suit ensuite un cycle de vie explicite, proposée puis lancée puis terminée, ou refusée.

Le nommage compte plus qu'on ne croit. Tant que l'outil s'appelait lancer quelque chose, le modèle annonçait à l'utilisateur que le calcul avait démarré. Renommer les outils en préparer a suffi à corriger le discours, parce que le modèle décrit ce que fait la fonction qu'il appelle. Un détail de vocabulaire dans une signature de fonction, et le message utilisateur devient honnête.

Une dernière précaution qui coûte trois lignes. Au moment du clic sur Exécuter, on revérifie les droits. Entre la proposition et la validation, il peut s'écouler des heures, et un accès a pu être retiré entre-temps.

Ce que la même architecture donnerait dans l'aéronautique

Je travaille à Toulouse, donc la question m'est souvent posée sous une forme aéronautique. La plateforme dont je parle ici sert des professionnels RH, mais j'ai mis en place des structures similaires dans l'aéronautique, et le problème de fond ne change pas. Des données lourdes, déjà calculées, que des experts consultent à travers des tableaux de bord qu'ils configurent eux-mêmes.

Quatre transpositions me paraissent directes.

  • Fiabilité de flotte. Un agent qui répond au niveau du tableau de bord de fiabilité, recalcule une combinaison période, type d'avion et chapitre ATA sans relancer de traitement, et prépare l'analyse lourde que l'ingénieur valide. C'est très exactement le service que j'ai décrit, avec un autre référentiel.
  • Qualité et non-conformités. Sur un corpus de fiches de non-conformité ou de 8D, les mêmes outils bornés servent à explorer, et la partie modèle sert à regrouper les formulations différentes d'un même défaut récurrent.
  • Essais et bancs. Les campagnes d'essais produisent des volumes que personne ne relit en entier. Un agent outillé pour décrire, filtrer et extraire, sans jamais dumper le fichier, est un bien meilleur point d'entrée qu'un chatbot branché sur tout.
  • Documentation technique. Un copilote sur les manuels de maintenance relève plutôt du RAG, mais il hérite des mêmes règles, réponses sourcées, périmètre par rôle, et aucune affirmation sans document à l'appui.

Les trois exigences que j'entends systématiquement chez les industriels du secteur sont celles qui ont structuré ce service. Le cloisonnement strict entre organisations, vérifié à chaque appel et pas seulement à la connexion. La traçabilité de ce qui a été consulté, et surtout de ce qui ne l'a pas été. Et la possibilité de faire tourner le modèle sur leur infrastructure, ce qui reste réaliste tant que les outils ne dépendent pas du fournisseur.

C'est aussi le type d'architecture que je mets en place en tant que consultant IA à Toulouse, sur des données qui ne sortent pas de l'entreprise.

FAQ sur l'architecture d'un agent IA

Comment concevoir les outils d'un agent IA ? En partant de ce que l'agent a le droit de lire et de faire, pas de ce que le modèle sait faire. Chaque outil est une fonction typée qui renvoie une valeur dérivée et bornée, jamais un dump de données brutes. Le jeu d'outils chargé définit le périmètre réel, puisqu'un outil non chargé n'existe pas pour le modèle.

Combien d'outils faut-il donner à un agent IA ? Assez pour couvrir les questions réelles, pas plus. Ici le maximum est de 23 outils, dont 17 en lecture seule. Le découpage compte plus que le nombre. Un outil au résultat borné et explicite vaut mieux que trois outils qui se recouvrent et que le modèle confond.

Faut-il donner des outils typés ou un interpréteur de code à un agent IA ? Cela dépend de qui relit le résultat. Un interpréteur donne plus de liberté et fait en une action ce que plusieurs outils feraient, c'est le bon choix pour un agent de code. Sur une plateforme métier, les fonctions typées l'emportent, les droits tiennent par construction, le résultat est reproductible et la trace reste lisible par un utilisateur non technique.

Pourquoi limiter le nombre d'itérations d'un agent IA ? Parce qu'un agent qui boucle coûte de l'argent et du temps sans rien produire. La limite est un plafond dur sur le nombre d'allers-retours entre le modèle et ses outils pour un seul message. J'ai retenu 25 tours, largement de quoi enchaîner plusieurs lectures, et assez bas pour couper une boucle.

Comment empêcher un agent IA d'inventer des chiffres ? En interdisant au modèle de produire lui-même le moindre nombre. Tout chiffre affiché vient d'un appel d'outil du tour en cours. La règle tient parce que les outils calculent côté serveur et que le modèle ne voit jamais la donnée brute, pas parce que le prompt le demande.

Faut il une validation humaine dans un agent IA en entreprise ? Oui dès qu'une action est coûteuse, lente ou irréversible. Séparez ce que le rôle a le droit de faire et le moment où on demande l'accord. Les outils d'écriture enregistrent une proposition avec son coût et sa durée estimés, un bouton de l'interface déclenche l'exécution réelle.

Comment un agent IA gère les droits d'accès des utilisateurs ? En chargeant un jeu d'outils différent selon le rôle, et en revérifiant les droits à chaque appel sur la ressource réellement visée. Un contrôle fait une seule fois en début de conversation ne suffit pas, puisque le modèle peut passer l'identifiant d'une autre ressource en argument.

Peut-on changer de modèle LLM sans réécrire son agent ? En grande partie oui, si les outils sont indépendants du moteur et que le fournisseur expose une API compatible OpenAI. Les routes et le format des requêtes sont identiques, donc changer l'URL de base suffit. Prévoyez quand même des différences de comportement en streaming, à absorber dans une couche d'adaptation.

Pour aller plus loin

Si mes articles vous intéressent, que vous avez des questions ou simplement envie de discuter de vos propres défis liés à l'IA, n'hésitez pas à m'écrire à anas@tensoria.fr, j'adore échanger sur ces sujets !

Vous avez une plateforme métier sur laquelle vous voulez brancher un agent, et des données qui ne doivent pas en sortir ? Réservez un créneau d'échange, le cadrage est gratuit.


À propos de moi

Je suis Anas Rabhi, consultant Data Scientist freelance. J'accompagne les entreprises dans leur stratégie et mise en œuvre de solutions d'IA (RAG, Agents, NLP).

Découvrez mes services sur tensoria.fr ou testez notre solution d'agents IA heeya.fr.