LangChain4j vs Spring AI : deux façons d'amener un LLM dans une JVM
Après avoir intégré Spring AI dans un backend Kotlin, la question naturelle a été de comparer avec LangChain4j, l'autre librairie JVM qui revient systématiquement dans les discussions sur l'IA côté Java et Kotlin. Les deux font sensiblement la même chose, appeler un LLM, gérer des outils, structurer une sortie, mais elles partent de deux points de départ opposés, et ce point de départ se ressent à chaque ligne de code.
Deux philosophies, pas deux implémentations d'une même idée#
Spring AI part du framework : un ChatClient s'injecte comme n'importe quel
bean Spring, la configuration passe par les mécanismes Spring habituels
(application.yml, auto-configuration), et l'intégration vise à disparaître
dans les conventions déjà en place sur un projet Spring Boot. LangChain4j
part du modèle : la librairie ne présuppose aucun framework, elle expose ses
propres abstractions (chains, agents, mémoire conversationnelle) que l'on
peut faire cohabiter avec Spring, Quarkus, Micronaut ou aucun framework du
tout.
| Spring AI | LangChain4j | |
|---|---|---|
| Point de départ | Le framework Spring | Le modèle et ses abstractions |
| Dépendance à un framework | Fort, pensé pour Spring Boot | Aucune, s'utilise indépendamment |
| Configuration | application.yml, auto-configuration Spring | Construction explicite en code |
| Sortie structurée | entity(), désérialisation directe | Interfaces AI Services, générées dynamiquement |
| Courbe d'adoption sur un projet Spring existant | Faible, s'intègre aux conventions en place | Moyenne, introduit son propre vocabulaire |
Ce que ça donne côté code#
Le même besoin, scorer une offre de mission par rapport à une stack, s'écrit en LangChain4j via une interface annotée plutôt qu'un appel impératif :
interface MissionScorer {
@SystemMessage("Tu scores une offre de 0 à 100 par rapport à la stack fournie.")
@UserMessage("Stack : {{stack}}\n\nOffre : {{mission}}")
ScoreResult score(@V("stack") String stack, @V("mission") String mission);
}
MissionScorer scorer = AiServices.create(MissionScorer.class, model);
ScoreResult result = scorer.score(stackSummary, missionDescription);L'interface MissionScorer n'a ici aucune implémentation écrite à la main :
LangChain4j en génère une dynamiquement à partir des annotations. C'est
élégant, et ça pousse le prompt au même niveau de première classe qu'une
signature de méthode. C'est aussi ce qui, pour un développeur venant d'un
monde Spring pur, demande un temps d'adaptation réel : le comportement n'est
plus dans le corps de la méthode, il est dans ses annotations.
Là où Spring AI gagne : un projet Spring Boot existant#
Sur un backend Spring Boot déjà en place, avec son auto-configuration, son observabilité et ses conventions établies, Spring AI a un avantage qui n'est pas technique mais organisationnel : il ne demande pas d'apprendre un nouveau vocabulaire, juste un nouveau type de bean.
C'était le cas pour l'exemple pris sur MissionMatch : Spring AI s'est glissé dans une architecture hexagonale existante sans rien redéfinir, parce que tout le reste du projet parlait déjà Spring.
Là où LangChain4j gagne : la portabilité et les agents#
LangChain4j prend l'avantage dès que le projet n'est pas un projet Spring, ou dès que le besoin dépasse un simple appel modèle : orchestration d'outils multiples, mémoire conversationnelle, agents qui enchaînent plusieurs appels. Ses abstractions sont pensées pour ces cas dès le départ, là où Spring AI reste plus proche d'un client HTTP typé que d'un framework d'orchestration d'agents.
Choisir LangChain4j pour ses capacités d'agent sur un projet qui n'a besoin, en réalité, que d'un appel modèle simple, importe une complexité et un vocabulaire qui ne se justifient pas. La question à se poser n'est pas « laquelle est la plus puissante », c'est « qu'est-ce que ce projet précis a vraiment besoin de faire ».
Le critère qui tranche, en pratique#
Le choix ne se fait pas sur des benchmarks de performance, les deux appellent le même modèle derrière une fine couche d'abstraction. Il se fait sur une seule question : le projet est-il déjà structuré autour de Spring, ou a-t-il besoin d'une librairie qui ne présuppose rien sur le reste de la stack ? Sur un backend Spring Boot existant, Spring AI coûte moins cher en adoption. Sur un projet neutre, ou qui a vraiment besoin d'orchestrer plusieurs outils et agents, LangChain4j offre un vocabulaire déjà pensé pour ça, que Spring AI n'a pas vocation à couvrir seul.