Nos agents ont écrit le code. Voici comment on a vérifié leur travail.
Du vendredi au lundi, des agents IA ont implémenté notre prototype de LLM privé hébergé à Paris. Décisions écrites, critères d’acceptation, vérifications sur les machines et revue adverse : ce que cette méthode a permis de contrôler, ce qu’elle a révélé, ce qu’elle ne garantit pas.

Vendredi 6 novembre, après-midi : on définit le besoin et une dizaine de décisions d’architecture. Lundi 9 novembre au matin : le service est ouvert aux trois associés.
Entre les deux, un modèle open-weight s’est mis à tourner sur un GPU à Paris. Un veilleur l’éteint quand personne ne s’en sert et le rallume à la demande ; son architecture fait l’objet d’un article de la série. Un test rejouable envoie des requêtes marquées, puis recherche leur contenu dans les journaux et les fichiers de nos deux serveurs ; il n’y a retrouvé aucun marqueur, dans la configuration testée ; la méthode et ses limites ont aussi leur article.
Le code, les tests et la documentation ont été écrits par des agents IA. Notre travail a consisté à définir les garanties recherchées, à exclure les composants incompatibles, à arbitrer les compromis et à examiner les résultats avant de valider. C’est cette part-là que raconte cet article : ce qui change quand le vibe coding, décrire ce qu’on veut et laisser l’agent faire, touche à de l’infrastructure qui traitera les données de clients.
Une précision d’abord, parce que la question viendra : les agents de développement et le modèle que nous hébergeons sont deux maillons distincts. Héberger le second à Paris ne dit rien de l’endroit où les premiers traitent leur contexte. Le contrôle des données envoyées aux outils de développement se cadre séparément.
Méthode
Six étapes, deux pour l’humain, une pour casser
- Décision écrite, interdits comprishumain
- Ticket et critères mesurableshumain + agent
- Implémente, déploie, mesureagent
- Vérifie sur l’infra réelleagent
- Attaque : « qu’est-ce qui casse ? »agent
- Valide, preuves en mainhumain
- Une règle critique sans test : rien ne prouvait que le GPU reste allumé pendant une longue réponse.
- Une contre-épreuve qui pouvait exposer les autres : elle journalise toutes les requêtes reçues pendant sa fenêtre.
- Une erreur prise pour un succès : une réponse d’API illisible comptée comme « zéro snapshot ».
Avant toute implémentation, une dizaine de décisions, chacune en une ou deux phrases, datée, avec sa raison. Où héberger : Scaleway, à Paris. Pour qui : trois personnes, à travers leurs agents de code, sans interface de chat. Quel modèle. Et surtout, ce que veut dire « zéro rétention » : zéro contenu, pas zéro métadonnée.
La plus utile était une liste d’exclusions. Nous avions demandé de reprendre notre gabarit d’infrastructure habituel, éprouvé sur d’autres projets. Il prévoyait un proxy Cloudflare devant le service et Sentry pour le suivi d’erreurs. Le premier aurait terminé le chiffrement chez un tiers[1] ; le second aurait ajouté un circuit de collecte à contrôler pour en exclure tout contenu de requête[2]. Pour ce prototype, une décision écrite les supprime tous les deux, avec les sauvegardes de disques et l’export de journaux applicatifs.
Un agent optimise ce qu’on lui demande. Ce qu’on ne lui interdit pas, il le reprend de bonne foi, surtout s’il l’a vu marcher ailleurs. Écrire les interdits est un travail d’expert : il faut savoir quel composant, anodin ailleurs, casse une garantie ici.
Trois tickets : le serveur GPU, le veilleur, la preuve. Chacun avec des critères d’acceptation mesurables, pas des intentions :
- sans requête pendant le délai d’inactivité, le GPU s’éteint et ne facture plus le calcul ;
- la première requête suivante le rallume sans intervention, en moins de dix minutes ;
- un test montre qu’aucun contenu n’est écrit sur disque ni dans les journaux de la chaîne serveur ;
- le coût mensuel reste sous 150 € pour trois personnes.
C’étaient nos objectifs de départ. Le réveil dépend de la disponibilité des GPU chez l’hébergeur ; le budget dépend du temps pendant lequel ils restent allumés. Ce week-end ne fournit ni une garantie de disponibilité, ni une mesure du coût complet de la méthode.
« Fini » ne voulait pas dire « l’agent dit que c’est fini », mais : mesuré. Le serveur GPU a été livré avec ses chiffres (modèle prêt 2 min 29 après l’allumage, environ 61 tokens par seconde), le veilleur avec deux réveils chronométrés, la preuve avec la sortie complète de ses exécutions.
Chaque ticket passe entre trois rôles. Le premier agent implémente, déploie, mesure. Le deuxième vérifie sur l’infrastructure réelle que les critères sont tenus : il relance notamment tofu plan depuis une copie neuve du dépôt pour chercher les écarts sur les ressources gérées par OpenTofu[3], puis complète par des contrôles sur les machines et le rejeu des tests, car un plan sans changement ne dit rien de la configuration effective des serveurs. Le troisième relit le code avec une seule consigne : trouver ce qui casse.
C’est ce troisième rôle qui a le plus servi. Trois exemples :
- Une règle critique sans test. Le veilleur empêchait déjà l’extinction pendant une requête, mais rien ne le prouvait. Le relecteur a exigé un test de non-régression : il simule une requête en cours au-delà du délai d’inactivité et vérifie que l’extinction attend sa fin. Il ne remplace pas un essai avec une longue réponse réelle.
- Une contre-épreuve qui pouvait exposer les autres utilisateurs. Pour vérifier que le test sait détecter une fuite, on active volontairement les journaux du moteur. Pendant ce temps, toutes les requêtes reçues sont journalisées, y compris celles des autres. Le script refuse désormais de démarrer si une autre clé a servi récemment. Ce garde-fou ne bloque pas les appels concurrents : il les signale après coup, et leur contenu reste dans le journal en mémoire du serveur GPU jusqu’à son extinction. La contre-épreuve se joue donc hors usage, en prévenant ; nous ne l’avons pas rejouée depuis l’ouverture aux associés.
- Une erreur de lecture prise pour un succès. Une erreur de l’API de Scaleway, au moment de compter les snapshots de disques, pouvait être lue comme « zéro snapshot », donc conforme. Le script rejette désormais les comptes vides ou non numériques, et vérifie aussi la présence et le type des listes renvoyées : un champ absent rend le test non concluant au lieu d’être lu comme zéro.
Ces revues ont produit des corrections et un test de non-régression sur une règle critique. Une démonstration réussie n’aurait pas suffi à les faire apparaître.
Un agent est souvent sincère et parfois faux. Il a donc fallu exiger, à chaque étape, la trace de ce qui avait été fait : la sortie du script, la ligne de journal, le chronomètre.
Avant d’annoncer le service aux associés, on a demandé une vérification de bout en bout. Le fil de test semblait bloqué. Il attendait en réalité le réveil du GPU : le veilleur avait répondu quatre fois « Le GPU démarre », le client avait réessayé seul, et la réponse était arrivée 3 min 35 après l’envoi. C’est cette mesure, et pas une estimation, qui figure dans la documentation.
Les essais ont mis au jour trois limites de nature différente. Chacune appelle une réponse différente.
- Une capacité GPU non réservée. En testant la nouvelle commande « éteindre », un agent a rendu la machine à Scaleway[4] en pleine pénurie : quelques minutes plus tard, les indicateurs ne montraient plus aucun GPU disponible. Un rallumage a été accepté vers 10 h 12, environ deux minutes après. La documentation dit désormais en gras qu’éteindre rend la machine ; notre carnet de bord Scaleway raconte cette matinée. La réponse est une décision d’exploitation : accepter ce risque, ou payer une capacité réservée.
- Une identité de test confondue avec celle d’un utilisateur. Le script de vérification choisissait automatiquement la première clé disponible : celle d’un associé. Ses appels lui étaient donc attribués, puisque le journal identifie une clé, pas la personne à l’origine de chaque appel. La réponse est technique, et elle est en place : les tests ont désormais une identité dédiée.
- Un réglage du moteur incompatible avec la mémoire. Avec sa valeur par défaut, le moteur réservait de la mémoire pour 256 requêtes simultanées[5] et ne démarrait pas. Le diagnostic a pris une dizaine de minutes de GPU. La borne posée, 16, a permis au moteur de démarrer ; nos mesures portent sur un utilisateur, et la charge de trois agents simultanés reste à tester. La réponse est une règle : lire ce que font les réglages par défaut.
Les agents ont écrit le code, déployé, mesuré, relu, documenté. Ils ont même écrit une notice qui apprend à d’autres agents à piloter le serveur ; testée avec la question « le GPU est prêt ? », un agent a regardé l’état et répondu : « éteint, je ne l’ai pas allumé ».
Restaient à l’humain :
- les décisions : où héberger, quoi promettre, quoi exclure ;
- les arbitrages : passer le délai d’extinction de 15 à 10 minutes, accepter deux GPU plus petits pour la démonstration plutôt que de la repousser ;
- les secrets : les identifiants de déploiement, fournis par saisie sécurisée ; les clés personnelles d’accès au modèle, générées par l’infrastructure puis transmises en privé ;
- la validation : le merge, et l’exigence de preuve avant toute annonce ;
- l’acceptation du risque résiduel : ce que le prototype ne garantit pas, écrit noir sur blanc.
Pour un usage client, il resterait à cadrer ce que ce prototype n’a pas : les droits accordés aux agents, les changements soumis à une revue humaine, la procédure de retour arrière, et les données transmises aux agents de développement.
Si vous construisez votre produit avec des agents, vous pouvez aller loin. Pas sans garde-fous dès que le code touche à de l’infrastructure ou aux données de vos clients. Trois règles changent la nature du résultat :
- Écrivez vos décisions, et surtout vos interdits, avant de faire implémenter.
- Exigez des preuves : un chiffre, une sortie de test, une ligne de journal. Pas un « c’est fait ».
- Confiez la revue à un autre intervenant, avec les critères d’acceptation et la consigne de chercher les échecs. Une revue par agent apporte des objections supplémentaires ; elle ne suffit pas, seule, à autoriser un changement sensible.
Sur ce prototype interne, cette organisation a tenu du vendredi au lundi. Elle a surtout rendu les décisions, les résultats et les limites discutables sur pièces.
Sources
Cloudflare Docs — Encryption modes
developers.cloudflare.com · non daté · consulté le · Documentation vivante, mise à jour le 16 avril 2026 : le mode de chiffrement de la zone régit deux connexions distinctes, du visiteur à Cloudflare, puis de Cloudflare au serveur d’origine.
Sentry Docs (SDK Python) — Data Collected
docs.sentry.io · non daté · consulté le · Documentation vivante du SDK Python : le corps des requêtes HTTP entrantes peut être envoyé à Sentry ; l’en empêcher demande un réglage explicite (max_request_body_size à « never »).
OpenTofu — Command: plan
opentofu.org · non daté · consulté le · Documentation vivante, version 1.13 : le plan relit l’état des objets distants déjà gérés, compare la configuration à l’état précédent et propose les changements.
Scaleway (dépôt de la documentation) — How to power off your Instance
github.com · non daté · consulté le · Fichier source de la page scaleway.com/en/docs/instances/how-to/power-off-instance/, publiée le 26 mai 2021 et validée le 17 septembre 2025 : à l’extinction, la machine retourne au parc des machines disponibles. Le site refuse les lecteurs automatisés ; le texte a été lu dans ce dépôt officiel de Scaleway.
vLLM (code source) — vllm/engine/arg_utils.py, version v0.33.0
github.com · publié le · consulté le · Version de notre serveur. Sans réglage, max_num_seqs vaut 256 pour le serveur d’API sur un GPU de moins de 70 Go, comme le L40S ; la page des options de la documentation ne donne pas cette valeur.

