Java en tant que langage de production pour l’IA : Spring Boot, RAG et pgvector
Une carte pratique pour mettre en place des services RAG sur la JVM à l’aide de Spring AI ou LangChain4j, choisir un stockage vectoriel, ainsi que gérer les locations, les coûts, l’évaluation et les solutions de secours.
Python est utilisé pour entraîner les modèles, tandis que Java devient progressivement le langage qui permet de les déployer. Pendant environ trois ans, le domaine de l’IA ressemblait à une conférence dédiée à Python, mais avec un budget plus important : des démonstrations dans des notebooks, des tutoriels commençant par pip install, ainsi que des diagrammes d’architecture où une petite boîte intitulée « Python LLM service » était représentée séparément du vrai backend. Ce dernier était généralement Spring Boot, déjà chargé de l’authentification, de la facturation, des journaux d’audit et de la base de données.
Cette petite boîte n’est plus obligatoire. Spring AI a dépassé la version 1.0 et est désormais à la version 2.0. LangChain4j constitue une véritable bibliothèque JVM disposant de plus de vingt fournisseurs de modèles et de plus de trente entrepôts vectoriels. PostgreSQL stocke les embeddings grâce à pgvector. Un service Spring Boot déjà en cours d’exécution peut appeler un LLM, récupérer du contexte pertinent, invoquer des outils, transmettre des tokens et publier des métriques Micrometer, tout cela directement à l’intérieur de la JVM.
Cela fait-il de Java le nouveau roi de l’IA ? Pas au sens des guerres verbales habituelles entre langages. Personne ne remplace PyTorch par Java. Ce que Java gagne, c’est le domaine où se trouvent les revenus : les applications commerciales qui doivent être fiables, observables et, au mieux, peu attrayantes. Si vous travaillez dans ce secteur, le gagnant est ce qui fonctionne déjà sur votre cluster de production, et c’est de plus en plus souvent Java.
Le reste de cet article décrit ce changement. Il explique pourquoi il s’est produit, à quoi ressemble un service RAG dans Spring Boot, comment choisir un stockage de vecteurs, et quels détails de production distinguent une démonstration d’une solution fiable pour des données clients.
L’avantage de Python a toujours été la recherche
Python a dominé l’ère de la recherche pour des raisons valables qui restent d’actualité : NumPy, PyTorch, Hugging Face, Jupyter, ainsi qu’une génération entière d’ingénieurs maîtrisant les tenseurs. Le fine-tuning de modèles, le test d’une nouvelle architecture d’encodage ou l’entraînement sur des GPU relèvent toujours de Python.
Le déploiement en production est une autre affaire. La plupart des entreprises n’entraînent jamais de modèle de base. Elles appellent un service externe, puis le véritable travail commence : récupération de documents, application de politiques, séparation des utilisateurs, enregistrement des requêtes, limitation des dépenses et vérification pour s’assurer qu’aucun montant de remboursement ne soit inventé. Il s’agit de conception d’API, d’accès aux données, de sécurité et d’opérations, domaines que Spring Boot gère depuis 2014.
Le raccourci populaire consistant à placer le modèle derrière FastAPI entraînait des coûts récurrents :
- deux langages au sein d’un même produit
- des pipelines de déploiement distincts
- des systèmes de surveillance séparés
Les gens ont accepté cela parce que Java manquait d’outils sérieux pour les LLM. En 2025, ce n’était plus le cas. Spring AI 1.0 est devenu généralement disponible en mai 2025, et la version 2.0 est sortie en juin 2026 avec Spring Boot 4. LangChain4j a atteint la version 1.0 durant la même période. La pile JVM ne rattrape plus son retard aujourd’hui. Pour les équipes déjà utilisant Spring, c’est un choix logique par défaut.
Que signifie « ajouter de l’IA » dans une application Spring
Aucune réécriture n’est nécessaire, il s’agit simplement de trois fonctionnalités.
- Une couche de chat.
ChatClientdans Spring AI, ou unAiServicedans LangChain4j, transforme une requête et l’historique des messages en une réponse du modèle. La transmission en flux est standard, et la sortie structurée peut être stockée dans un record Java, ce qui vous évite de devoir extraire du JSON à l’aide de regex à partir du texte. - Accès à vos propres données. Vous calculez des embeddings et les conservez dans un stockage vectoriel, de sorte que les réponses proviennent de vos politiques, factures, guides opérationnels et documentation produit, et non de ce que le modèle se souvient vaguement. Il s’agit de la génération augmentée par récupération d’informations (RAG).
- Appels à des outils. Le modèle peut invoquer des méthodes Java conformément à vos règles d’autorisation, par exemple pour rechercher une commande, ouvrir un dossier ou consulter un solde. C’est ici que le système de types et les services que vous possédez déjà se révèlent utiles. Le modèle n’est pas votre source de vérité ; il raisonne sur la base d’une telle source.
Avec Spring Security, Spring Data, Actuator et PostgreSQL en place, il s’agit d’un autre type de client, tout comme lors de l’apparition de Redis ou Kafka.
RAG, expliqué pour un développeur Java
En enlevant le voile de mystère, RAG est un pipeline de recherche qui se termine par un modèle linguistique. Les étapes sont les suivantes :
- Découper les documents en fragments.
- Transformer chaque fragment en un embedding, c’est-à-dire un vecteur de nombres flottants qui encode son sens.
- Enregistrer ces vecteurs avec des métadonnées telles que le propriétaire, l’ID du document, l’URI de source et la date de référence.
- Lorsqu’une question arrive, l’embeddingner et rechercher les fragments les plus proches.
- Insérer ces fragments dans la requête.
- Indiquer au modèle de répondre uniquement à partir d’eux, et d’admettre s’ils ne contiennent pas la réponse.
Pour les projets Spring Boot, PostgreSQL associé à pgvector constitue généralement le point de départ. PostgreSQL est déjà déployé, sauvegardé et géré en pool, ce qui fait que l’ajout d’une extension coûte moins cher que l’intégration immédiate de Pinecone, Weaviate ou Qdrant. Les moteurs spécialisés présentent des avantages lorsque l’échelle est extrême ou qu’une recherche hybride est nécessaire, mais la plupart des applications RAG internes restent bien en deçà de ces besoins.
Un squelette fonctionnel
La configuration ci-dessous associe Spring AI 2.0 à Boot 4 ; pour Boot 3.4 ou 3.5, utilisez plutôt la version 1.1.x. Intégrez d’abord la liste des dépendances afin que toutes les bibliothèques de démarrage utilisent la même version :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.1.8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Ensuite, déclarez uniquement les dépendances dont vous avez besoin :
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
JDBC est mentionné délibérément. Le starter pgvector fonctionne via JdbcTemplate, et oublier cette dépendance est une cause étonnamment fréquente d’échec du démarrage.
Les paramètres se trouvent dans application.yml. C’est là l’objectif de Spring AI : un modèle doit être configuré comme une source de données.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app
username: app
password: ${DB_PASSWORD}
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
options:
model: gpt-4o-mini
temperature: 0.2
embedding:
options:
model: text-embedding-3-small
vectorstore:
pgvector:
initialize-schema: true
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1536
Deux détails dans ce fichier sont plus importants qu’ils n’y paraissent. La dimension d’incorporation doit correspondre à celle produite par le modèle d’incorporation, et text-embedding-3-small génère 1536. Si vous changez de modèle sans tenir compte de ce chiffre, la recherche par similarité se dégrade sans qu’aucune erreur ne soit signalée. Le deuxième point concerne une température basse pour RAG, car vous souhaitez que les résultats soient proches du texte récupéré, et non une réécriture créative d’un bilan.
Considérez l’ingestion comme un service à part entière plutôt que comme une simple instruction de contrôle. La méthode VectorStore.add(...) accepte des fragments de type Document, et chacun de ces fragments doit contenir les métadonnées sur lesquelles vous ferez des filtres ultérieurement, tels que tenantId, source, docType et effectiveDate. Sans filtres, la recherche sémantique peut afficher le contrat d’un client dans les résultats d’un autre client.
La requête est tout aussi concise. Le QuestionAnswerAdvisor de Spring AI représente une version prédéfinie de ce processus : récupérer les données, ajouter du contexte, puis appeler le modèle. Lorsque vous avez besoin de filtres, de réclassement ou de citations, utilisez similaritySearch vous-même et interprétez filterExpression comme une clause WHERE, car c’est précisément sa fonction.
Choisir un stockage vectoriel sans dogme
Vous trouverez quatre options :
- Postgres avec pgvector. C’est le choix par défaut logique, bien compris en termes opérationnels. Grâce à l’indexation HNSW, au suivi du taux de rappel et aux blocs compacts, il gère des dizaines de millions de vecteurs. Il montre ses limites lorsque vous avez besoin d’une recherche hybride avancée ou d’une équipe dédiée à l’exploitation d’une infrastructure d’approximation des voisins les plus proches.
La méthode de décision est simple, et c’est là sa force. Commencez par pgvector lorsque Postgres fonctionne déjà en production. Changez de stratégie lorsque la récupération des données, la latence ou la recherche hybride ne respectent pas les exigences réelles en matière de performance, et non parce qu’un rapport affirme que les applications d’IA sérieuses utilisent tel ou tel produit. Conservez également une référence au document d’origine à côté de chaque vecteur, afin de pouvoir le réinsérer chaque fois qu’une politique évolue.
C’est ce dernier point que les tutoriels omettent. Les modèles d’incorporation sont remplacés, la segmentation des données devient plus sophistiquée et les documents juridiques sont modifiés. Un job d’ingestion idempotent, indexé sur la version du document, vous évite de perdre un temps précieux à chercher pourquoi le bot cite le barème des frais de l’année dernière.
Spring AI versus LangChain4j
Les deux sont prêts pour la production. Le choix dépend de l’état actuel de votre équipe.
Spring AI reprend l’idée bien connue de Spring concernant les abstractions portables et l’applique aux modèles. Si vous l’imaginez comme une version Spring Data adaptée aux LLM, cela vous semblera naturel, et l’auto-configuration, ChatClient, les conseillers, Actuator et Micrometer s’intègrent tous facilement. Utilisez la version 2.0 avec Boot 4. Avec Boot 3, restez sur la version 1.1.x, car la 2.0 ne peut pas être intégrée directement.
LangChain4j est d’abord conçu pour Java et propose également un starter Spring. Il prend en charge davantage de fournisseurs, ses AiServices typés ressemblent à des clients Feign orientés vers des modèles, et il convient aux équipes qui utilisent également Quarkus ou du Java pur. Ceux qui souhaitent un contrôle précis sur le cycle de l’agent ont tendance à le choisir.
Rien ne vous empêche d’utiliser les deux. Une solution pratique consiste à utiliser Spring AI pour les conversations et RAG dans les services destinés aux clients, avec LangChain4j pour combler les lacunes liées à un fournisseur ou à un modèle d’agent spécifique. Gardez leurs composants séparés, et ne permettez jamais à deux modèles d’incorporation différents d’écrire des vecteurs incompatibles dans une même table.
Un environnement entièrement basé sur Spring-Boot qui peut planifier une mise à jour vers Boot 4 devrait opter pour Spring AI. Un environnement mixte en JVM, ou un environnement bloqué sur Boot 3 depuis un an, trouvera probablement que LangChain4j dépend moins du calendrier de sorties du framework.
C’est en production que la JVM prend l’avantage
N’importe qui peut démontrer une réponse. Un produit, lui, doit résister à un audit. Voici les aspects à prendre en compte :
- Ancrage et refus. Limitez le modèle au contexte récupéré et indiquez les citations correspondantes. Lorsque les scores de similarité sont en dessous d’un seuil, la réponse doit être « cela n’est pas dans la base de connaissances » et non une supposition. Dans les domaines financier, opérationnel et de la santé, une erreur formulée avec assurance coûte plus cher qu’un simple refus.
- Location et censure. Filtrez les vecteurs par locataire et supprimez les informations sensibles des requêtes. Évitez d’inclure les numéros de carte, les numéros de compte et les données de santé dans les journaux brut des requêtes. Si le débogage vous oblige à les enregistrer, tokenisez-les d’abord et conservez-les conformément aux règles de conservation du système source.
- Budgets pour les coûts et la latence. Les tokens coûtent de l’argent, il faut donc enregistrer les tokens d’entrée, les tokens de sortie, le temps de récupération et le temps d’exécution du modèle. Imposez une limite maximale de tokens à chaque appel, mettez en cache les embeddings des documents récurrents, et envoyez la classification ou le routage à un modèle plus petit, n’utilisant un modèle plus grand que si c’est nécessaire.
Tout cela relève des tâches habituelles avec Spring : envelopper une appel distant, marquer une métrique, rejeter les requêtes non authentifiées. Le LLM constitue une nouvelle dépendance avec des SLA moins favorables, il faut donc le gérer en conséquence.
Où l’adage « Java est roi » est vrai
Java représente un meilleur point de départ lorsque le système d’information existe déjà sur la JVM, lorsque la fonctionnalité d’IA doit partager des informations d’identité, de location et d’audit avec les API existantes, lorsque l’on a besoin d’appeler des services Java internes en tant qu’outils, lorsque les exigences de conformité ne permettent pas l’utilisation d’une stack Python parallèle, et lorsque les personnes de garde à 2 heures du matin maîtrisent déjà Spring Boot.
Python reste en tête lorsque l’on s’occupe de l’entraînement ou du fine-tuning, lorsqu’il faut disposer d’une bibliothèque de recherche dès sa sortie, ou lorsque le modèle lui-même constitue le produit et non une simple fonctionnalité au sein d’une application plus large.
Ce sont des tâches distinctes, et pendant deux ans l’industrie a agi comme si elles ne l’étaient pas. Le résultat a été une avalanche d’architectures utilisant un sidecar Python, dans l’espoir que ses contraintes restent inchangées. Le modèle qui semble prometteur pour 2026 est mixte : Python, ou un laboratoire de modèles hébergé, s’occupe de l’entraînement et de l’évaluation, Java gère le service, la recherche vectorielle fonctionne en parallèle des données opérationnelles, le modèle provient d’un fournisseur tandis que la logique métier reste entre vos mains.
Un premier projet judicieux
Évitez de commencer avec un chatbot applicable à l’ensemble de l’entreprise sans limites. Choisissez un domaine de contenu précis et utile ainsi qu’une question pour laquelle vous pouvez évaluer les réponses. Voici quelques exemples efficaces :
- Des questions-réponses pour les ingénieurs en service, liées à la page source
- Un assistant aux politiques qui cite exactement la clause concernée
- Des questions-réponses sur une facture ou un relevé que l’utilisateur vient de télécharger
Mettez cela derrière une API authentifiée que vous possédez déjà, enregistrez chaque récupération, affichez les citations dans l’interface utilisateur, ajoutez un interrupteur de configuration, et déterminez le coût par requête avant d’agrandir le corpus. Le premier projet enseigne le découpage en blocs, les métadonnées, l’évaluation et le contrôle des modifications des prompts ; ces compétences sont transférables, tandis que la marque du framework ne l’est pas.
L’environnement de exécution en cui vous avez déjà confiance
« Java est le nouveau roi de l’IA » fonctionne comme un titre, mais manque de rigueur en tant que thèse. Java n’a pas remporté la bataille de l’apprentissage automatique ; il a simplement intégré l’IA appliquée dans la plateforme qui gère déjà les systèmes de transactions mondiaux.
Un ingénieur Spring Boot n’a besoin de l’autorisation de personne pour travailler ici, ni d’un diplôme en science des données au préalable. Ce qui est requis, c’est un fournisseur de modèles, un modèle d’incorporation, un index vectoriel ainsi que les mêmes précautions opérationnelles appliquées aux paiements et aux messageries. Python continue de former les stars du laboratoire. Java devient le leader sur le chemin allant du laboratoire au registre, où les réponses doivent être étayées, les appels d’outils autorisés et chaque facture nécessite une explication. Pour la plupart des équipes, c’est le seul titre d’honneur qui vaille la peine d’être obtenu.
Si un service Spring Boot que vous possédez gère déjà l’identité, l’argent et le journal d’audit, il n’y a aucune raison d’attendre un sidecar. Choisissez ce week-end un corpus restreint, placez ChatClient devant pgvector, et exigez des citations provenant du modèle.