L'intégration de l'intelligence artificielle générative dans l'écosystème Java s'est simplifiée avec l'émergence de Spring AI. L'un des cas d'usage les plus performants consiste à coupler un modèle de langage (LLM) avec une base de données vectorielle pour créer un système de type RAG (Retrieval-Augmented Generation). Cet article détaille comment orchestrer Spring AI et Milvus pour bâtir une solution de questions-réponses intelligente.
Prérequis techniques
- Java 17 ou version ultérieure
- Environnement Maven 3.8+
- Docker pour l'instance de base de données
Configuraton des dépendances
Pour commencer, intégrez les modules nécessaires dans votre fichier pom.xml. Vous aurez besoin du starter web ainsi que du connecteur spécifique pour Milvus fourni par Spring AI.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-milvus-store-spring-boot-starter</artifactId>
<version>1.0.0-M1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Infrastructure : Déploiement de Milvus
Milvus agit comme le cerveau de stockage pour nos vecteurs. Utilisez Docker pour instancier rapidement un serveur local :
docker run -d --name milvus-standalone \
-p 19530:19530 \
-p 9091:9091 \
milvusdb/milvus:latest
Ensuite, définissez les paramètres de connexion dans le fichier application.yml de votre projet Spring Boot :
spring:
ai:
vectorstore:
milvus:
client:
host: localhost
port: 19530
collection-name: base_connaissance
embedding-dimension: 1536
Architecture du service de recherche
La logique métier repose sur l'interface VectorStore. Nous allons créer un composant capable d'indexer des documents et d'intreroger la base vectorielle pour trouver les segments de texte les plus pertinents par rapport à une requête utiilsateur.
@Service
public class MoteurRechercheService {
private final VectorStore magasinVecteurs;
public MoteurRechercheService(VectorStore magasinVecteurs) {
this.magasinVecteurs = magasinVecteurs;
}
public List<String> recupererContextes(String requeteUtilisateur) {
// Recherche par similarité avec un seuil de pertinence
SearchRequest requeteSearch = SearchRequest.query(requeteUtilisateur)
.withTopK(3)
.withSimilarityThreshold(0.7);
return magasinVecteurs.similaritySearch(requeteSearch)
.stream()
.map(Document::getContent)
.toList();
}
public void indexerDonnees(List<Document> documents) {
magasinVecteurs.add(documents);
}
}
Exposition via une API REST
Pour interagir avec notre système, nous implémentons un contrôleur simple qui reçoit les interrogations et retourne les fragments de connaissances identifiés par l'IA.
@RestController
@RequestMapping("/api/ia")
public class AssistantController {
private final MoteurRechercheService rechercheService;
public AssistantController(MoteurRechercheService rechercheService) {
this.rechercheService = rechercheService;
}
@GetMapping("/demander")
public ResponseEntity<List<String>> poserQuestion(@RequestParam String texte) {
var resultats = rechercheService.recupererContextes(texte);
if (resultats.isEmpty()) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(resultats);
}
}
Optimisation des performances
Lors de la phase d'implémentation, il est crucial de configurer correctement le modèle d'embedding (comme OpenAI, Ollama ou HuggingFace). La dimension spécifiée dans la configuration Milvus doit impérativement correspondre à la sortie du modèle sélectionné. Pour améliorer la précision, l'ajustement du paramètre TopK permet de contrôler la quantité de contexte fournie au LLM final.