Agents IA on-premise : trois architectures
En bref
Trois runtimes d'agents évalués sur le même matériel et le même modèle, avec des seuils écrits avant la mesure. Ce qu'ils protègent, ce qu'ils laissent passer, ce qu'ils coûtent, et pourquoi le choix ne se joue pas là où on l'attend.
Choisir un runtime d’agent se réduit rarement à comparer des fonctionnalités. Les trois que nous exploitons ou avons évalués savent tous répondre, appeler des outils, mémoriser et planifier. Ce qui les sépare est ailleurs : dans ce qu’ils font sans qu’on le leur demande, dans ce qu’ils laissent accessible à l’agent, et dans ce qu’on peut relire avant que ça s’applique. Cet article met les trois côte à côte, avec les mesures et avec leurs limites.
Comparaison établie le 24 août 2026 à partir de deux POC menés les 22, 23 et 24 août sur le même matériel et le même modèle, et de l’exploitation courante de notre propre plateforme. Les chiffres cités sont ceux relevés pendant ces opérations.
Trois positions, pas trois concurrents
OpenClaw (notre plateforme interne) est la plateforme que nous construisons et exploitons. Elle est planifiée en sept phases, dont deux sont livrées, et elle porte aujourd’hui deux blocs matures : un agent de veille en service continu, et un pipeline de décision encadré par des règles codées hors de portée du modèle.
Hermes (agent conversationnel Python) a été évalué comme candidat pour les usages de messagerie. Neuf critères, huit tenus. Son POC a surtout mis au jour trois comportements non annoncés.
IronClaw (runtime Rust) a été évalué comme option pour les contextes les plus exigeants en confinement. Onze critères, deux échecs assumés, et un mode de protection des secrets que les deux autres n’atteignent pas.
Une précaution avant de comparer, parce qu’elle change la lecture du tableau : notre plateforme interne n’a pas été passée au même banc. Elle est en exploitation, pas en évaluation. Les cases vides de sa colonne signifient « non mesuré dans ce cadre », jamais « absent ».
Le tableau
| Mécanisme | OpenClaw (plateforme interne) | Hermes (agent Python) | IronClaw (runtime Rust) |
|---|---|---|---|
| Mécanisme d’identité | fichier unique sur disque (convention) | fichier unique posé par l’exploitant (convention) | quatre fichiers natifs, injectés à chaque tour (natif) |
| Qui écrit l’identité | l’exploitant (convention) | l’exploitant (convention) | l’agent lui-même, sous profil base de données (natif) |
| Identité relisible avant application | oui (convention) | oui (convention) | non, elle vit en base (natif) |
| Restriction d’outillage | native, par canal (natif) | native, outils non chargés (natif) | native et plus fine, par capacité (natif) |
| Secrets accessibles à l’agent | non mesuré | non mesuré | non, absence structurelle (natif) |
| Terminal accessible à l’agent | non mesuré | oui en ligne de commande (extensible : il vient du jeu d’outils chargé) | non par défaut, l’outil d’écriture étant désactivé (natif, réglable par capacité) |
| Cloisonnement réseau | liste blanche de sortie (hors produit) | liste blanche de sortie par compte (hors produit) | deux couches (natif + hors produit), chacune prouvée seule |
| Protection contre les requêtes détournées | non mesuré | non mesuré | oui, après résolution de nom (natif) |
| Bac à sable d’outils | non mesuré | non mesuré | WebAssembly, mémoire, temps et accès (natif) |
| Installation au démarrage | aucune (non mesuré) | deux paquets, à chaque lancement (natif) | aucune (natif) |
| Empreinte mémoire | non mesuré | 139 Mo | 193 Mo, plus 102 Mo de base |
| Pic processeur en génération | non mesuré | 209 % d’un cœur | 18 % d’un cœur |
| Latence par tour | non mesuré | 14,0 s à froid, 7,4 s à chaud | environ 22 s, plate |
Comment lire les marqueurs. (natif) : le mécanisme est fourni par le produit lui-même. (extensible) : il dépend des compétences ou outils chargés, donc il peut apparaître ou disparaître selon la configuration. (convention) : ce n’est pas un mécanisme du produit, c’est un fichier que l’exploitant pose et que rien n’oblige. (hors produit) : le contrôle vient de l’infrastructure, pas du runtime. (non mesuré) : les rapports de POC ne permettent pas de trancher. Les trois dernières lignes sont des mesures et non des mécanismes : elles ne portent pas de marqueur.
Le cas le plus parlant est celui du terminal. Chez l’agent Python, il n’est pas une propriété du produit : il apparaît parce que le jeu d’outils chargé en ligne de commande le fournit. Changer de jeu d’outils change la réponse. C’est exactement la différence entre une capacité native et une capacité extensible, et c’est ce qui rend la question « cet agent a-t-il accès au shell » insuffisante si on ne précise pas « avec quels outils chargés ».
Une réserve de méthode, à ne pas dissimuler
Les deux POC n’ont pas emprunté le même canal : l’agent Python a été éprouvé sur une messagerie, le runtime Rust sur son interface web. Les mesures de charge restent directement comparables, puisque le matériel, le modèle et le proxy de modèles étaient identiques. Les mesures d’adhérence aux consignes le sont moins : le canal influe sur le formatage attendu et sur la façon dont l’agent se présente.
Le dire est plus utile que de présenter douze lignes homogènes dont deux ne le sont pas.
Ce que la comparaison apprend vraiment
Le confinement et la gouvernance ne progressent pas ensemble
C’est le résultat le plus contre-intuitif. Le runtime le plus solide sur le confinement est le plus faible sur la gouvernance de l’identité.
D’un côté : secrets structurellement absents du processus d’outillage, double couche réseau, bac à sable éprouvé par trois témoins inverses, aucune installation, aucune télémétrie. De l’autre : une identité qui vit dans une base de données, écrite par l’agent lui-même, sans voie opérateur, donc ni versionnable ni relisible avant application.
Les deux autres font l’inverse : une identité qui est un fichier, donc revue, datée, comparable, et un confinement plus perméable.
Il n’y a pas de bon choix dans l’absolu. Il y a une question à se poser : dans votre contexte, le risque dominant est-il qu’un agent lise ce qu’il ne devrait pas, ou qu’une politique change sans que personne s’en aperçoive.
Un défaut d’usine est une décision qu’on prend pour vous
Trois exemples, un par produit, tous découverts par la mesure et non par la documentation.
Le runtime Rust expose cinquante et une portes d’approbation, toutes correctement conçues, et un réglage global d’approbation automatique actif à l’installation qui les neutralise ensemble.
L’agent Python demande trois réglages pour empêcher la création automatique de compétences là où la documentation en annonce un ; les deux autres sont actifs par défaut et absents de la configuration livrée.
Notre propre plateforme n’a pas échappé à la règle : son composant de contrôle appliquait ses règles correctement mais ne les journalisait pas, ce qui rendait invérifiable une affirmation que nous portions dans nos documents. Nous l’avons retirée, puis instrumentée.
Trois produits, un même schéma : ce qui n’est pas explicitement fermé est ouvert, et rien ne vous le signale.
La panne silencieuse est le mode de défaillance dominant
Sur les trois plateformes, les défauts les plus coûteux partagent une propriété : le système fonctionne, ne signale rien, et le résultat est faux.
Un jeton de veille expiré produit exactement ce que produit un service en bonne santé, à savoir aucune alerte. Un contrôle sans journal fonctionne peut-être parfaitement, mais rien ne permet de l’affirmer. Une passerelle en panne pendant que la ligne de commande répond parfaitement laisse croire à un produit fonctionnel. Des fichiers d’identité placés au mauvais endroit ne provoquent aucune erreur : ils sont simplement retrouvés par recherche sémantique au lieu d’être injectés, ce qui donne une adhérence intermittente.
La conséquence pratique est une règle de conception, pas une bonne intention : tout contrôle doit produire une trace, et tout contrôle qui ne produit rien doit être considéré comme absent jusqu’à preuve du contraire.
Un contrôle vaut par ce qu’il exerce, pas par ce qu’il affiche. C’est la seule phrase que je garderais si je devais n’en garder qu’une des trois évaluations. Elle s’applique aux produits qu’on achète, à ceux qu’on construit, et aux tableaux de bord qui prétendent les surveiller.
Le contrôle strict est aussi un instrument de mesure
Le comportement le plus important relevé pendant ces POC n’était pas cherché. C’est une liste blanche de sortie réseau qui l’a rendu visible : sans elle, l’installation de paquets à chaque démarrage aurait réussi silencieusement, et personne n’aurait su qu’un agent tirait du code à chaque réveil.
Un environnement contraint ne sert pas seulement à empêcher. Il sert à rendre bruyant ce qui, ailleurs, passe inaperçu.
Comment nous tranchons
Sans transformer cela en recommandation universelle, voici la logique que nous appliquons.
Pour un usage conversationnel interne, où l’enjeu est la disponibilité et le confort, l’agent Python est le plus rapide à chaud et le plus léger en mémoire, à condition de neutraliser explicitement l’installation au démarrage et les trois chemins de création de compétences.
Pour un contexte exigeant en confinement, où l’on doit pouvoir démontrer et pas seulement affirmer, le runtime Rust est le seul des trois à produire une absence plutôt qu’un refus, et le seul à faire tenir un bac à sable sous témoin inverse. Au prix d’une latence qui interdit l’échange interactif, et d’une gouvernance d’identité à compenser par une procédure.
Pour l’orchestration métier et tout ce qui doit être audité, notre plateforme interne reste le socle, parce que ses règles sont dans du code et non dans une invite, et parce qu’elles sont désormais tracées.
Le dernier mot revient à la même idée que les trois articles partagent : un contrôle vaut par ce qu’il exerce, pas par ce qu’il affiche.