La première version de l’IA de Klickbee tenait en une idée simple : un prompt, une réponse. L’utilisateur écrit un brief, on l’injecte dans un gros prompt, et le modèle renvoie un objet structuré — une roadmap avec ses jalons et ses tâches. Techniquement : un seul appel generateObject, un schéma Zod pour garantir la forme.
Et honnêtement, ça marche. Pour transformer « refonte du site vitrine » en une roadmap plausible, un bon prompt suffit. Rapide à écrire, facile à comprendre, peu coûteux.
Le problème : ce modèle atteint un plafond dès que la tâche devient réelle.
En utilisant vraiment le produit, quatre défauts reviennent tout le temps. Aucun ne se règle avec « un meilleur prompt » — ils sont architecturaux.
Reconstruire la roadmap d’un dépôt GitLab à partir d’un simple prompt donne une fiction crédible, pas ce qui s’est passé. Il n’a pas accès aux commits, aux merge requests, aux issues.
Chaque échange repart de zéro. L’utilisateur explique une contrainte, et deux messages plus tard l’IA la redemande. Ça vire à l’interrogatoire.
Un one-shot rend sa première réponse, bonne ou mauvaise. Pas de recul, pas d’auto-critique.
Un champ mal typé renvoyé par le modèle, et tout le tour plante avec un « Failed to parse » incompréhensible côté utilisateur.
« Agent », ce n’est pas un buzzword pour « prompt un peu plus malin ». Le vrai changement, c’est de passer de générer une réponse à mener une tâche. Sur Klickbee, chaque IA importante est devenue un graphe (LangGraph) avec des étapes explicites.
Le tout est durable — l’état persiste dans Postgres, un run survit à un crash ou à une reprise plus tard — et tracé : chaque étape, chaque appel LLM est visible dans Langfuse pour déboguer et scorer.
répond.
va chercher, décide, vérifie, collabore, et reprend.
Le brief passe désormais par gather → clarify → draft → review → validate → apply. Le nœud draft est lui-même agentique : une boucle où le modèle appelle ses outils pour s’ancrer avant d’écrire. S’il manque une info clé — échéance, périmètre — il pose une question plutôt que de deviner. Puis il se relit et se corrige avant de montrer quoi que ce soit.
Ici l’ancrage change tout. L’agent lit les vrais commits, merge requests et issues, en mode autonome, et reconstruit une roadmap fidèle à ce qui a été livré — au lieu d’une histoire inventée.
Détail révélateur : l’API GitLab ne renvoie pas de total de commits sur certains endpoints ; il a fallu paginer pour ne plus afficher « 100 commits » à l’infini. L’agentique force à regarder le réel en face.
C’est là que la leçon a été la plus nette. La première version interrogeait l’utilisateur, une question après l’autre, en oubliant les réponses précédentes. On l’a basculée en act-first : agir par défaut avec des hypothèses explicites, ne demander qu’en cas de blocage réel, et se souvenir de toute la conversation. Comme un bon collègue, pas comme un formulaire.
Le petit dernier : on décrit « qui bosse sur quoi », l’agent étiquette les postes, compose les équipes, et — parce qu’il lit le roster existant — réutilise les membres et équipes déjà là au lieu de créer des doublons. Il pose une question quand deux personnes se marchent sur les pieds.
Ce que l’agentique apporte, concrètement :
Soyons honnêtes sur la facture : plus de complexité (un graphe, des nœuds, des outils), plus de tokens (plusieurs appels au lieu d’un), plus d’infra (une base pour l’état, du tracing). Un generateObject d’une ligne devient un sous-système.
Le vrai déclic n’est pas technique, c’est un changement de posture. On arrête de se demander « quel prompt me donnera la bonne réponse ? » et on commence à se demander « quelles étapes une personne compétente suivrait-elle pour faire ce travail ? » — puis on donne à l’IA les outils, la mémoire et les points de contrôle pour suivre ces étapes.
Sur Klickbee, c’est ce qui a fait passer l’IA de démo qui impressionne à outil sur lequel on peut vraiment travailler.
Il faut lever une ambiguïté que j’ai moi-même mis du temps à clarifier : un graphe LangGraph n’est pas automatiquement un agent. Anthropic pose la distinction la plus nette que je connaisse — un workflow orchestre LLM et outils sur des chemins de code prédéfinis, un agent laisse le modèle diriger son propre processus et décider quels outils appeler. Sur Klickbee, le graphe global reste largement un workflow (gather → clarify → draft → review → apply, des arêtes fixes), mais le nœud draft, lui, est vraiment agentique : c’est une boucle où le modèle choisit d’appeler tel outil, de reboucler ou de s’arrêter.
Le bon réflexe : rester en workflow tant que le chemin est connu d’avance, et n’ouvrir une zone agentique que là où la décision « quoi faire ensuite » dépend vraiment de ce que le modèle vient de découvrir. Chaque tour autonome coûte de la latence, des tokens, et laisse une erreur précoce se propager.
La durabilité dont je parlais n’est pas un vague « on sauvegarde en base ». LangGraph la modélise avec deux notions précises. Un checkpointer persiste l’état du graphe à chaque superstep, rattaché à un thread_id : c’est ce qui permet à un run de survivre à un crash et de reprendre exactement où il en était. Et un store, lui, sert la mémoire durable qui traverse les threads — les préférences et décisions qui doivent survivre d’une conversation à l’autre. La mémoire du chat d’ajustement, c’est le store ; la reprise après interruption, c’est le checkpointer.
Le human-in-the-loop m’a réservé le piège le plus subtil. Quand un nœud appelle interrupt() avec une valeur JSON-sérialisable, le graphe fige son état et attend indéfiniment ; on reprend plus tard, potentiellement dans une autre requête HTTP, avec Command(resume=…) et le même thread_id — la réponse humaine devient la valeur de retour de l’interrupt. Le piège : à la reprise, le nœud redémarre depuis le début, il ne repart pas de la ligne de l’interrupt. Tout code exécuté avant sera rejoué. La leçon : on met les effets de bord (écritures, appels d’API non idempotents) après le point d’interruption, pas avant.
« Il se relit » mérite d’être démonté, parce que c’est un patron nommé et étudié, pas une astuce maison. Anthropic l’appelle évaluateur-optimiseur : un LLM produit, un second évalue et renvoie un feedback, on boucle. Il ne brille que sous deux conditions — des critères d’évaluation clairs, et un gain mesurable à chaque itération. Sur la génération de roadmap, les deux sont réunies : « chaque tâche a-t-elle un jalon parent ? y a-t-il des doublons ? le périmètre du brief est-il couvert ? » sont des questions vérifiables.
La version la plus ambitieuse de ce patron s’appelle Reflexion. LangChain la décrit bien : au lieu d’une auto-critique purement interne, l’acteur ancre sa critique sur des données externes — il va chercher des preuves avant de se juger. Le guide Reflexion décompose ça en trois rôles : un acteur qui produit, un évaluateur qui score la trajectoire, et une auto-réflexion qui transforme ce score en consigne verbale pour le tour suivant. C’est exactement ce que fait mon nœud draft quand il relit les vrais commits GitLab avant de valider un plan.
le modèle se juge sur ce qu’il « pense ».
le modèle va chercher des preuves avant de se juger.
Une boucle sans garde-fou tourne à l’infini ou explose la facture. Trois protections : un plafond d’itérations (MAX_REVIEWS), une condition d’arrêt claire (« review.ok === true »), et une sortie structurée validée à chaque tour. Chez moi, le schéma Zod fait double emploi : la génération échoue plutôt que de renvoyer un objet invalide, ce qui transforme un « Failed to parse » silencieux en erreur qu’on peut rattraper et rejouer.