Veille Spring Boot — semaine du 02/11/2026

Spring Boot · Publié le

Spring AI 2.1 : les message parts préservent le raisonnement entre deux appels

Spring Blog · 28/10/2026

En bref : Spring AI 2.1 remplace le texte simple d'un message par une liste ordonnée de MessagePart. Les blocs de raisonnement, leurs signatures et les appels d'outils gardent ainsi leur ordre et peuvent être renvoyés tels quels au modèle.

Ce qu'il faut retenir :

  • AbstractMessage expose désormais getParts(), une liste ordonnée partagée par tous les types de messages.
  • MessagePart est une interface sealed avec six records : TextPart, ReasoningPart, ToolCallPart, ToolResultPart, MediaPart et UnknownPart (JSON brut des blocs non modélisés).
  • OpaquePayload(provider, kind, data) transporte les données opaques (signature Anthropic, thought_signature Gemini, encrypted_content OpenAI). Le modèle qui les a produites les renvoie sans les modifier, et les autres les ignorent.
  • getReasoning() offre un accesseur unique pour le raisonnement, quel que soit le modèle. Avant 2.1, chaque modèle l'exposait à sa façon (métadonnées isThought pour Google GenAI, getReasoningContent() pour DeepSeek).
  • Le nouveau OpenAiResponsesChatModel utilise l'API Responses d'OpenAI en mode stateless.
  • Les constructeurs et méthodes builder existants continuent de fonctionner. Le code qui lit le raisonnement doit toutefois être adapté.
  • Le texte indique que Session memory persiste désormais les parts, et non plus seulement le texte.

Exemple :

ChatResponse response = chatModel.call(prompt);

// Spring AI 2.1 : un accesseur unique pour tous les chat models
List<String> thoughts = response.getResult().getOutput().getReasoning().stream()
    .map(ReasoningPart::text)
    .toList();
String answer = response.getResult().getOutput().getText();

Dans un projet : Si votre application utilise un modèle de raisonnement avec appels d'outils (Claude avec thinking, Gemini, OpenAI Responses), migrez vers 2.1 et remplacez les accès spécifiques au fournisseur par getReasoning(). Vérifiez aussi la persistance de l'historique, car le texte seul ne suffit plus pour rejouer le raisonnement.

Lire l'article

Spring AI 2.1 : upsert et recherche avec vos propres embeddings

Spring Blog · 28/10/2026

En bref : Spring AI 2.1 ajoute VectorStore.upsert(...) pour indexer des documents accompagnés de vecteurs fournis par l'application, sans appel au modèle d'embedding du store. Une surcharge de similaritySearch accepte aussi un vecteur de requête. Le cas d'usage cité est la recherche multimodale (images, vidéos, audio).

Ce qu'il faut retenir :

  • upsert(List<EmbeddedDocument>) insère les documents aux identifiants nouveaux et remplace ceux dont l'identifiant existe déjà. Des identifiants stables, par exemple dérivés d'un SKU, évitent les doublons lors d'un ré-indexation.
  • EmbeddedDocument associe un Document à son vecteur float[].
  • Un Document doit contenir du texte ou un média, mais les vector stores ne persistent pas les médias. Le texte vide .text("") garde le document valide, et upsert ne l'embedde pas.
  • DocumentMetadata.CONTENT_REF stocke une référence externe (URL de l'image). Spring AI ne télécharge pas le contenu.
  • similaritySearch(float[], SearchRequest) utilise le vecteur fourni et ignore le texte de la requête. Il faut utiliser le même modèle multimodal pour indexer et pour rechercher.
  • Les dimensions du store doivent correspondre à celles du modèle (exemple : spring.ai.vectorstore.pgvector.dimensions=1408). La colonne vectorielle existante doit aussi avoir une dimension compatible.
  • Les écritures d'un même appel upsert ne sont pas transactionnelles : en cas d'erreur, certains documents peuvent déjà être écrits.

Exemple :

float[] vector = this.multimodal.call(new DocumentEmbeddingRequest(photo))
    .getResult().getOutput();

Document row = Document.builder()
    .id(UUID.nameUUIDFromBytes(product.sku().getBytes(UTF_8)).toString())
    .text("")
    .metadata(DocumentMetadata.CONTENT_REF.value(), product.photoUrl())
    .metadata("sku", product.sku())
    .build();

this.vectorStore.upsert(List.of(new EmbeddedDocument(row, vector)));

Dans un projet : Utilisez upsert si vos embeddings viennent d'ailleurs (API batch d'un fournisseur, migration de base, modèle multimodal) et que vous ne voulez pas les recalculer. Gardez le nom du modèle et sa version dans les métadonnées pour savoir quels documents réindexer lors d'un changement de modèle.

Lire l'article

Transformation de requêtes dans le RAG modulaire de Spring AI

Baeldung · 30/10/2026

En bref : Le RAG modulaire de Spring AI découpe le pipeline en quatre étapes. Cet article détaille la phase de pré-récupération, où un LLM réécrit la requête utilisateur avant la recherche vectorielle. Il présente trois transformeurs fournis par Spring AI.

Ce qu'il faut retenir :

  • RetrievalAugmentationAdvisor relie les étapes. Il s'enregistre sur un ChatClient via defaultAdvisors(...).
  • La méthode queryTransformers(...) accepte plusieurs transformeurs. Ils s'exécutent en séquence, chacun recevant la sortie du précédent, et chacun fait son propre appel LLM via un ChatClient.Builder.
  • RewriteQueryTransformer retire les informations inutiles d'une requête longue ou confuse. Dans l'exemple, « I'm studying machine learning... What is an LLM anyway? » devient « What is an LLM in machine learning? ».
  • TranslationQueryTransformer traduit la requête dans la langue cible, avec targetLanguage("english"), pour mieux correspondre aux documents et au modèle d'embedding.
  • CompressionQueryTransformer compresse la requête en tenant compte de l'historique de conversation, ce qui résout les questions de suivi (« And how does it support RAG? »).
  • L'article recommande temperature: 0.0 pour obtenir des transformations déterministes.
  • La phase de récupération est configurée séparément avec documentRetriever(VectorStoreDocumentRetriever...topK(3)).

Exemple :

RetrievalAugmentationAdvisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
  .queryTransformers(
    RewriteQueryTransformer.builder()
      .chatClientBuilder(chatClientBuilder).build(),
    TranslationQueryTransformer.builder()
      .chatClientBuilder(chatClientBuilder)
      .targetLanguage("english").build(),
    CompressionQueryTransformer.builder()
      .chatClientBuilder(chatClientBuilder).build())
  .documentRetriever(VectorStoreDocumentRetriever.builder()
    .vectorStore(vectorStore)
    .topK(3).build())
  .build();

ChatClient chatClient = chatClientBuilder.defaultAdvisors(ragAdvisor).build();

Dans un projet : Ajoutez des transformeurs si vos utilisateurs posent des questions longues, dans une autre langue que vos documents, ou dans des conversations multi-tours. Chaque transformeur ajoute un appel LLM, donc une latence et un coût supplémentaires à mesurer.

Lire l'article

Gérer les en-têtes forwarded dans Spring Boot

Baeldung · 30/10/2026

En bref : Derrière un reverse proxy ou un API gateway, l'application ne voit plus l'IP, le nom d'hôte ou le protocole du client d'origine. L'article rappelle les en-têtes X-Forwarded-* et Forwarded (RFC 7239), puis met en place un test avec Nginx et Docker. Le texte fourni s'interrompt avant la présentation détaillée des stratégies Spring Boot.

Ce qu'il faut retenir :

  • En-têtes X-Forwarded-* : For (IP client), By (IP du proxy), Host, Port, Proto (http, https, ws, wss) et Prefix (préfixe de chemin absent de l'URL backend).
  • En-tête standard RFC 7239 : Forwarded: by=...; for=...; host=...; proto=....
  • Les usages cités sont le rate limiting par IP, l'audit, la génération d'URL HATEOAS et les redirections HTTP.
  • L'article indique que Spring Boot prend en charge trois stratégies de traitement de ces en-têtes à partir de la version 2.2.0. Le texte fourni ne les détaille pas.
  • Dans la configuration Nginx de l'article, le slash final de proxy_pass http://backend-app:8081/ est obligatoire pour remplacer le préfixe /myapp/.
  • L'exemple utilise Spring Boot 4.1.1 et eclipse-temurin:21-jre-alpine.

Exemple :

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate     /etc/nginx/certs/api.example.com.crt;
    ssl_certificate_key /etc/nginx/certs/api.example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;

    location /myapp/ {
        proxy_pass http://backend-app:8081/;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Dans un projet : Si votre service tourne derrière Nginx, un load balancer ou une gateway, vérifiez que les en-têtes forwarded sont transmis et pris en compte. Sans cela, les URL générées (HATEOAS, redirections) pointent vers le backend interne. Consultez l'article complet pour la propriété exacte de chaque stratégie.

Lire l'article

This Week in Spring : nouvelles versions Spring Boot, Spring AI, Spring Security et Spring Modulith

Spring Blog · 27/10/2026

En bref : La newsletter du 27 octobre annonce plusieurs nouvelles versions. Les plus importantes sont les mises à jour de Spring Boot (corrections sur les branches 4.0 et 4.1, et première RC de la 4.2), la RC de Spring AI 2.1 et celle de Spring Security 7.2. Le texte ne mentionne aucun CVE.

Ce qu'il faut retenir :

  • Spring Boot 4.0.9 et 4.1.2 sont disponibles (versions correctives), et Spring Boot 4.2.0-RC1 est publiée.
  • Spring AI 2.1.0-RC1 et 2.0.2 sont disponibles. La 2.1.0-RC1 introduit les message parts et l'upsert d'embeddings détaillés dans les articles ci-dessus.
  • Spring Security 7.2.0-RC1 est disponible. La newsletter cite aussi Spring Security 7.0.8 et 7.1.2, sans précision sur les corrections.
  • Spring Modulith 2.2 RC1 est publiée, avec les versions 2.1.2, 2.0.9 et 1.4.14.
  • Spring Cloud 2026.0.0-RC1 (Paddington) et Spring Cloud 2025.1.4 (Northfields) sont publiées, comme Spring Data 2026.0.2 et 2025.1.8.

Dans un projet : Pour les branches 4.0 et 4.1 de Spring Boot, appliquez les correctifs (4.0.9 et 4.1.2) en priorité. Testez les RC (Spring Boot 4.2, Spring AI 2.1, Spring Security 7.2) sur une branche dédiée avant de les adopter. Les notes de version contiennent les détails de migration.

Lire l'article


Veille préparée automatiquement par Claude à partir de 7 articles de la semaine.