<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adnene HAMDOUNI</title>
    <description>The latest articles on DEV Community by Adnene HAMDOUNI (@adnene_hamdouni_75694870a).</description>
    <link>https://dev.to/adnene_hamdouni_75694870a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2818953%2F00d710c5-ac5f-4c98-a27c-0a860cf38d10.png</url>
      <title>DEV Community: Adnene HAMDOUNI</title>
      <link>https://dev.to/adnene_hamdouni_75694870a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adnene_hamdouni_75694870a"/>
    <language>en</language>
    <item>
      <title>RAG with Spring Boot: Give Your AI a Private Contextual Memory</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:21:58 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/rag-with-spring-boot-give-your-ai-a-private-contextual-memory-47km</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/rag-with-spring-boot-give-your-ai-a-private-contextual-memory-47km</guid>
      <description>&lt;h1&gt;
  
  
  RAG with Spring Boot: Give Your AI a Private Contextual Memory
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Metadata
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: RAG / Vector Databases / Spring AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target&lt;/strong&gt;: Java Developers, Data/AI Architects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimated Reading Time&lt;/strong&gt;: 10 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: #SpringBoot #SpringAI #RAG #VectorDatabase #JavaAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges of generative AI in the enterprise is the phenomenon of &lt;strong&gt;hallucinations&lt;/strong&gt;. An LLM, however powerful, can invent facts with disconcerting confidence, especially when it comes to recent data or confidential internal documents it has never "seen" during its training.&lt;/p&gt;

&lt;p&gt;Imagine asking your AI: &lt;em&gt;"What is the reimbursement procedure for customer X?"&lt;/em&gt;. If the AI doesn't have access to your contracts, it will make a guess based on statistical probabilities. This is where &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt; changes the game.&lt;/p&gt;

&lt;p&gt;RAG doesn't seek to retrain the model (which would be costly and slow). Instead, it turns the AI into an ultra-fast researcher: before answering, the AI searches your private documents, extracts the relevant passages, and uses this information as a basis to formulate its response. This is called &lt;strong&gt;grounded generation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By the end of this article, you will understand how to orchestrate this flow with Spring AI and implement a robust contextual memory architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Technical Core
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The RAG Pipeline Deconstructed: Understanding the Flow
&lt;/h3&gt;

&lt;p&gt;To implement RAG, you need to design two distinct pipelines: one for ingestion and one for retrieval.&lt;/p&gt;

&lt;h4&gt;
  
  
  A. The Ingestion Pipeline (Storing Knowledge)
&lt;/h4&gt;

&lt;p&gt;This is where your documents become "readable" for the AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Document Reading&lt;/strong&gt;: Load files (PDF, Markdown, HTML) via &lt;code&gt;DocumentReader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking&lt;/strong&gt;: Split the text into pieces (chunks). Why? Because LLMs have a limited context window and precise pieces allow for finer search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding&lt;/strong&gt;: Each piece is converted into a numerical vector by an embedding model. This vector represents the &lt;em&gt;semantic meaning&lt;/em&gt; of the text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Store&lt;/strong&gt;: These vectors are stored in a vector database (like PGVector).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  B. The Retrieval Pipeline (The Response)
&lt;/h4&gt;

&lt;p&gt;This is what happens when the user asks a question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query Vectorization&lt;/strong&gt;: The question is converted into a vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similarity Search&lt;/strong&gt;: Search the Vector Store for the $K$ text pieces whose vectors are closest to that of the question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Augmentation&lt;/strong&gt;: Build a prompt like: &lt;em&gt;"Here are relevant documents: [Context]. Based solely on these documents, answer the question: [Question]"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation&lt;/strong&gt;: The LLM generates the final response based on the provided evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Technical Implementation with Spring AI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17+, Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;A Vector Store. We will use &lt;strong&gt;PGVector&lt;/strong&gt; (PostgreSQL extension), the preferred choice for enterprises because it allows keeping transactional and vector data in the same place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Vector Store Configuration
&lt;/h4&gt;

&lt;p&gt;Add the PGVector starter to your &lt;code&gt;pom.xml&lt;/code&gt; and configure your access in &lt;code&gt;application.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vectorstore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;pgvector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;initialize-schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;index-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HNSW&lt;/span&gt;
        &lt;span class="na"&gt;distance-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;COSINE_DISTANCE&lt;/span&gt;
        &lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1536&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Document Ingestion
&lt;/h4&gt;

&lt;p&gt;Here's how to load and store your knowledge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeIngestionService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;KnowledgeIngestionService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vectorStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Chat with Contextual Memory
&lt;/h4&gt;

&lt;p&gt;Thanks to the &lt;code&gt;QuestionAnswerAdvisor&lt;/code&gt;, Spring AI automates the entire retrieval process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RagController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;RagController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ragAdvisor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QuestionAnswerAdvisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;searchRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SearchRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;topK&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;similarityThreshold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultAdvisors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ragAdvisor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ask"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: If you notice the AI answering "I don't know" when the info is present, lower the &lt;code&gt;similarityThreshold&lt;/code&gt; (e.g., 0.6). If it hallucinates too much, increase it (e.g., 0.8).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analysis &amp;amp; Optimization: Going Further
&lt;/h3&gt;

&lt;p&gt;RAG is not a "magic" solution; it requires tuning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Chunking Challenge&lt;/strong&gt;&lt;br&gt;
Chunk size is crucial. Pieces that are too small lose the global context. Pieces that are too large introduce noise. A common strategy is "Overlapping": making chunks overlap to avoid cutting an important sentence in half.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddings: The Search Engine&lt;/strong&gt;&lt;br&gt;
The choice of the embedding model (e.g., &lt;code&gt;text-embedding-3-small&lt;/code&gt; vs a local model via HuggingFace) directly impacts precision. A good embedding model understands that "car" and "automobile" are semantically close.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidentiality vs Fine-Tuning&lt;/strong&gt;&lt;br&gt;
Why choose RAG over fine-tuning?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instant Updates&lt;/strong&gt;: Add a document to the Vector Store, and the AI knows it immediately. No retraining needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceability&lt;/strong&gt;: RAG allows citing sources ("According to document X, page 4..."), which is impossible with fine-tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: You control exactly which document is retrieved based on the user's rights.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Opening
&lt;/h2&gt;

&lt;p&gt;RAG transforms AI from a conversational assistant into a true business expert capable of exploiting your private data with precision and security. It is the foundation of any serious enterprise AI.&lt;/p&gt;

&lt;p&gt;But we still have one step to go. Today, our AI answers. Tomorrow, it must &lt;strong&gt;act&lt;/strong&gt;. This is where &lt;strong&gt;Autonomous Agents&lt;/strong&gt; and the &lt;strong&gt;MCP protocol&lt;/strong&gt; come in, which we will explore in the next article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn!&lt;/strong&gt; Install PGVector, load your first documents, and see your Spring Boot application suddenly become very intelligent.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html" rel="noopener noreferrer"&gt;Retrieval Augmented Generation :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/vectordbs/pgvector.html" rel="noopener noreferrer"&gt;PGvector :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simplifiedlearningblog.com/building-rag-pipeline-spring-ai-pgvector/" rel="noopener noreferrer"&gt;Building A RAG Pipeline With Spring AI And Pgvector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>rag</category>
      <category>spring</category>
    </item>
    <item>
      <title>Spring AI: Integrating Artificial Intelligence into Your Java Applications in Minutes</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:21:57 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrating-artificial-intelligence-into-your-java-applications-in-minutes-550</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrating-artificial-intelligence-into-your-java-applications-in-minutes-550</guid>
      <description>&lt;h1&gt;
  
  
  Spring AI: Integrating Artificial Intelligence into Your Java Applications in Minutes
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Metadata
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: Spring Boot / AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target&lt;/strong&gt;: Java Developers, Software Architects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimated Reading Time&lt;/strong&gt;: 8 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: #SpringBoot #SpringAI #Java #LLM #GenerativeAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;For a long time, generative AI seemed to be the exclusive domain of Python. Java developers were often forced to call raw REST APIs without any real abstraction layer.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Spring AI&lt;/strong&gt; comes in. &lt;/p&gt;

&lt;p&gt;This new project from the Spring ecosystem doesn't just add an HTTP client for OpenAI. It brings a real abstraction layer, similar to what Spring Data did for databases. The idea is simple: you write your business logic once, and you can change your AI model (GPT-4, Claude, Mistral, or even a local model via Ollama) without modifying a single line of business code.&lt;/p&gt;

&lt;p&gt;By the end of this article, you will know how to configure your first Spring AI project and create a chat service capable of returning structured data.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Technical Core
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fundamental Concept: Model Abstraction
&lt;/h3&gt;

&lt;p&gt;At the heart of Spring AI is the &lt;code&gt;ChatModel&lt;/code&gt; interface. It standardizes interactions with LLMs. This is critical in an enterprise environment to avoid "vendor lock-in". You can switch from OpenAI to a local model via Ollama simply by changing a dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Technical Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17 or higher.&lt;/li&gt;
&lt;li&gt;Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;An OpenAI API key (or Ollama installed locally).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Project Configuration
&lt;/h4&gt;

&lt;p&gt;Add the corresponding starter to your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-openai-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, configure your API key in the &lt;code&gt;application.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;openai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${OPENAI_API_KEY}&lt;/span&gt;
      &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-4o&lt;/span&gt;
          &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Creating the Chat Service with ChatClient
&lt;/h4&gt;

&lt;p&gt;The fluent &lt;code&gt;ChatClient&lt;/code&gt; API is the modern way to interact with AI. Here's how to implement a simple controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ai"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AiController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AiController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Mastering PromptTemplates and Structured Output
&lt;/h4&gt;

&lt;p&gt;To make your applications truly useful, you cannot rely on free-text messages. You need structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PromptTemplates&lt;/strong&gt; allow you to inject dynamic variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Explain the concept of {concept} in two sentences for a beginner."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concept"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Dependency Injection"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Structured Output&lt;/strong&gt; is the "killer feature" for Java devs. You can map the AI response directly into a Java &lt;code&gt;record&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;director&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/movie-info"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="nf"&gt;getMovieInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Give me info on the movie "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: Use &lt;code&gt;Advisors&lt;/code&gt; (like &lt;code&gt;MessageChatMemoryAdvisor&lt;/code&gt;) to natively add conversation history without having to manually manage a list of messages for every call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analysis &amp;amp; Comparison: Spring AI vs LangChain4j
&lt;/h3&gt;

&lt;p&gt;If you explore AI in Java, you will definitely encounter &lt;strong&gt;LangChain4j&lt;/strong&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;Spring AI&lt;/th&gt;
&lt;th&gt;LangChain4j&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native and deep with Spring Boot&lt;/td&gt;
&lt;td&gt;Standalone libraries (usable everywhere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very low for Spring devs&lt;/td&gt;
&lt;td&gt;Moderate (closer to LangChain Python)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Benefits from the entire Spring ecosystem&lt;/td&gt;
&lt;td&gt;Very complete on third-party integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Philosophy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstraction and simplicity&lt;/td&gt;
&lt;td&gt;Flexibility and functional richness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: If your stack is already Spring Boot, Spring AI is the logical choice for its simplicity and alignment with your development patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Opening
&lt;/h2&gt;

&lt;p&gt;AI is no longer an "option" or a gadget for data scientists; it is now a first-class citizen in the Java ecosystem. With Spring AI, the technical barrier collapses to make room for business innovation.&lt;/p&gt;

&lt;p&gt;But a LLM alone has a limit: it doesn't know your private data. That's where &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt; comes in. In the next article, we'll see how to give a "memory" to your Spring Boot application by connecting a Vector Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn!&lt;/strong&gt; Install Ollama locally, configure Spring AI, and try creating your first structured agent. Share your feedback in the comments!&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/2.0/api/chatclient.html" rel="noopener noreferrer"&gt;Chat Client API :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/prompt.html" rel="noopener noreferrer"&gt;Prompts :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/getting-started.html" rel="noopener noreferrer"&gt;Getting Started :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>llm</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>RAG with Spring Boot: Give Your AI a Private Contextual Memory</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:12:13 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/rag-with-spring-boot-give-your-ai-a-private-contextual-memory-392o</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/rag-with-spring-boot-give-your-ai-a-private-contextual-memory-392o</guid>
      <description>&lt;h1&gt;
  
  
  RAG with Spring Boot: Give Your AI a Private Contextual Memory
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Metadata
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: RAG / Vector Databases / Spring AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target&lt;/strong&gt;: Java Developers, Data/AI Architects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimated Reading Time&lt;/strong&gt;: 10 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: #SpringBoot #SpringAI #RAG #VectorDatabase #JavaAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges of generative AI in the enterprise is the phenomenon of &lt;strong&gt;hallucinations&lt;/strong&gt;. An LLM, however powerful, can invent facts with disconcerting confidence, especially when it comes to recent data or confidential internal documents it has never "seen" during its training.&lt;/p&gt;

&lt;p&gt;Imagine asking your AI: &lt;em&gt;"What is the reimbursement procedure for customer X?"&lt;/em&gt;. If the AI doesn't have access to your contracts, it will make a guess based on statistical probabilities. This is where &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt; changes the game.&lt;/p&gt;

&lt;p&gt;RAG doesn't seek to retrain the model (which would be costly and slow). Instead, it turns the AI into an ultra-fast researcher: before answering, the AI searches your private documents, extracts the relevant passages, and uses this information as a basis to formulate its response. This is called &lt;strong&gt;grounded generation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By the end of this article, you will understand how to orchestrate this flow with Spring AI and implement a robust contextual memory architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Technical Core
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The RAG Pipeline Deconstructed: Understanding the Flow
&lt;/h3&gt;

&lt;p&gt;To implement RAG, you need to design two distinct pipelines: one for ingestion and one for retrieval.&lt;/p&gt;

&lt;h4&gt;
  
  
  A. The Ingestion Pipeline (Storing Knowledge)
&lt;/h4&gt;

&lt;p&gt;This is where your documents become "readable" for the AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Document Reading&lt;/strong&gt;: Load files (PDF, Markdown, HTML) via &lt;code&gt;DocumentReader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking&lt;/strong&gt;: Split the text into pieces (chunks). Why? Because LLMs have a limited context window and precise pieces allow for finer search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding&lt;/strong&gt;: Each piece is converted into a numerical vector by an embedding model. This vector represents the &lt;em&gt;semantic meaning&lt;/em&gt; of the text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Store&lt;/strong&gt;: These vectors are stored in a vector database (like PGVector).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  B. The Retrieval Pipeline (The Response)
&lt;/h4&gt;

&lt;p&gt;This is what happens when the user asks a question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query Vectorization&lt;/strong&gt;: The question is converted into a vector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Similarity Search&lt;/strong&gt;: Search the Vector Store for the $K$ text pieces whose vectors are closest to that of the question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt Augmentation&lt;/strong&gt;: Build a prompt like: &lt;em&gt;"Here are relevant documents: [Context]. Based solely on these documents, answer the question: [Question]"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation&lt;/strong&gt;: The LLM generates the final response based on the provided evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Technical Implementation with Spring AI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17+, Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;A Vector Store. We will use &lt;strong&gt;PGVector&lt;/strong&gt; (PostgreSQL extension), the preferred choice for enterprises because it allows keeping transactional and vector data in the same place.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Vector Store Configuration
&lt;/h4&gt;

&lt;p&gt;Add the PGVector starter to your &lt;code&gt;pom.xml&lt;/code&gt; and configure your access in &lt;code&gt;application.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vectorstore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;pgvector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;initialize-schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;index-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HNSW&lt;/span&gt;
        &lt;span class="na"&gt;distance-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;COSINE_DISTANCE&lt;/span&gt;
        &lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1536&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Document Ingestion
&lt;/h4&gt;

&lt;p&gt;Here's how to load and store your knowledge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeIngestionService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;KnowledgeIngestionService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vectorStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Chat with Contextual Memory
&lt;/h4&gt;

&lt;p&gt;Thanks to the &lt;code&gt;QuestionAnswerAdvisor&lt;/code&gt;, Spring AI automates the entire retrieval process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RagController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;RagController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ragAdvisor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QuestionAnswerAdvisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;searchRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SearchRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;topK&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;similarityThreshold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultAdvisors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ragAdvisor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ask"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: If you notice the AI answering "I don't know" when the info is present, lower the &lt;code&gt;similarityThreshold&lt;/code&gt; (e.g., 0.6). If it hallucinates too much, increase it (e.g., 0.8).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analysis &amp;amp; Optimization: Going Further
&lt;/h3&gt;

&lt;p&gt;RAG is not a "magic" solution; it requires tuning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Chunking Challenge&lt;/strong&gt;&lt;br&gt;
Chunk size is crucial. Pieces that are too small lose the global context. Pieces that are too large introduce noise. A common strategy is "Overlapping": making chunks overlap to avoid cutting an important sentence in half.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddings: The Search Engine&lt;/strong&gt;&lt;br&gt;
The choice of the embedding model (e.g., &lt;code&gt;text-embedding-3-small&lt;/code&gt; vs a local model via HuggingFace) directly impacts precision. A good embedding model understands that "car" and "automobile" are semantically close.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidentiality vs Fine-Tuning&lt;/strong&gt;&lt;br&gt;
Why choose RAG over fine-tuning?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instant Updates&lt;/strong&gt;: Add a document to the Vector Store, and the AI knows it immediately. No retraining needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceability&lt;/strong&gt;: RAG allows citing sources ("According to document X, page 4..."), which is impossible with fine-tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: You control exactly which document is retrieved based on the user's rights.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Opening
&lt;/h2&gt;

&lt;p&gt;RAG transforms AI from a conversational assistant into a true business expert capable of exploiting your private data with precision and security. It is the foundation of any serious enterprise AI.&lt;/p&gt;

&lt;p&gt;But we still have one step to go. Today, our AI answers. Tomorrow, it must &lt;strong&gt;act&lt;/strong&gt;. This is where &lt;strong&gt;Autonomous Agents&lt;/strong&gt; and the &lt;strong&gt;MCP protocol&lt;/strong&gt; come in, which we will explore in the next article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn!&lt;/strong&gt; Install PGVector, load your first documents, and see your Spring Boot application suddenly become very intelligent.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html" rel="noopener noreferrer"&gt;Retrieval Augmented Generation :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/vectordbs/pgvector.html" rel="noopener noreferrer"&gt;PGvector :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simplifiedlearningblog.com/building-rag-pipeline-spring-ai-pgvector/" rel="noopener noreferrer"&gt;Building A RAG Pipeline With Spring AI And Pgvector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>rag</category>
      <category>spring</category>
    </item>
    <item>
      <title>Spring AI: Integrating Artificial Intelligence into Your Java Applications in Minutes</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 21:12:13 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrating-artificial-intelligence-into-your-java-applications-in-minutes-2k5</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrating-artificial-intelligence-into-your-java-applications-in-minutes-2k5</guid>
      <description>&lt;h1&gt;
  
  
  Spring AI: Integrating Artificial Intelligence into Your Java Applications in Minutes
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Metadata
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: Spring Boot / AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target&lt;/strong&gt;: Java Developers, Software Architects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Estimated Reading Time&lt;/strong&gt;: 8 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt;: #SpringBoot #SpringAI #Java #LLM #GenerativeAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;For a long time, generative AI seemed to be the exclusive domain of Python. Java developers were often forced to call raw REST APIs without any real abstraction layer.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Spring AI&lt;/strong&gt; comes in. &lt;/p&gt;

&lt;p&gt;This new project from the Spring ecosystem doesn't just add an HTTP client for OpenAI. It brings a real abstraction layer, similar to what Spring Data did for databases. The idea is simple: you write your business logic once, and you can change your AI model (GPT-4, Claude, Mistral, or even a local model via Ollama) without modifying a single line of business code.&lt;/p&gt;

&lt;p&gt;By the end of this article, you will know how to configure your first Spring AI project and create a chat service capable of returning structured data.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Technical Core
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fundamental Concept: Model Abstraction
&lt;/h3&gt;

&lt;p&gt;At the heart of Spring AI is the &lt;code&gt;ChatModel&lt;/code&gt; interface. It standardizes interactions with LLMs. This is critical in an enterprise environment to avoid "vendor lock-in". You can switch from OpenAI to a local model via Ollama simply by changing a dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Technical Implementation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17 or higher.&lt;/li&gt;
&lt;li&gt;Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;An OpenAI API key (or Ollama installed locally).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Project Configuration
&lt;/h4&gt;

&lt;p&gt;Add the corresponding starter to your &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-openai-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, configure your API key in the &lt;code&gt;application.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;openai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${OPENAI_API_KEY}&lt;/span&gt;
      &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-4o&lt;/span&gt;
          &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Creating the Chat Service with ChatClient
&lt;/h4&gt;

&lt;p&gt;The fluent &lt;code&gt;ChatClient&lt;/code&gt; API is the modern way to interact with AI. Here's how to implement a simple controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ai"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AiController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AiController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Mastering PromptTemplates and Structured Output
&lt;/h4&gt;

&lt;p&gt;To make your applications truly useful, you cannot rely on free-text messages. You need structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PromptTemplates&lt;/strong&gt; allow you to inject dynamic variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Explain the concept of {concept} in two sentences for a beginner."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concept"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Dependency Injection"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Structured Output&lt;/strong&gt; is the "killer feature" for Java devs. You can map the AI response directly into a Java &lt;code&gt;record&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;director&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/movie-info"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="nf"&gt;getMovieInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Give me info on the movie "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;: Use &lt;code&gt;Advisors&lt;/code&gt; (like &lt;code&gt;MessageChatMemoryAdvisor&lt;/code&gt;) to natively add conversation history without having to manually manage a list of messages for every call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analysis &amp;amp; Comparison: Spring AI vs LangChain4j
&lt;/h3&gt;

&lt;p&gt;If you explore AI in Java, you will definitely encounter &lt;strong&gt;LangChain4j&lt;/strong&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;Spring AI&lt;/th&gt;
&lt;th&gt;LangChain4j&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native and deep with Spring Boot&lt;/td&gt;
&lt;td&gt;Standalone libraries (usable everywhere)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very low for Spring devs&lt;/td&gt;
&lt;td&gt;Moderate (closer to LangChain Python)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Benefits from the entire Spring ecosystem&lt;/td&gt;
&lt;td&gt;Very complete on third-party integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Philosophy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstraction and simplicity&lt;/td&gt;
&lt;td&gt;Flexibility and functional richness&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: If your stack is already Spring Boot, Spring AI is the logical choice for its simplicity and alignment with your development patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Opening
&lt;/h2&gt;

&lt;p&gt;AI is no longer an "option" or a gadget for data scientists; it is now a first-class citizen in the Java ecosystem. With Spring AI, the technical barrier collapses to make room for business innovation.&lt;/p&gt;

&lt;p&gt;But a LLM alone has a limit: it doesn't know your private data. That's where &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt; comes in. In the next article, we'll see how to give a "memory" to your Spring Boot application by connecting a Vector Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn!&lt;/strong&gt; Install Ollama locally, configure Spring AI, and try creating your first structured agent. Share your feedback in the comments!&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/2.0/api/chatclient.html" rel="noopener noreferrer"&gt;Chat Client API :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/prompt.html" rel="noopener noreferrer"&gt;Prompts :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/getting-started.html" rel="noopener noreferrer"&gt;Getting Started :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>RAG avec Spring Boot : Donnez une mémoire contextuelle et privée à votre IA</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 20:46:18 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/rag-avec-spring-boot-donnez-une-memoire-contextuelle-et-privee-a-votre-ia-2l17</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/rag-avec-spring-boot-donnez-une-memoire-contextuelle-et-privee-a-votre-ia-2l17</guid>
      <description>&lt;h1&gt;
  
  
  RAG avec Spring Boot : Donnez une mémoire contextuelle et privée à votre IA
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Métadonnées
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Titre&lt;/strong&gt; : RAG avec Spring Boot : Donnez une mémoire contextuelle et privée à votre IA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sujet&lt;/strong&gt; : RAG / Vector Databases / Spring AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cible&lt;/strong&gt; : Développeurs Java, Architectes Data/IA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temps de lecture estimé&lt;/strong&gt; : 10 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt; : #SpringBoot #SpringAI #RAG #VectorDatabase #JavaAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;L'un des plus grands défis de l'IA générative en entreprise est le phénomène des &lt;strong&gt;hallucinations&lt;/strong&gt;. Un LLM, aussi puissant soit-il, peut inventer des faits avec une assurance déconcertante, surtout lorsqu'il s'agit de données récentes ou de documents internes confidentiels qu'il n'a jamais "vus" lors de son entraînement.&lt;/p&gt;

&lt;p&gt;Imaginez demander à votre IA : &lt;em&gt;"Quelle est la procédure de remboursement pour le client X ?"&lt;/em&gt;. Si l'IA n'a pas accès à vos contrats, elle fera une supposition basée sur des probabilités statistiques. C'est ici que le &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt; change la donne.&lt;/p&gt;

&lt;p&gt;Le RAG ne cherche pas à réentraîner le modèle (ce qui serait coûteux et lent). Au lieu de cela, il transforme l'IA en un chercheur ultra-rapide : avant de répondre, l'IA va fouiller dans vos documents privés, extraire les passages pertinents, et utiliser ces informations comme base pour formuler sa réponse. C'est ce qu'on appelle la &lt;strong&gt;génération groundée&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;À la fin de cet article, vous comprendrez comment orchestrer ce flux avec Spring AI et mettre en place une architecture de mémoire contextuelle robuste.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Corps de l'Article
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Le Pipeline RAG décomposé : Comprendre le flux
&lt;/h3&gt;

&lt;p&gt;Pour implémenter le RAG, il faut concevoir deux pipelines distincts : un pour l'ingestion et un pour la récupération.&lt;/p&gt;

&lt;h4&gt;
  
  
  A. Le Pipeline d'Ingestion (Le stockage du savoir)
&lt;/h4&gt;

&lt;p&gt;C'est l'étape où vos documents deviennent "lisibles" pour l'IA :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Document Reading&lt;/strong&gt; : On charge les fichiers (PDF, Markdown, HTML) via des &lt;code&gt;DocumentReader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking&lt;/strong&gt; : On découpe le texte en morceaux (chunks). Pourquoi ? Parce que les LLM ont une fenêtre de contexte limitée et que des morceaux précis permettent une recherche plus fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding&lt;/strong&gt; : Chaque morceau est converti en un vecteur numérique (une liste de nombres) par un modèle d'embedding. Ce vecteur représente le &lt;em&gt;sens sémantique&lt;/em&gt; du texte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Store&lt;/strong&gt; : Ces vecteurs sont stockés dans une base de données vectorielle (comme PGVector).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  B. Le Pipeline de Récupération (La réponse)
&lt;/h4&gt;

&lt;p&gt;C'est ce qui se passe quand l'utilisateur pose une question :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Vectorisation de la requête&lt;/strong&gt; : La question est convertie en vecteur.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recherche de similarité&lt;/strong&gt; : On cherche dans le Vector Store les $K$ morceaux de texte dont les vecteurs sont les plus proches de celui de la question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Augmentation du Prompt&lt;/strong&gt; : On construit un prompt du type : &lt;em&gt;"Voici des documents pertinents : [Contexte]. En t'appuyant uniquement sur ces documents, réponds à la question : [Question]"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Génération&lt;/strong&gt; : Le LLM génère la réponse finale basée sur les preuves fournies.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Mise en œuvre Technique avec Spring AI
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pré-requis
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17+, Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;Un Vector Store. Nous utiliserons &lt;strong&gt;PGVector&lt;/strong&gt; (extension de PostgreSQL), le choix privilégié pour les entreprises car il permet de garder les données transactionnelles et vectorielles au même endroit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Étape 1 : Configuration du Vector Store
&lt;/h4&gt;

&lt;p&gt;Ajoutez le starter PGVector à votre &lt;code&gt;pom.xml&lt;/code&gt; et configurez vos accès dans &lt;code&gt;application.yml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vectorstore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;pgvector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;initialize-schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;index-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HNSW&lt;/span&gt; &lt;span class="c1"&gt;# Optimisation pour la recherche rapide&lt;/span&gt;
        &lt;span class="na"&gt;distance-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;COSINE_DISTANCE&lt;/span&gt;
        &lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1536&lt;/span&gt; &lt;span class="c1"&gt;# Pour OpenAI text-embedding-3-small&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Étape 2 : L'ingestion des documents
&lt;/h4&gt;

&lt;p&gt;Voici comment charger et stocker vos connaissances :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KnowledgeIngestionService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;KnowledgeIngestionService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vectorStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Lecture du PDF&lt;/span&gt;
        &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TikaDocumentReader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdfResource&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Découpage en chunks&lt;/span&gt;
        &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TokenTextSplitter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splitter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Stockage (Embedding + Save)&lt;/span&gt;
        &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Étape 3 : Le Chat avec mémoire contextuelle
&lt;/h4&gt;

&lt;p&gt;Grâce au &lt;code&gt;QuestionAnswerAdvisor&lt;/code&gt;, Spring AI automatise tout le processus de récupération.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RagController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;RagController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// On configure l'Advisor pour le RAG&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ragAdvisor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;QuestionAnswerAdvisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;searchRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SearchRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;topK&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;similarityThreshold&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultAdvisors&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ragAdvisor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ask"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Astuce de pro&lt;/strong&gt; : Si vous constatez que l'IA répond "Je ne sais pas" alors que l'info est présente, baissez le &lt;code&gt;similarityThreshold&lt;/code&gt; (ex: 0.6). Si elle hallucine trop, augmentez-le (ex: 0.8).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analyse &amp;amp; Optimisation : Aller plus loin
&lt;/h3&gt;

&lt;p&gt;Le RAG n'est pas une solution "magique", il demande du réglage :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le défi du Chunking&lt;/strong&gt;&lt;br&gt;
La taille des morceaux est cruciale. Des morceaux trop petits perdent le contexte global. Des morceaux trop grands introduisent du bruit. Une stratégie courante est le "Overlapping" : faire chevaucher les chunks pour ne pas couper une phrase importante en deux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddings : Le moteur de la recherche&lt;/strong&gt;&lt;br&gt;
Le choix du modèle d'embedding (ex: &lt;code&gt;text-embedding-3-small&lt;/code&gt; vs un modèle local via HuggingFace) impacte directement la précision. Un bon modèle d'embedding comprend que "voiture" et "automobile" sont sémantiquement proches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidentialité vs Fine-Tuning&lt;/strong&gt;&lt;br&gt;
Pourquoi choisir le RAG plutôt que le fine-tuning ?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mise à jour instantanée&lt;/strong&gt; : Ajoutez un document au Vector Store, et l'IA le connaît immédiatement. Pas besoin de réentraîner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traçabilité&lt;/strong&gt; : Le RAG permet de citer ses sources ("Selon le document X, page 4..."), ce qui est impossible avec le fine-tuning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sécurité&lt;/strong&gt; : Vous contrôlez exactement quel document est récupéré selon les droits de l'utilisateur.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Ouverture
&lt;/h2&gt;

&lt;p&gt;Le RAG transforme l'IA d'un assistant conversationnel en un véritable expert métier capable d'exploiter vos données privées avec précision et sécurité. C'est la fondation de toute application d'IA sérieuse en entreprise.&lt;/p&gt;

&lt;p&gt;Mais nous avons encore un pas à franchir. Aujourd'hui, notre IA répond. Demain, elle doit &lt;strong&gt;agir&lt;/strong&gt;. C'est là qu'interviennent les &lt;strong&gt;Agents Autonomes&lt;/strong&gt; et le protocole &lt;strong&gt;MCP&lt;/strong&gt;, que nous explorerons dans le prochain article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;À vous de jouer !&lt;/strong&gt; Installez PGVector, chargez vos premiers documents et voyez votre application Spring Boot devenir soudainement très intelligente.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Ressources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/retrieval-augmented-generation.html" rel="noopener noreferrer"&gt;Retrieval Augmented Generation :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/vectordbs/pgvector.html" rel="noopener noreferrer"&gt;PGvector :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simplifiedlearningblog.com/building-rag-pipeline-spring-ai-pgvector/" rel="noopener noreferrer"&gt;Building A RAG Pipeline With Spring AI And Pgvector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>java</category>
      <category>rag</category>
      <category>spring</category>
    </item>
    <item>
      <title>Spring AI : Intégrez l'Intelligence Artificielle dans vos applications Java en quelques minutes</title>
      <dc:creator>Adnene HAMDOUNI</dc:creator>
      <pubDate>Mon, 07 Sep 2026 20:46:17 +0000</pubDate>
      <link>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrez-lintelligence-artificielle-dans-vos-applications-java-en-quelques-minutes-3hk1</link>
      <guid>https://dev.to/adnene_hamdouni_75694870a/spring-ai-integrez-lintelligence-artificielle-dans-vos-applications-java-en-quelques-minutes-3hk1</guid>
      <description>&lt;h1&gt;
  
  
  Spring AI : Intégrez l'Intelligence Artificielle dans vos applications Java en quelques minutes
&lt;/h1&gt;




&lt;h2&gt;
  
  
  📌 Métadonnées
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Titre&lt;/strong&gt; : Spring AI : Intégrez l'Intelligence Artificielle dans vos applications Java en quelques minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sujet&lt;/strong&gt; : Spring Boot / AI / Java&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cible&lt;/strong&gt; : Développeurs Java, Architectes Logiciels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temps de lecture estimé&lt;/strong&gt; : 8 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags&lt;/strong&gt; : #SpringBoot #SpringAI #Java #LLM #GenerativeAI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 Introduction
&lt;/h2&gt;

&lt;p&gt;Pendant longtemps, le monde de l'IA générative a semblé être le domaine exclusif de Python. Entre LangChain, PyTorch et la simplicité des notebooks Jupyter, les développeurs Java se sentaient souvent comme des citoyens de seconde zone, contraints d'appeler des API REST brutes ou de jongler avec des bibliothèques peu matures.&lt;/p&gt;

&lt;p&gt;C'est ici qu'intervient &lt;strong&gt;Spring AI&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Ce nouveau projet de l'écosystème Spring ne se contente pas d'ajouter un client HTTP pour OpenAI. Il apporte une véritable couche d'abstraction, similaire à ce que Spring Data a fait pour les bases de données. L'idée est simple : vous écrivez votre logique métier une seule fois, et vous pouvez changer de modèle d'IA (GPT-4, Claude, Mistral ou même un modèle local via Ollama) sans modifier une seule ligne de code métier.&lt;/p&gt;

&lt;p&gt;À la fin de cet article, vous saurez comment configurer votre premier projet Spring AI et créer un service de chat intelligent capable de retourner des données structurées.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Corps de l'Article
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Concept Fondamental : L'Abstraction du Modèle
&lt;/h3&gt;

&lt;p&gt;Le cœur de Spring AI réside dans l'interface &lt;code&gt;ChatModel&lt;/code&gt;. Plutôt que de vous lier à un SDK spécifique, Spring AI définit un contrat standard pour l'interaction avec les LLM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pourquoi est-ce crucial ?&lt;/strong&gt;&lt;br&gt;
Dans un environnement entreprise, la dépendance à un seul fournisseur d'IA est un risque. Un jour, vous pourriez préférer Azure OpenAI pour la conformité, ou un modèle Llama 3 hébergé localement pour la confidentialité des données. Grâce à l'injection de dépendances de Spring, le passage d'un modèle à un autre se résume à un changement de dépendance dans votre &lt;code&gt;pom.xml&lt;/code&gt; et une clé API dans vos propriétés.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Mise en Œuvre Technique (Le "Comment")
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Pré-requis
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;JDK 17 ou supérieur.&lt;/li&gt;
&lt;li&gt;Spring Boot 3.x.&lt;/li&gt;
&lt;li&gt;Une clé API OpenAI (ou Ollama installé localement).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Étape 1 : Configuration du projet
&lt;/h4&gt;

&lt;p&gt;Ajoutez le starter correspondant à votre fournisseur dans votre fichier &lt;code&gt;pom.xml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-openai-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensuite, configurez votre clé API dans le fichier &lt;code&gt;application.yml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;openai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${OPENAI_API_KEY}&lt;/span&gt;
      &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-4o&lt;/span&gt;
          &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Étape 2 : Création du service de Chat avec ChatClient
&lt;/h4&gt;

&lt;p&gt;L'API fluide &lt;code&gt;ChatClient&lt;/code&gt; est la manière moderne d'interagir avec l'IA. Voici comment implémenter un contrôleur simple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ai"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AiController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Le Builder est auto-configuré par Spring Boot&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AiController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Étape 3 : Maîtriser les PromptTemplates et la Sortie Structurée
&lt;/h4&gt;

&lt;p&gt;Pour rendre vos applications réellement utiles, vous ne pouvez pas vous contenter de messages libres. Vous avez besoin de structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Les PromptTemplates&lt;/strong&gt; permettent d'injecter des variables dynamiques :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Explique-moi le concept de {concept} en deux phrases pour un débutant."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;param&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concept"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Injection de dépendances"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;La Sortie Structurée&lt;/strong&gt; est la fonctionnalité "tueuse" pour les devs Java. Vous pouvez mapper la réponse de l'IA directement dans un &lt;code&gt;record&lt;/code&gt; Java :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;director&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/movie-info"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Movie&lt;/span&gt; &lt;span class="nf"&gt;getMovieInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Donne moi des infos sur le film "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;movieName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Movie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Mapping automatique JSON -&amp;gt; Java Record&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Astuce de pro&lt;/strong&gt; : Utilisez les &lt;code&gt;Advisors&lt;/code&gt; (comme &lt;code&gt;MessageChatMemoryAdvisor&lt;/code&gt;) pour ajouter nativement un historique de conversation sans avoir à gérer manuellement une liste de messages à chaque appel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Analyse &amp;amp; Comparaison : Spring AI vs LangChain4j
&lt;/h3&gt;

&lt;p&gt;Si vous explorez l'IA en Java, vous croiserez forcément &lt;strong&gt;LangChain4j&lt;/strong&gt;. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Critère&lt;/th&gt;
&lt;th&gt;Spring AI&lt;/th&gt;
&lt;th&gt;LangChain4j&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intégration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native et profonde avec Spring Boot&lt;/td&gt;
&lt;td&gt;Bibliothèques autonomes (utilisables partout)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Courbe d'apprentissage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Très faible pour les devs Spring&lt;/td&gt;
&lt;td&gt;Modérée (approche plus proche de LangChain Python)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Écosystème&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bénéficie de tout l'écosystème Spring&lt;/td&gt;
&lt;td&gt;Très complet sur les intégrations tierces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Philosophie&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Abstraction et simplicité&lt;/td&gt;
&lt;td&gt;Flexibilité et richesse fonctionnelle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt; : Si votre stack est déjà Spring Boot, Spring AI est le choix logique pour sa simplicité et son alignement avec vos patterns de développement.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; Ouverture
&lt;/h2&gt;

&lt;p&gt;L'IA n'est plus une "option" ou un gadget pour les data scientists ; c'est désormais un premier citoyen dans l'écosystème Java. Avec Spring AI, la barrière technique s'effondre pour laisser place à l'innovation métier.&lt;/p&gt;

&lt;p&gt;Mais un LLM seul a une limite : il ne connaît pas vos données privées. C'est là qu'intervient le &lt;strong&gt;RAG (Retrieval Augmented Generation)&lt;/strong&gt;. Dans le prochain article, nous verrons comment donner une "mémoire" à votre application Spring Boot en connectant un Vector Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;À vous de jouer !&lt;/strong&gt; Installez Ollama en local, configurez Spring AI et essayez de créer votre premier agent structuré. Partagez vos retours en commentaires !&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 Sources &amp;amp; Ressources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/2.0/api/chatclient.html" rel="noopener noreferrer"&gt;Chat Client API :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/api/prompt.html" rel="noopener noreferrer"&gt;Prompts :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.spring.io/spring-ai/reference/getting-started.html" rel="noopener noreferrer"&gt;Getting Started :: Spring AI Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
