Des articles approfondis sur les technologies qui façonnent l'avenir.

Talorys : des agents IA stateful sur serverless

Comment exécuter un agent IA avec état sur du serverless sans état ? Talorys utilise Cloudflare Workers, Durable Objects et SQLite, le tout dans l'offre gratuite.

Illustration d'une petite maison reliée à un cube lumineux unique, au milieu d'une grille infinie de blocs qui ressemblent à des serveurs.
Un agent, un objet, un compte : l'application entière vit dans un seul Durable Object, sur la grille de quelqu'un d'autre.

Voici ma position à contre-courant, et je vais la défendre : un agent IA personnel est un meilleur candidat pour une infrastructure serverless que pour le Raspberry Pi posé sous votre bureau. Le projet Talorys, un assistant personnel open source qui se déploie dans votre propre compte Cloudflare avec un simple npx create-talorys@latest, est la meilleure preuve à ce jour que le problème de l'agent IA avec état sur du serverless sans état n'est pas seulement soluble, c'est un cas d'usage naturel. Et les gens de Hacker News qui débattent pour savoir si ça mérite le qualificatif « self-hosted » se trompent complètement de débat.

J'ai passé des années à faire tourner des infrastructures et à nettoyer les dégâts derrière. Ce qui tue le logiciel personnel auto-hébergé, ce n'est pas le déploiement, c'est le troisième mois : le disque se remplit de logs, le certificat TLS expire, et vous ne vous souvenez plus de l'unité systemd qui gère la planification. Talorys contourne toute cette classe de pannes en n'ayant tout simplement pas de serveur. Tout ce dont il a besoin (discussion, mémoire, tâches, rappels programmés) tourne sur l'offre gratuite de Cloudflare : Pages pour le frontend, un Worker privé pour l'API, un Durable Object adossé à SQLite pour tout l'état, et Workers AI pour le modèle. Coût mensuel pour un utilisateur : zéro.

Le vrai problème : les agents ont un état, le serverless non

Un agent IA est un paquet d'état longue durée qui se fait passer pour une application requête-réponse. Il lui faut un historique de conversation, des souvenirs durables, une liste de tâches, des jobs programmés qui se déclenchent à 7 h qu'il y ait quelqu'un de connecté ou non, et un endroit où stocker les sorties d'outils pendant qu'une chaîne en plusieurs étapes s'exécute. Chacun de ces éléments est hostile au modèle serverless classique, où votre fonction est un poisson rouge : elle se réveille, traite une requête, et oublie tout.

La réponse habituelle de l'industrie consiste à reconstituer l'état à la périphérie : Redis pour les données de session, Postgres pour les enregistrements durables, une file de messages plus un planificateur pour les tâches cron, une base vectorielle pour le rappel sémantique. Ça fonctionne, mais vous venez de reconstruire une batterie de serveurs avec des services managés, avec la facture et la surface opérationnelle qui vont avec. J'ai vu des équipes passer plus de temps d'ingénierie à relier entre eux cinq services avec état pour un agent qu'à écrire la logique de l'agent elle-même. Comme je l'ai déjà défendu, les agents LLM ne sont que des systèmes distribués, et les systèmes distribués sont le cimetière des bonnes intentions.

Talorys fait le pari inverse : mettre tout l'état au même endroit. Un seul Durable Object, nommé personal-agent, contient l'ensemble du monde : conversations, souvenirs, tâches, notes, projets, automatisations, sessions, réglages et suivi de l'usage, le tout dans sa base SQLite embarquée. Pas de KV, pas de D1, pas de R2, pas de Vectorize. Le README précise explicitement que rien de tout cela n'est provisionné. Ce n'est pas un hasard, c'est l'architecture.

Les Durable Objects, la botte secrète

Les Durable Objects sont la primitive la plus discrètement radicale du cloud aujourd'hui, et ce n'est pas de l'hyperbole. Un Durable Object est une instance unique de code, avec un stockage transactionnel à cohérence forte, physiquement colocalisé avec lui. Quand une requête arrive pour l'objet personal-agent, Cloudflare réveille cet objet en quelques millisecondes à partir de l'état froid, exécute votre code sur sa SQLite locale, puis le met en veille dès qu'il est inactif. Vous obtenez l'ergonomie d'un processus serveur longue durée avec le modèle de facturation d'une Lambda.

Pour un agent personnel mono-utilisateur, les limites bien connues de ce modèle deviennent des atouts :

  • Un seul écrivain, et c'est un atout. Un seul utilisateur signifie un seul écrivain. Toute l'horreur de la concurrence des états multi-tenants disparaît : vous obtenez un accès sérialisé et transactionnel à tout, gratuitement.
  • La colocalisation tue la latence. Les requêtes mémoire de l'agent, les recherches de tâches et l'historique des conversations sont des lectures SQLite sur disque local, et non des allers-retours réseau vers une base située dans une autre zone de disponibilité.
  • Les alarmes remplacent le cron. Les alarmes des Durable Objects permettent à l'objet de planifier ses propres réveils. Rappels, routines récurrentes et résumés quotidiens se déclenchent sans qu'aucune machine reste allumée : l'objet dort, l'alarme le réveille, il fait son travail, puis se rendort.
  • La mise en veille est gratuite. Le temps d'inactivité ne coûte rien. Un assistant personnel inactif 23 heures sur 24 est exactement la charge de travail pour laquelle la tarification serverless a été inventée.

C'est l'idée que j'aurais aimé voir retenue par davantage de gens dans ce projet. Si votre application est naturellement mono-utilisateur (un outil personnel, un espace de travail par client, un coordinateur par appareil), le modèle « un Durable Object par locataire » vous offre ce qui nécessitait autrefois un VPS : un petit ordinateur conceptuellement toujours en marche, qui ne coûte rien à l'arrêt et n'a jamais besoin d'un administrateur système. L'histoire de la planification vaut à elle seule le prix d'entrée. Quiconque a fait tourner une petite machine avec cron connaît le scénario catastrophe : la machine redémarre, le démon cron ne revient pas, et vous découvrez deux semaines plus tard que vos rappels se sont arrêtés en silence. Les alarmes sont une planification gérée par l'infrastructure, c'est une chose de moins à surveiller.

Le modèle réseau fait mieux que la plupart des configurations de production

Voici le point qui m'a fait réagir, venant d'un profil sécurité. Le Worker de l'agent dans Talorys est déployé avec workers_dev: false et preview_urls: false. Il n'a aucune URL publique. Le navigateur ne parle qu'à un site *.pages.dev ; une Pages Function sur /api/* transmet les requêtes au Worker via un service binding, le câblage interne et privé de Cloudflare entre les calculs d'un même compte. L'authentification et l'autorisation se font dans le Worker, pas dans le frontend.

Réfléchissez à ce que cela élimine. Plus de point d'accès API public à scanner. Pas de règles de pare-feu à mal configurer. Pas de reverse proxy à oublier de patcher. La surface d'attaque du backend de l'agent se résume, en pratique, à « il faut passer par le flux d'authentification du frontend ». J'ai examiné des déploiements de production dans de vraies entreprises, avec des budgets et des équipes sécurité, qui étaient moins bien protégés que ce projet perso. Le schéma d'incident le plus courant que j'ai vu dans les environnements cloud : un service interne « accessible uniquement en interne » qui, un jour, ne l'était plus, parce que quelqu'un s'était trompé dans la configuration d'un load balancer. Impossible de rendre public par erreur un service binding : l'URL n'existe tout simplement pas.

L'installeur mérite aussi une mention. Il hache le mot de passe propriétaire localement avec PBKDF2-SHA256, ne stocke que le hash comme secret Cloudflare, génère un secret de session de 256 bits, nomme les ressources de façon unique, puis vérifie le déploiement en production, notamment en contrôlant que les requêtes non authentifiées sont bien rejetées, sans consommer de quota d'inférence IA. Une vérification post-déploiement qui confirme que l'authentification refuse effectivement l'accès aux requêtes anonymes, c'est le genre de chose que j'ai écrit dans des comptes rendus d'incident. La voir dans un installeur d'une seule commande est une agréable surprise.

Forteresse avec une porte unique gardée et une salle intérieure scellée, accessible uniquement par un pont interne.
Une seule porte publique, zéro backend public : grâce aux service bindings, le Worker de l'agent n'a aucune URL à attaquer.

Vivre dans l'offre gratuite sans se mentir

L'offre gratuite est réelle, mais c'est un budget, pas un buffet à volonté. Cloudflare accorde aux comptes gratuits une allocation quotidienne de Workers AI mesurée en « Neurons », 10 000 par jour, ainsi que des quotas de requêtes et d'utilisation des Durable Objects. Ces chiffres sont fixés par Cloudflare et peuvent changer. Talorys gère cela plus honnêtement que la plupart des projets « gratuits » que j'ai vus : quand l'allocation IA est épuisée, le chat le dit clairement et reprend après la réinitialisation quotidienne, pendant que tâches, notes, souvenirs et rappels continuent de fonctionner, car aucun d'eux n'a besoin du modèle.

Les garde-fous méritent d'être repris dans vos propres projets. Talorys propose des plafonds configurables : nombre maximal de tokens en sortie, nombre maximal de tokens de contexte (l'historique ancien est résumé plutôt que tronqué silencieusement), nombre maximal d'appels d'outils et d'étapes de raisonnement par requête, nombre maximal de requêtes IA par jour, et nombre maximal d'exécutions IA planifiées par jour. C'est une position mature. Les boucles d'agent sans limite sont la façon la plus sûre de se réveiller avec une facture ou une panne de quota, et « l'agent a décidé d'appeler l'outil 40 fois » est un scénario que j'ai vu brûler de l'argent réel en production. Par ailleurs, le choix du projet de ne jamais utiliser l'IA pour les rappels et résumés simples est exactement le bon. Si un chemin de code est déterministe, ne le faites pas passer par un modèle probabiliste. C'est la même discipline que celle qui sous-tend la contrainte des sorties de modèle vers des décisions structurées : n'utilisez le modèle que là où un jugement est réellement nécessaire.

Une mise en garde issue des retours de la communauté : plusieurs personnes signalent des surprises de facturation opaques en combinant Workers AI avec des forfaits Workers payants, une comptabilité des Neurons qui ne correspond pas aux limites documentées, et des tickets support restés sans réponse. Je ne peux pas vérifier les détails, mais ça ressemble à un schéma que je connais bien : la facturation IA à l'usage est déroutante partout, et « compatible avec l'offre gratuite » ne veut pas dire « impossible à facturer ». Si vous déployez ce projet sur un forfait payant, configurez une alerte de dépense dans le tableau de bord Cloudflare dès le premier jour. Considérez l'interface d'usage du fournisseur comme la source de vérité, et non les estimations locales de l'application.

La querelle sur « self-hosted » passe à côté de l'essentiel

Maintenant, la concession qu'exige mon affirmation d'ouverture. Les commentaires en tête de ce projet sont une guerre de tranchées autour du mot « self-hosted », et les pinailleurs ont un vrai point : tout repose entièrement sur Cloudflare. Vos données vivent dans leurs centres de données, votre inférence tourne sur leurs GPU, et si demain ils modifient l'offre gratuite, votre assistant change avec. Appeler cela de l'auto-hébergement étire le mot au-delà de sa limite. La lecture charitable (aucun tiers au-delà d'un compte Cloudflare que vous contrôlez déjà, aucune télémétrie vers les développeurs, aucun opérateur intermédiaire) se décrit mieux comme « self-owned » ou « self-custodied ». Les mots comptent, et le projet recevrait moins de critiques avec de meilleurs termes.

Mais c'est là que les pinailleurs me perdent. Le vrai modèle de menace pour un logiciel personnel n'est pas « les conditions d'utilisation d'une entreprise pourraient changer ». C'est l'exfiltration de données, la télémétrie, et le développeur qui fait faillite et ferme la version hébergée. Sur ces trois points, Talorys est réellement solide : il n'y a aucun code d'analyse ou de suivi, rien ne remonte vers les auteurs, et il n'existe aucune version hébergée à fermer. Par ailleurs, le code est sous licence MIT et, comme l'a souligné un commentateur, rediriger les appels IA vers un serveur de modèle local ne demande qu'un petit patch. La pile entière peut même tourner localement avec wrangler dev et un fournisseur IA factice. Si Cloudflare devenait inacceptable, la sortie serait courte. Comparez avec l'application « self-hosted » moyenne, qui est en réalité un fichier Docker Compose tirant une image depuis le registre de quelqu'un, et qui appelle son serveur pour vérifier des licences.

Il y a aussi une critique plus juste enfouie dans le fil : rien ne prouve que l'assistant soit réellement bon. Une interface de chat, un CRUD de mémoire, des embeddings et du cron sont chacun triviaux à construire ; le harnais, le prompting, la politique de récupération des souvenirs et les schémas d'outils sont là où les assistants personnels réussissent ou échouent, et rien de tout cela n'est démontré par un schéma d'architecture propre. C'est vrai de presque tous les projets de ce genre, et c'est une bonne raison d'être sceptique. Jugez Talorys comme une infrastructure, un châssis bien conçu, et non comme un copilote éprouvé. Si vous évaluez des modèles pour ce type d'usage, notre article sur l'exécution de LLM sur votre propre matériel couvre l'autre extrémité du spectre de souveraineté.

Balance en laiton pesant un cadenas contre un petit nuage.
Contrôle et commodité sont sur les deux plateaux opposés : le compromis honnête oppose l'enfermement à la charge opérationnelle.

Ce qu'il faut reprendre de cette conception

Même si vous ne déployez jamais Talorys, cette architecture est une référence qui mérite d'être assimilée. Les idées transposables :

  1. Un objet par locataire. Si votre application est mono-utilisateur ou se partitionne proprement, colocalisez code et état dans un seul Durable Object, et supprimez votre couche de cache, votre file de messages et votre pool de connexions.
  2. Aucune URL de backend publique. Les service bindings avec workers_dev: false sont la victoire sécuritaire la moins coûteuse du serverless. Un service inaccessible ne peut pas être attaqué.
  3. Des alarmes plutôt que des machines cron. Une planification qui vit avec l'infrastructure survit aux redémarrages, aux redéploiements et à vos propres oublis.
  4. Une dégradation consciente des quotas. Concevez l'application pour que la dépendance coûteuse (le modèle) puisse échouer ou épuiser son quota pendant que le produit principal continue de fonctionner. La dégradation doit être une fonctionnalité, pas une panne.
  5. Des migrations en ajout seul. L'espace de noms du Durable Object n'est jamais recréé lors d'une mise à jour, et les migrations de schéma s'exécutent de façon transactionnelle à la première requête. C'est ainsi qu'on met à jour un serverless avec état sans jouer à la roulette des pertes de données.

La leçon plus large concerne la direction que prend le logiciel personnel. Pendant vingt ans, le choix était binaire : faire confiance à une entreprise SaaS avec vos données, ou devenir administrateur système à temps partiel. Les Durable Objects, et les primitives similaires que les autres clouds ne manqueront pas de livrer, ouvrent une troisième voie : un logiciel que vous seul contrôlez, opéré par une infrastructure que vous louez, pour un coût nul à l'échelle personnelle. Ce n'est pas de l'auto-hébergement. C'est peut-être mieux.