<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged localllm</title>
<link>https://coderlegion.com/tag/localllm</link>
<description>Powered by Question2Answer</description>
<item>
<title>Building a RAG Powered Assistant with Spring AI and LM Studio</title>
<link>https://coderlegion.com/11789/building-a-rag-powered-assistant-with-spring-ai-and-lm-studio</link>
<description>&lt;p&gt;&lt;em&gt;How to Create an Intelligent Document Q&amp;amp;A System Using Spring AI, PostgreSQL, and Vector Embeddings&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Imagine having an AI assistant that can instantly answer questions about hundreds of financial documents, quarterly reports, market analyses, policy papers without you having to manually search through pages of text. That's exactly what Retrieval Augmented Generation (RAG) enables, and in this tutorial, we'll build one from scratch using Spring Boot.&lt;/p&gt;
&lt;p&gt;By the end of this guide, you'll have a fully functional application that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ingests PDF documents and extracts their content&lt;/li&gt;
&lt;li&gt;Converts text into semantic embeddings using AI models&lt;/li&gt;
&lt;li&gt;Stores embeddings in a PostgreSQL vector database&lt;/li&gt;
&lt;li&gt;Answers natural language queries with contextual accuracy&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-is-rag-and-why-does-it-matter-&quot;&gt;What is RAG and Why Does It Matter?&lt;/h3&gt;
&lt;p&gt;Retrieval Augmented Generation (RAG) is a technique that enhances Large Language Models (LLMs) by providing them with relevant context from external knowledge sources. Instead of relying solely on the model's training data, RAG systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Retrieve&lt;/strong&gt; relevant documents based on semantic similarity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Augment&lt;/strong&gt; the LLM's prompt with retrieved context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate&lt;/strong&gt; accurate, grounded answers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach is particularly powerful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enterprise knowledge bases with proprietary information&lt;/li&gt;
&lt;li&gt;Financial document analysis and compliance&lt;/li&gt;
&lt;li&gt;Customer support systems with extensive documentation&lt;/li&gt;
&lt;li&gt;Research paper exploration and literature reviews&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h3&gt;
&lt;p&gt;Our FinanceRag application follows a straightforward yet powerful architecture:&lt;/p&gt;
&lt;h4 id=&quot;1-document-ingestion-pipeline&quot;&gt;1. Document Ingestion Pipeline&lt;/h4&gt;
&lt;p&gt;PDF documents are read from the classpath and processed by Spring AI's &lt;code&gt;PagePdfDocumentReader&lt;/code&gt;, which extracts text while preserving structure.&lt;/p&gt;
&lt;h4 id=&quot;2-text-chunking&quot;&gt;2. Text Chunking&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;TokenTextSplitter&lt;/code&gt; divides the extracted text into manageable chunks (800 tokens each). This is crucial because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Embedding models have token limits&lt;/li&gt;
&lt;li&gt;Smaller chunks provide more precise semantic matching&lt;/li&gt;
&lt;li&gt;Context windows in LLMs benefit from focused, relevant information&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-vector-embedding-generation&quot;&gt;3. Vector Embedding Generation&lt;/h4&gt;
&lt;p&gt;Each text chunk is converted into a high-dimensional vector (embedding) using the &lt;code&gt;nomic-embed-text&lt;/code&gt; model. These embeddings capture semantic meaning similar concepts cluster together in vector space.&lt;/p&gt;
&lt;h4 id=&quot;4-vector-storage-with-pgvector&quot;&gt;4. Vector Storage with pgvector&lt;/h4&gt;
&lt;p&gt;Embeddings are persisted in PostgreSQL using the &lt;code&gt;pgvector&lt;/code&gt; extension, which enables efficient similarity searches. We use HNSW indexing for fast approximate nearest neighbor (ANN) queries.&lt;/p&gt;
&lt;h4 id=&quot;5-query-processing&quot;&gt;5. Query Processing&lt;/h4&gt;
&lt;p&gt;When a user asks a question:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The question is embedded using the same model&lt;/li&gt;
&lt;li&gt;Vector similarity search retrieves the most relevant document chunks&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;QuestionAnswerAdvisor&lt;/code&gt; augments the LLM prompt with this context&lt;/li&gt;
&lt;li&gt;The LLM generates a contextual answer&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;building-the-application-step-by-step&quot;&gt;Building the Application: Step by Step&lt;/h3&gt;
&lt;h4 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h4&gt;
&lt;p&gt;Before diving into code, ensure you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 17+&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PostgreSQL 12+&lt;/strong&gt; with pgvector extension&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LM Studio&lt;/strong&gt; (or another OpenAI-compatible LLM endpoint)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maven 3+&lt;/strong&gt; for dependency management&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;setting-up-postgresql-with-pgvector&quot;&gt;Setting Up PostgreSQL with pgvector&lt;/h4&gt;
&lt;p&gt;You have two options for setting up PostgreSQL:&lt;/p&gt;
&lt;h5 id=&quot;option-1-using-docker-recommended-for-quick-start-&quot;&gt;Option 1: Using Docker (Recommended for Quick Start)&lt;/h5&gt;
&lt;p&gt;Your repository includes a &lt;code&gt;compose.yaml&lt;/code&gt; file for easy setup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;services:
  postgres:
    image: pgvector/pgvector:pg16
    ports:
      - &quot;55419:5432&quot;
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: finance
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simply run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This spins up PostgreSQL with pgvector pre-installed on port 55419.&lt;/p&gt;
&lt;h5 id=&quot;option-2-manual-installation&quot;&gt;Option 2: Manual Installation&lt;/h5&gt;
&lt;p&gt;First, create a database and enable the vector extension:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE DATABASE finance;
\c finance
CREATE EXTENSION IF NOT EXISTS vector;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pgvector extension adds a new &lt;code&gt;vector&lt;/code&gt; data type to PostgreSQL, enabling efficient storage and querying of high-dimensional vectors.&lt;/p&gt;
&lt;h4 id=&quot;configuring-spring-boot&quot;&gt;Configuring Spring Boot&lt;/h4&gt;
&lt;p&gt;Your &lt;code&gt;application.properties&lt;/code&gt; file should include:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;# Application Name
spring.application.name=finaceRag

# Database Configuration (Docker setup)
spring.datasource.url=jdbc:postgresql://localhost:55419/finance
spring.datasource.username=postgres
spring.datasource.password=postgres

# LLM Configuration (LM Studio)
spring.ai.openai.base-url=http://localhost:1234/
spring.ai.openai.api-key=dummy

# Embedding Model
spring.ai.openai.embedding.options.model=nomic-embed-text

# Chat Model
spring.ai.openai.chat.options.model=google/gemma-3-4b

# Vector Store Configuration
spring.ai.vectorstore.pgvector.initialize-schema=true

# Ingestion Control (IMPORTANT!)
financerag.ingest.enabled=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key Configuration Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Port &lt;code&gt;55419&lt;/code&gt; matches the Docker Compose setup&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;initialize-schema=true&lt;/code&gt; automatically creates the vector store table&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nomic-embed-text&lt;/code&gt; is a lightweight, high-quality embedding model&lt;/li&gt;
&lt;li&gt;&lt;code&gt;google/gemma-3-4b&lt;/code&gt; is the chat model served by LM Studio&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt; Important: Ingestion Control&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;financerag.ingest.enabled&lt;/code&gt; property is a smart optimization:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First Run (Initial Setup):&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;financerag.ingest.enabled=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This processes your PDFs and populates the vector store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subsequent Runs:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;financerag.ingest.enabled=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This skips ingestion and starts the application immediately. The embeddings are already in PostgreSQL, so there's no need to re-process documents every time!&lt;/p&gt;
&lt;p&gt;This design prevents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duplicate embeddings in the database&lt;/li&gt;
&lt;li&gt;Slow startup times on every restart&lt;/li&gt;
&lt;li&gt;Unnecessary LLM API calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;setting-up-lm-studio&quot;&gt;Setting Up LM Studio&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Download and Install LM Studio&lt;/strong&gt; from &lt;a rel=&quot;nofollow&quot; href=&quot;https://lmstudio.ai/&quot;&gt;lmstudio.ai&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Download the Required Models:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Embedding Model:&lt;/strong&gt; Search for &quot;nomic-embed-text&quot; in LM Studio and download it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat Model:&lt;/strong&gt; Search for &quot;google/gemma-3-4b&quot; (or similar) and download it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start the Local Server:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open LM Studio&lt;/li&gt;
&lt;li&gt;Go to the &quot;Local Server&quot; tab&lt;/li&gt;
&lt;li&gt;Select your chat model (gemma-3-4b)&lt;/li&gt;
&lt;li&gt;Click &quot;Start Server&quot; (it will run on &lt;code&gt;http://localhost:1234&lt;/code&gt; by default)&lt;/li&gt;
&lt;li&gt;Ensure the embedding model is also loaded&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verify the Connection:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl http://localhost:1234/v1/models
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see your loaded models listed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;the-ingestion-service&quot;&gt;The Ingestion Service&lt;/h4&gt;
&lt;p&gt;The heart of our document processing pipeline is the &lt;code&gt;IngestionService&lt;/code&gt;. Here's how it works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Component
@ConditionalOnProperty(
    name = &quot;financerag.ingest.enabled&quot;,
    havingValue = &quot;true&quot;,
    matchIfMissing = false
)
public class IngestionService implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(IngestionService.class);
    
    private final VectorStore vectorStore;
    
    @Value(&quot;classpath:/docs/article.pdf&quot;)
    private Resource pdfResource;
    
    public IngestionService(VectorStore vectorStore) {
        this.vectorStore = vectorStore;
    }
    
    @Override
    public void run(String... args) throws Exception {
        logger.info(&quot;Starting data ingestion process...&quot;);
        
        // 1. Read PDF using paragraph-based reader
        var pdfReader = new ParagraphPdfDocumentReader(pdfResource);
        
        // 2. Split text into chunks
        TextSplitter splitter = new TokenTextSplitter();
        
        // 3. Process and store in vector database
        vectorStore.accept(splitter.apply(pdfReader.get()));
        
        logger.info(&quot;Vector store updated with PDF content.&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key Implementation Insights:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Conditional Ingestion&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;@ConditionalOnProperty&lt;/code&gt; annotation is brilliant - it only runs ingestion when you explicitly enable it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;# Enable ingestion on first run
financerag.ingest.enabled=true

# Disable after initial setup to avoid re-ingesting
financerag.ingest.enabled=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prevents re-processing documents on every application restart!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. CommandLineRunner Interface&lt;/strong&gt;&lt;br&gt;
By implementing &lt;code&gt;CommandLineRunner&lt;/code&gt;, the ingestion happens automatically after Spring Boot starts, but before the application begins serving requests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. ParagraphPdfDocumentReader vs PagePdfDocumentReader&lt;/strong&gt;&lt;br&gt;
Your code uses &lt;code&gt;ParagraphPdfDocumentReader&lt;/code&gt; which:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preserves document structure better by respecting paragraph boundaries&lt;/li&gt;
&lt;li&gt;Creates more semantically meaningful chunks&lt;/li&gt;
&lt;li&gt;Better suited for financial documents with structured content&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. Simplified API&lt;/strong&gt;&lt;br&gt;
The &lt;code&gt;vectorStore.accept()&lt;/code&gt; method elegantly handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Embedding generation for each chunk&lt;/li&gt;
&lt;li&gt;Batch insertion into PostgreSQL&lt;/li&gt;
&lt;li&gt;All the complexity hidden behind a clean API&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;the-chat-controller&quot;&gt;The Chat Controller&lt;/h4&gt;
&lt;p&gt;Now let's expose a REST endpoint for queries:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder chatClient, PgVectorStore vectorStore) {
        this.chatClient = chatClient
            .defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).build())
            .build();
    }
    
    @GetMapping(&quot;/chat&quot;)
    public String chat(@RequestParam String question) {
        return chatClient.prompt()
            .user(question)
            .call()
            .content();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The Magic of QuestionAnswerAdvisor:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;QuestionAnswerAdvisor&lt;/code&gt; is where RAG happens. Behind the scenes, it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Converts the user's question into an embedding&lt;/li&gt;
&lt;li&gt;Performs a similarity search against the vector store&lt;/li&gt;
&lt;li&gt;Injects the most relevant document chunks into the prompt&lt;/li&gt;
&lt;li&gt;Sends the augmented prompt to the LLM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Key Implementation Details:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The advisor is built using the builder pattern: &lt;code&gt;QuestionAnswerAdvisor.builder(vectorStore).build()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Spring AI automatically handles the vector search and context injection&lt;/li&gt;
&lt;li&gt;The controller method is elegantly simple - just pass the question through the chat client&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;real-world-considerations&quot;&gt;Real World Considerations&lt;/h3&gt;
&lt;h4 id=&quot;choosing-the-right-chunk-size&quot;&gt;Choosing the Right Chunk Size&lt;/h4&gt;
&lt;p&gt;The 800-token chunk size is a starting point. Consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Smaller chunks (200-400 tokens):&lt;/strong&gt; Better precision, but may lose context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Larger chunks (1000-1500 tokens):&lt;/strong&gt; More context, but less precise matching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Experiment with your specific use case. Financial reports might need larger chunks to preserve numerical context, while FAQs work better with smaller, focused chunks.&lt;/p&gt;
&lt;h4 id=&quot;scaling-to-production&quot;&gt;Scaling to Production&lt;/h4&gt;
&lt;p&gt;For production deployments, consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Async ingestion:&lt;/strong&gt; Move document processing to background jobs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching:&lt;/strong&gt; Cache embeddings for frequently accessed documents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata filtering:&lt;/strong&gt; Add tags (date, category, source) to narrow searches&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt; Track query latency and similarity scores&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;hybrid-search-strategies&quot;&gt;Hybrid Search Strategies&lt;/h4&gt;
&lt;p&gt;Pure vector search isn't always optimal. Combine it with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Full-text search:&lt;/strong&gt; For exact keyword matches&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BM25 ranking:&lt;/strong&gt; Traditional relevance scoring&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Re-ranking:&lt;/strong&gt; Use a cross-encoder model to refine top results&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;testing-your-rag-system&quot;&gt;Testing Your RAG System&lt;/h3&gt;
&lt;p&gt;Start the application and test with curl:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl &quot;http://localhost:8080/chat?question=What%20were%20the%20key%20trends%20in%20Q4%20earnings?&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see an answer grounded in your ingested documents. Compare responses with and without RAG to appreciate the difference in accuracy and relevance.&lt;/p&gt;
&lt;h3 id=&quot;common-pitfalls-and-solutions&quot;&gt;Common Pitfalls and Solutions&lt;/h3&gt;
&lt;h4 id=&quot;1-embedding-dimension-mismatch&quot;&gt;1. Embedding Dimension Mismatch&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Embeddings fail to store with dimension errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Ensure &lt;code&gt;spring.ai.vectorstore.pgvector.dimensions&lt;/code&gt; matches your embedding model. For &lt;code&gt;nomic-embed-text&lt;/code&gt;, use 768.&lt;/p&gt;
&lt;h4 id=&quot;2-poor-retrieval-quality&quot;&gt;2. Poor Retrieval Quality&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Answers don't align with document content.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Adjust chunk size, increase &lt;code&gt;topK&lt;/code&gt;, or lower the similarity threshold. Also verify your embedding model is appropriate for your domain.&lt;/p&gt;
&lt;h4 id=&quot;3-memory-issues-during-ingestion&quot;&gt;3. Memory Issues During Ingestion&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Application crashes with &lt;code&gt;OutOfMemoryError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Process documents in batches, increase JVM heap size (&lt;code&gt;-Xmx4g&lt;/code&gt;), or limit the &lt;code&gt;maxNumChunks&lt;/code&gt; parameter.&lt;/p&gt;
&lt;h3 id=&quot;extending-financerag-ideas-for-enhancement&quot;&gt;Extending FinanceRag: Ideas for Enhancement&lt;/h3&gt;
&lt;p&gt;This project is a foundation. Here are some powerful extensions:&lt;/p&gt;
&lt;h4 id=&quot;multi-document-support&quot;&gt;Multi Document Support&lt;/h4&gt;
&lt;p&gt;Instead of hardcoding a single PDF, scan a directory or accept uploads via REST API. Add metadata (filename, upload date) to enable filtered searches.&lt;/p&gt;
&lt;h4 id=&quot;conversational-memory&quot;&gt;Conversational Memory&lt;/h4&gt;
&lt;p&gt;Implement session based chat history so users can ask follow up questions without repeating context. Spring AI supports this with &lt;code&gt;MessageChatMemoryAdvisor&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;source-attribution&quot;&gt;Source Attribution&lt;/h4&gt;
&lt;p&gt;Return not just the answer but citations showing which document chunks were used. This builds trust and allows users to verify information.&lt;/p&gt;
&lt;h4 id=&quot;advanced-analytics&quot;&gt;Advanced Analytics&lt;/h4&gt;
&lt;p&gt;Track which documents are queried most frequently, average similarity scores, and query patterns to identify knowledge gaps.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;You've now built a production-ready RAG system that can intelligently answer questions about your documents. This architecture scales to thousands of documents and can be adapted for countless use cases such as customer support, legal document analysis, medical research, and more.&lt;/p&gt;
&lt;p&gt;The beauty of Spring AI is how it abstracts the complexity of embeddings, vector stores, and LLM orchestration, letting you focus on business logic. With just three components IngestionService, ChatController, and pgvector we've created a powerful AI assistant.&lt;/p&gt;
&lt;p&gt;The full source code for FinanceRag is available on &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/abhijith-zero/FinanceRag&quot;&gt;GitHub&lt;/a&gt;. Clone it, experiment with different models and chunk sizes, and adapt it to your domain. The future of enterprise AI is built on foundations like these combining the power of LLMs with your organization's proprietary knowledge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Special Thanks:&lt;/strong&gt; This project was inspired by the excellent Spring AI content from &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.danvega.dev/&quot;&gt;Dan Vega&lt;/a&gt;, whose tutorials have helped countless developers understand the power of RAG architectures.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Happy coding, and may your AI assistants always retrieve the right context!&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;about-the-author&quot;&gt;About the Author&lt;/h3&gt;
&lt;p&gt;This tutorial is brought to you by the &lt;a rel=&quot;nofollow&quot; href=&quot;https://abhizero.vercel.app/&quot;&gt;Abhijith Rajesh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/abhijith-zero/FinanceRag&quot;&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://docs.spring.io/spring-ai/reference/&quot;&gt;Spring AI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/pgvector/pgvector&quot;&gt;pgvector Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://lmstudio.ai/&quot;&gt;LM Studio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/11789/building-a-rag-powered-assistant-with-spring-ai-and-lm-studio</guid>
<pubDate>Tue, 17 Feb 2026 03:15:30 +0000</pubDate>
</item>
</channel>
</rss>