Agents à 12 facteurs : des modèles d’applications LLM fiables
(github.com/humanlayer)- 12-Factor Agents est un guide public qui formalise 12 principes pour créer des logiciels basés sur les LLM suffisamment fiables pour être proposés à des clients en production
- Selon ce guide, un bon agent ressemble moins à un système de type « on lui donne un prompt, un ensemble d’outils, puis il boucle jusqu’à l’objectif » qu’à une architecture qui insère des étapes LLM aux endroits nécessaires dans un logiciel déterministe
- Une boucle d’agent typique fonctionne ainsi : le LLM décide de l’étape suivante via un appel d’outil en JSON structuré, un code déterministe l’exécute, puis ajoute le résultat à la fenêtre de contexte, et le cycle se répète jusqu’à la fin
- De nombreux créateurs de SaaS démarrent rapidement avec un framework et atteignent une qualité de 70 à 80 %, mais cela reste insuffisant pour des fonctions exposées aux clients, ce qui les conduit à rétroconcevoir framework, prompts et flux, voire à tout recommencer depuis zéro
- La manière la plus rapide de livrer un logiciel IA de haute qualité aux clients n’est pas d’adopter un framework d’agents complet, mais d’intégrer à un produit existant de petits concepts de construction d’agents modulaires
La problématique du projet
- 12-Factor Agents est un projet public qui cherche à appliquer l’esprit de 12 Factor Apps aux principes de construction d’applications LLM
- La question centrale est : « quels principes peut-on utiliser pour créer un logiciel basé sur les LLM réellement assez bon pour être confié à des clients en production ? »
- Le projet part d’expériences menées avec divers frameworks d’agents, ainsi que de discussions avec des fondateurs de startups techniques au sein et autour de YC
- Beaucoup de fondateurs construisent leur propre stack plutôt que d’utiliser massivement des frameworks pour des agents en production orientés client
- Beaucoup de produits qualifiés d’« AI Agent » ne sont pas entièrement agentiques ; ils combinent plutôt, selon ce point de vue, des étapes LLM bien placées dans un code majoritairement déterministe
Perspective de base sur les agents
- Un bon agent ne se résume pas au schéma « prompt, boîte à outils, boucle jusqu’à atteindre l’objectif »
- On peut voir le logiciel comme un graphe orienté (DG), ce qui explique aussi pourquoi les anciens programmes étaient souvent représentés sous forme d’organigrammes
- Depuis environ 20 ans, les orchestrateurs DAG se sont largement répandus
- La promesse des agents est qu’au lieu de coder toutes les étapes et exceptions, l’ingénieur ne fournit que l’objectif et les transitions, tandis que le LLM décide du chemin à suivre en temps réel
- L’idée est d’écrire moins de code, de récupérer d’erreurs et de permettre au LLM de trouver de nouvelles solutions
- Mais, en pratique, cette approche ne fonctionnerait pas aussi bien qu’espéré
Modèle d’exécution de la boucle d’agent
- La boucle d’agent de base se compose de jugement du LLM → exécution d’outil → ajout du résultat au contexte → répétition
- Le flux est le suivant
- Le contexte initial peut être un message utilisateur, une exécution cron ou un événement de type webhook
- Le LLM décide de l’étape suivante ou de la fin
- L’étape suivante est produite sous forme d’appel d’outil en JSON structuré
- Un code déterministe exécute cet appel d’outil
- Le résultat d’exécution est ajouté à la fenêtre de contexte
- Si l’étape suivante est
done, la réponse finale est renvoyée
- L’exemple du README montre une boucle où
llm.determine_next_step(context)choisit l’étape suivante, puisexecute_step(next_step)l’exécute avant d’ajouter le résultat au contexte
Pourquoi 12 principes sont nécessaires
- En construisant HumanLayer, l’auteur a parlé avec au moins 100 créateurs de SaaS, généralement des fondateurs techniques cherchant à rendre leur produit existant plus agentique
- Leur parcours typique ressemble à ceci
- Ils décident de créer un agent
- Ils définissent le design produit, la cartographie UX et le problème à résoudre
- Pour aller vite, ils choisissent un framework donné
- Ils atteignent un niveau de qualité de 70 à 80 %
- Ils se rendent compte que 80 % ne suffisent pas pour la plupart des fonctions exposées aux clients
- Pour dépasser les 80 %, ils doivent rétroconcevoir le framework, les prompts et les flux
- Ils finissent par recommencer depuis le début
- Cette critique ne vise pas à attaquer les frameworks ni leurs créateurs ; le texte précise au contraire que les frameworks ont accéléré l’écosystème IA
- Le guide ne traite pas de MCP ; les exemples utilisent surtout TypeScript, mais les principes s’appliquent aussi à Python et à d’autres langages
Les 12 facteurs
- Même si les LLM deviennent toujours plus puissants, les techniques d’ingénierie essentielles pour rendre les logiciels basés sur les LLM plus fiables, plus extensibles et plus faciles à maintenir restent valables
- Les 12 facteurs sont les suivants
- Factor 1: Natural Language to Tool Calls : convertir le langage naturel en appels d’outils
- Factor 2: Own your prompts : garder la maîtrise de ses prompts
- Factor 3: Own your context window : garder la maîtrise de sa fenêtre de contexte
- Factor 4: Tools are just structured outputs : les outils ne sont que des sorties structurées
- Factor 5: Unify execution state and business state : unifier l’état d’exécution et l’état métier
- Factor 6: Launch/Pause/Resume with simple APIs : lancer, mettre en pause et reprendre avec des API simples
- Factor 7: Contact humans with tool calls : contacter des humains via des appels d’outils
- Factor 8: Own your control flow : garder la maîtrise de son flux de contrôle
- Factor 9: Compact Errors into Context Window : compacter les erreurs dans la fenêtre de contexte
- Factor 10: Small, Focused Agents : des agents petits et ciblés
- Factor 11: Trigger from anywhere, meet users where they are : déclencher depuis n’importe où et rejoindre les utilisateurs là où ils sont
- Factor 12: Make your agent a stateless reducer : faire de son agent un reducer sans état
- Un conseil supplémentaire est donné avec Factor 13: Pre-fetch all the context you might need : précharger tout le contexte dont on pourrait avoir besoin
Mise en pratique et ressources associées
- Adopter un framework complet au point d’aboutir de fait à une réécriture greenfield peut s’avérer contre-productif
- Les principes clés qui rendent un agent efficace peuvent souvent être obtenus via un framework, mais la voie la plus rapide pour livrer un logiciel IA de haute qualité aux clients consiste à intégrer à un produit existant des concepts plus petits et modulaires
- Selon le guide, même des ingénieurs logiciel expérimentés sans background IA peuvent définir et appliquer ces concepts modulaires
- Ressources associées : Building Effective Agents d’Anthropic, Prompts are Functions, Library patterns: Why frameworks are evil, The Wrong Abstraction
- Le contenu et les images sont fournis sous licence CC BY-SA 4.0, et le code sous licence Apache 2.0
1 commentaires
Avis sur Hacker News
Les points de cet article sont excellents. J’ai aussi une liste d’enseignements tirés de plusieurs années de pratique directe : https://mg.dev/lessons-learned-building-ai-agents/
Aujourd’hui, le principal élément que j’ajouterais serait de posséder soi-même la boucle de planification de plus bas niveau. La planification dynamique, c’est bien, mais il faut avoir sa propre boucle observation-orientation-décision-action (OODA), avec des heuristiques pour déterminer si l’on converge vers une solution (par ex. un scoring) ou des conditions de sortie (par ex. un nombre maximal d’itérations)
Il vaut aussi la peine d’envisager d’ajouter un moteur de workflow. Plutôt que de faire en sorte que le modèle maintienne et fasse avancer un workflow implicite sur plusieurs tours, il vaut mieux lui faire produire une spécification de workflow qui sera exécutée par ce moteur, puis rappeler le modèle à chaque étape si nécessaire
Je me demande comment des bibliothèques comme DSPY s’insèrent dans le facteur 2 : https://dspy.ai/, https://github.com/humanlayer/12-factor-agents/blob/main/con...
En lisant, j’ai vu qu’il était question de générer des prompts avec BAML. Personnellement, écrire à la main des prompts pour extraire des informations structurées à partir de données non structurées ne m’a pas semblé facile, et j’ai eu jusqu’ici une assez bonne expérience avec DSPY
Si l’on utilise les prompts bruts de BAML, je me demande comment vous voyez l’approche consistant à utiliser les prompts bruts de DSPY : https://dspy.ai/tutorials/observability/#using-inspect_histo...
Je ne suis pas entièrement d’accord avec cet article, https://www.chrismdp.com/beyond-prompting/, mais la comparaison cartes perforées → assembleur → C → langages de haut niveau est assez utile ici
Je ne sais pas encore quand la bonne abstraction émergera, et je ne pense pas que LangChain ou DSPY soient déjà le « langage de programmation C » de l’IA. Peut-être qu’ils le deviendront un jour
Pour l’instant, j’utiliserais plutôt un établi bas niveau qui me permette d’inspecter les tokens, de changer l’ordre des tokens spéciaux comme system/user/JSON, et de m’adapter rapidement aux particularités de nouveaux modèles sans être bloqué en attendant le support d’une bibliothèque
Un ancien article assez méconnu sur les patterns de frameworks m’a parlé tout au long de ma carrière, et je pense qu’il s’applique aussi ici : https://tomasp.net/blog/2015/library-frameworks/
Pour les raisons décrites dans l’article, et même au-delà — surtout dans une période comme aujourd’hui où tout évolue vite — il vaut mieux utiliser les LLM comme des bibliothèques plutôt que comme des frameworks. Cela dit, les frameworks sont plus sexy, plus faciles à vendre, et mènent au lock-in et à des services additionnels, donc ils sont davantage mis en avant
J’ai construit et viens de publier mon propre « framework d’agents IA », SecAI, basé sur le modèle d’acteurs, les machines à états et la programmation orientée aspect : https://github.com/pancsta/secai
J’aime particulièrement le point 5, « Unifier l’état d’exécution et l’état métier », et le point 8, « Posséder soi-même le flux de contrôle ». SecAI est essentiellement une bibliothèque de flux de contrôle par graphe ; elle n’utilise pas un DAG mais un multigraphe, et les appels LLM sont intégrés dans les nœuds du graphe
Le flux est enrichi par la négociation, l’annulation et des relations avec état, ce qui lui donne un comportement plus organique. Il inclut aussi des outils de développement dédiés souvent absents des autres frameworks (dbg, repl, svg), une programmation pensée pour l’échec, l’inspection détaillée de chaque étape, l’export automatique de données (métriques, traces, logs, SQL) et une intégration simple (bash)
J’ai aussi publié une première démo technique, avec une implémentation de référence deepresearch portée depuis AtomicAgents, qui montre les outils de développement : https://youtu.be/0VJzO1S-gV0
Les boutons Send/Stop correspondent en pratique au « Facteur 6. Démarrer/mettre en pause/reprendre avec une API simple », et il y a aussi une transparence réseau, donc c’est extensible
J’ajouterais encore un point : il faut prévoir le coût à grande échelle
Ces systèmes ne sont pas bon marché quand ils montent en charge ; si une tâche peut être traitée par un composant déterministe, mieux vaut essayer cette voie d’abord. Cela réduit non seulement les hallucinations et la latence, mais peut aussi faire une grande différence sur la rentabilité finale
Pour rendre chaque principe plus facile à suivre, ce serait bien d’avoir un récit cohérent qui traverse plusieurs facteurs. Par exemple, utiliser tout du long un exemple de système proche du réel rendrait la compréhension plus simple
J’aimerais continuer à le faire évoluer publiquement avec la communauté
Excellent. J’en ai déjà appris 80 % à la dure, et les 20 % restants semblent valoir la lecture
Personnellement, j’ai eu de bons résultats avec la combinaison LangGraph + schémas pydantic. Je suis aussi curieux de savoir quels outils d’autres personnes ont trouvés utiles
Cet article arrive exactement au moment où j’en avais besoin
Je suis en train d’expérimenter une idée de bac à sable audiovisuel. Quelque chose comme vvvv, mais beaucoup plus simple et réduit au minimum fonctionnel : https://kfs.mkj.lt/#audiovisllm, https://vvvv.org/
L’idée est d’insérer des « nœuds » LM chargés d’une tâche précise et dont la sortie est très limitée, ou de petits réseaux neuronaux locaux. C’est pourquoi un exemple comme « question -> answer: float » est très séduisant. Dans mon cas, certaines questions peuvent être assez abstraites, mais les pipelines en plusieurs étapes m’intéressent aussi
Je n’ai pas lu en détail, mais je veux utiliser autant que possible du code déterministe et recourir aux LLM le moins possible
À mon avis, c’est ce qui permet d’obtenir des résultats prévisibles, de faibles coûts d’exploitation, et c’est aussi un signal indiquant qu’il sera difficile pour d’autres de cloner rapidement la même app. Plutôt que d’utiliser tel quel un liant à la mode pour connecter les LLM à d’autres systèmes, j’ai plutôt tendance à fabriquer mes propres outils
Si ces conditions ne sont pas remplies ou ne sont pas nécessaires, je pense que quelqu’un pourra recréer la même solution en un rien de temps avec du vibe coding. Il faut garder le contrôle. C’est une colline sur laquelle je suis prêt à mourir. Cela ne veut pas dire que les LLM ne m’impressionnent pas ; c’est même tout le contraire