Contexte
Un client soumis à de fortes contraintes de sécurité gère plusieurs centaines de sites et exécute chaque jour quatre processus administratifs récurrents : la maintenance des équipements sur le terrain, le traitement des événements parasites récurrents émis par ces équipements, la rédaction de rapports d’intervention pour ses propres clients et la vérification de la bonne réception du contrôle de santé périodique de chaque site. Les données d’entrée sont dispersées entre trois systèmes aux modes d’accès très différents : des rapports PDF reçus par courriel, un portail web métier sans API publique et des classeurs Excel tenus à la main depuis de nombreuses années.
L’objectif : automatiser ces processus sur un poste de travail de bureau tout en laissant à un opérateur humain le dernier mot sur chaque message adressé aux clients.
Contraintes de conception
- Aucun modèle de langage à l’exécution. Chaque décision découle de règles explicites et chaque phrase d’un modèle de texte. La sortie du robot est ainsi reproductible : les mêmes entrées produisent toujours les mêmes brouillons, de sorte qu’une nouvelle version peut être comparée mot pour mot à la production, et que toute modification peut être rattachée à une règle ou à une source de données. Aucune donnée client n’est transmise à un service de modèle externe. Un modèle vision-langage a été utilisé une seule fois, hors ligne, lors de la conception, pour cartographier des sessions d’écran enregistrées d’opérateurs ; il ne fait pas partie du système déployé.
- Des brouillons, pas des envois. Le robot se contente de créer des brouillons Outlook ; l’opérateur les relit et les envoie. Un interrupteur d’arrêt global impose le mode brouillon quels que soient les réglages propres à chaque processus.
- Exécution locale, sans nouvelle infrastructure. Python sur un poste Windows, tâches planifiées, dossier partagé sur NAS pour l’état et la configuration.
- Aucun secret en clair. Identifiants et jetons sont stockés dans le Gestionnaire d’identifiants Windows (DPAPI) ; la configuration est en YAML, modifiable par l’opérateur sans recompilation.
Architecture
Les quatre processus
Maintenance des équipements. Les lignes de panne extraites des rapports PDF quotidiens sont confrontées à l’historique des piles et des réparations de chaque appareil. Un arbre de décision ordonné (la première correspondance l’emporte) choisit entre ignorer, attendre, remplacer la pile, remplacer l’appareil ou tester la portée radio, et rédige un ordre d’intervention pour le technicien ; chaque appareil d’un ordre portant sur plusieurs appareils conserve sa propre décision.
Événements parasites récurrents. Le nombre d’événements par site et par appareil sur 24 heures est comparé à des seuils pour détecter les événements parasites récurrents. Les données du portail (un incident confirmé comme réel, un système mis à l’arrêt quelques minutes après une salve) priment sur ces comptages ; il en résulte un courriel de sensibilisation au client, un ordre d’intervention, ou rien.
Rapports d’intervention. Pour chaque intervention sur site, le robot reconstitue une chronologie unique à partir du journal d’événements du portail, du journal d’appels et des relevés des équipes de terrain, gère les événements à cheval sur minuit et rédige un rapport client accompagné des fichiers médias.
Contrôles de santé périodiques. Les sites dont le contrôle de santé périodique est absent sont identifiés, l’état de chaque canal de connectivité est vérifié sur le portail, puis un courriel au client, un ordre d’intervention ou une note interne est rédigé.
Rédiger un courriel : des paramètres au brouillon
Chaque brouillon est l’aboutissement d’une longue chaîne de décisions explicites. Comptés dans le code source (octobre 2026), les quatre moteurs de règles comportent 53 issues terminales (chaque endroit où une règle rend une décision), réparties sur 37 types de décision et 13 générateurs de brouillons.
Le courriel de sensibilisation du processus « événements parasites » en donne la mesure.
Un site n’y aboutit qu’après 14 tests ordonnés au plus dans le moteur de règles
(16 issues terminales pour ce seul processus). Le composeur lit ensuite 21 entrées :
17 champs de la fiche de décision du site et de la fiche client, la liste des
destinataires, les pièces jointes et deux ressources apprises (les noms de zones du
portail et un dictionnaire d’orthographe appris dans le classeur d’historique de
l’opérateur lui-même). Entre la décision et le texte final, on compte 108 points de
branchement conditionnel (instructions if, expressions conditionnelles et opérandes
booléens, comptés sur l’arbre syntaxique du composeur et des dix fonctions auxiliaires
qu’il appelle, avant la mise en forme HTML).
L’espace de formulation de ce seul courriel : 2 formes d’objet, 3 formes de salutation, 2 formes de phrase d’ouverture, 7 formulations de cause atteignables (dont deux avec ou sans renvoi aux médias joints), 2 demandes d’action et une liste facultative de 2 à 6 appareils. Tous les seuils ci-dessus sont dans la configuration YAML, pas dans le code.
| Paramètre | Source | Effet sur le courriel |
|---|---|---|
| Nombre d’événements sur 24 h | rapports quotidiens | chiffre de la phrase d’ouverture ; à partir de 30, préfixe d’urgence dans l’objet |
| Règle déclenchée | moteur de règles | choisit la formulation de la cause ; conditionne les vérifications « erreur de manipulation » et « site en activité » |
| Appareils concernés (nettoyés, dédoublonnés) | rapports quotidiens | un appareil nommé, ou une formule générique suivie d’une liste de 6 lignes au plus, par nombre d’événements |
| Code de l’appareil sur chaque ligne de rapport | rapports quotidiens | ajouté entre parenthèses à chaque appareil listé, seulement s’il est connu |
| Nom de zone de l’appareil principal | portail | remplace le libellé brut du rapport lorsqu’il est disponible |
| Graphies apprises | classeur d’historique de l’opérateur | rétablit accents et casse des noms d’appareils |
| Cellules civilité et nom du contact | fiche client | l’une des 3 formes de salutation ; plusieurs personnes, une fonction ou un nom d’organisation ramènent à la forme générique |
| Raison sociale | fiche client | forme juridique retirée, casse rétablie en conservant les sigles, utilisée dans l’objet et le corps |
| Type de site, heures d’ouverture apprises, interventions dans la fenêtre | classeur de suivi, journal du portail | active ou neutralise la formulation « site en activité » |
| Mise en marche ou à l’arrêt autour de la salve | journal du portail | formulation « erreur de manipulation » (2 variantes), prioritaire sur toute autre cause |
| Drapeaux du site | fiche client | choix entre les 2 demandes d’action |
| Présence de pièces jointes | médias du portail | renvoi aux pièces jointes, ou rien |
| Adresses des destinataires | fiche client | toutes les adresses trouvées ; à défaut, une boîte interne de repli |
Les autres brouillons s’appuient sur les mêmes fonctions partagées de rédaction en français : la préposition devant un nom de site s’accorde avec son premier nom (6 formes, de « chez » à « à l’ » et « aux ») ; les titres des rapports s’accordent en genre et en nombre ; les dates sont écrites en toutes lettres ; l’intitulé « Contact » passe au pluriel dès que plusieurs contacts sont listés ; et une table de 8 entrées traduit le jargon technique des équipements en vocabulaire client.
Ingénierie de la fiabilité
- Idempotence. Un registre quotidien indexé par site, type de message et empreinte de l’objet empêche les brouillons en double ; un registre inter-jours empêche de réémettre un ordre d’intervention avant que l’intervention précédente n’ait eu lieu. Les jours manqués sont rattrapés automatiquement.
- Concurrence sur un NAS partagé. Fichiers de verrou exclusifs (
O_CREAT|O_EXCL) avec une durée de vie pour les verrous orphelins ; deux postes publient des battements de cœur, et le poste secondaire ne prend le relais que lorsque le principal est silencieux depuis deux minutes. - Écritures sûres dans les classeurs. Les écritures passent par un fichier temporaire et un remplacement atomique, avec nouvelles tentatives lorsque le classeur est ouvert par un utilisateur ; les lignes insérées décalent les formules de pied de tableau pour que les totaux restent justes.
- Robustesse réseau. Les appels Graph gèrent le renouvellement des jetons, l’en-tête
Retry-Afterdes réponses HTTP 429 et le repli progressif sur les erreurs 5xx. - Échec explicite. Une enveloppe de plantage, sans dépendance au paquet principal, envoie une alerte expurgée et un signal d’homme mort même lorsque les imports échouent ; une sentinelle déclenche une alerte lorsque le portail ne renvoie aucune donnée au lieu de signaler un succès.
- Évaluation en parallèle (shadow). Une version bac à sable rejoue une journée en lecture seule et compare ses brouillons à ceux de la production. Le critère d’acceptation est la part des brouillons que l’opérateur envoie sans en modifier un seul mot.
Résultats
- 1 766 tests automatisés dans le dépôt (octobre 2026), reposant sur des adaptateurs simulés de messagerie et de portail, les tests sur systèmes réels étant marqués à part.
- Un audit du corpus de rapports reçus a montré que 9,5 % des lignes d’événements étaient écartées silencieusement, parce que les codes et libellés d’événements sont concaténés dans le texte extrait des PDF ; l’analyseur a été réécrit pour reconnaître les formes de codes effectivement émises.
- La mise en cache du classeur d’historique des pannes (1,49 Mo, 15 533 lignes) a réduit la durée du processus de maintenance des équipements, sur un rejeu de rapports réels, de 161,1 s à 23,3 s ; le nombre d’ouvertures du classeur est passé de 26 à 3.
- Première comparaison en parallèle sans écart avec la production : 14 brouillons de chaque côté, 14 en commun, 0 manquant, 0 en trop.
Stack technique
Python 3.11 · Microsoft Graph · MSAL · httpx · Playwright · pypdf ·
openpyxl · pydantic · keyring · pytest · PyInstaller