Avec l’idée que « la gestion d’état et le contrôle du flux deviendraient plus propres », j’ai adopté LangGraph, mais le code est au contraire devenu plus complexe.
Ceci est un retour d’expérience, mis au propre et partagé, sur le fait qu’introduire un framework peut aussi dégrader l’architecture.
Après diagnostic, la situation était la suivante :
- Le graphe n’avait qu’un seul nœud. Avec une structure
current_step → END, il n’y avait ni arêtes conditionnelles ni embranchements, etgraph.invoke()revenait exactement à appeler directement une fonction. La transition entre étapes était décidée par le code de service en dehors du graphe. - Le même état était stocké à deux endroits. Le
MemorySaverde LangGraph (en mémoire) et un checkpointer PostgreSQL maison sauvegardaient et restauraient en double la même session, provoquant des incohérences. - Environ 8 700 lignes de code dupliquées dans 3 exécuteurs LangGraph (Executor). La logique métier réelle se résumait essentiellement à « appel du LLM + assemblage du prompt », tandis que tout le reste concernait surtout la gestion d’état, les branchements conditionnels et des correctifs pour les edge cases.
En apparence, le problème venait du fait que les vraies fonctionnalités du framework (arêtes conditionnelles, checkpointer intégré, Human-in-the-Loop) n’étaient pas utilisées, et qu’il n’avait été introduit que comme une coquille vide. Mais en creusant davantage, la cause était ailleurs.
- La majeure partie avait été produite en vibe coding, mais sans examiner en profondeur le code interne ni les principes de conception pendant la réalisation ; à chaque fois, seule l’intention et les exigences étaient reformulées avant de poursuivre l’implémentation.
- Le problème n’était pas le vibe coding en lui-même, mais l’avancement sans validation. Cela optimise seulement la fonctionnalité immédiate, sans préserver les frontières de responsabilité de l’architecture globale. Le double checkpointing, l’état dispersé et la logique dupliquée étaient tous le résultat accumulé d’optimisations locales.
- Le vrai problème n’était pas l’absence de concepteur, mais le fait de donner des instructions au-dessus du framework sans avoir suffisamment compris ce qu’il était censé prendre en charge par conception.
J’ai donc pris du recul et voici comment j’ai corrigé cela.
- Séparation des sessions via une topologie indépendante + isolation par
thread_id - Dans le
State, ne garder que les métadonnées et déplacer le contenu vers leStore - Utilisation de
tool_usenatif à la place du parsing par regex - Séparation des nœuds pour permettre les tests
- Moi-même, j’avais besoin d’une compréhension précise du framework et d’une structure d’utilisation adaptée
Ce n’est pas un billet sur « comment l’utiliser », mais sur « comment je l’ai mal utilisé ».
2 commentaires
Il semble que tous les cas d’usage de langchain et langgraph puissent être remplacés par l’AI SDK.
C’est vrai. Je suis d’accord. Cela créera sans doute une dépendance au SDK, mais vu la courbe d’apprentissage élevée, ce sera peut-être préférable.