<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged springai</title>
<link>https://coderlegion.com/tag/springai</link>
<description>Powered by Question2Answer</description>
<item>
<title>The Bug That's Been Breaking Software for 40 Years Is Now Breaking Your AI Agents, Too</title>
<link>https://coderlegion.com/25313/the-bug-thats-been-breaking-software-for-40-years-is-now-breaking-your-ai-agents-too</link>
<description>&lt;p&gt;Picture a Java developer shipping an AI agent into production. The agent gets a prompt and starts working through a task, 50 steps, each one a call to a model like OpenAI or Anthropic, a database write, maybe a few dollars of compute. At step 49 of 50, something fails: a bug, a network blip, an AWS outage, a Kubernetes scale-down mid-run. What happens next, according to Yaron Schneider, CTO and co-founder of Diagrid, is the part nobody budgets for. &quot;The agent is going to need to pick back up all the way from the beginning, and you're going to be paying for all of those LLM calls right from the very beginning,&quot; he said. &quot;Which is a great way to go bankrupt.&quot;&lt;/p&gt;
&lt;p&gt;That failure mode is what Diagrid's new integration, diagrid-spring-ai, is built to close. Announced this week, it brings durable execution to Spring AI, the framework Java developers already use to build agents, without asking them to rethink how they write one.&lt;/p&gt;
&lt;h3 id=&quot;the-same-40-year-old-problem-with-worse-consequences&quot;&gt;The same 40-year-old problem, with worse consequences&lt;/h3&gt;
&lt;p&gt;Schneider doesn't frame this as a new category of failure. It's the same reliability problem distributed systems have always had. &quot;The exact same problems that made software unreliable for the past 40 years are still true for AI agents,&quot; he said. &quot;Only with AI agents, the consequences are much bigger.&quot; A crashed script used to mean lost time. A crashed agent means lost time and a re-billed stack of model calls, at a cost that scales with however many steps the agent had already completed.&lt;/p&gt;
&lt;p&gt;Schneider said the companies Diagrid works with see failures on roughly 30% of production agent runs, on average, not rare edge cases, but a routine cost of running agents at scale.&lt;/p&gt;
&lt;h3 id=&quot;zero-code-changes-by-design&quot;&gt;Zero code changes, by design&lt;/h3&gt;
&lt;p&gt;The integration's core pitch is unusually low-friction for infrastructure-level tooling. &quot;With Spring AI, literally nothing,&quot; Schneider said, when asked what a developer has to change to adopt it. &quot;All you need to do is pull in the package. There is zero code changes. You do not need to recompile your code.&quot; Underneath, the integration runs on Dapr Workflow, the open-source project Schneider originally built at Microsoft and later spun into Diagrid, now used by more than 30,000 companies, including over half the Fortune 500 and, notably, NASA.&lt;/p&gt;
&lt;h3 id=&quot;how-it-actually-avoids-re-running-side-effects&quot;&gt;How it actually avoids re-running side effects&lt;/h3&gt;
&lt;p&gt;The obvious follow-up question for anyone who's built distributed systems: how do you resume an interrupted agent without re-executing a step that already sent an email or wrote to a database? Diagrid's answer is an immutable ledger. &quot;We keep an immutable record of everything that the agent did. We're essentially journaling,&quot; Schneider said. When an agent fails mid-run, the platform reads the journal, recovers the state, exactly what was completed, its inputs, outputs, and memory, and resumes from that point rather than replaying anything already finished.&lt;/p&gt;
&lt;p&gt;Schneider was direct about the confidence customers should have in that recovery: &quot;If they're using our technology, they know for 100%, for a fact, that we will always resume where they left off mid-run.&quot; He added that customers can and do test this themselves, running failure simulations in their own environments to verify the behavior before trusting it in production.&lt;/p&gt;
&lt;h3 id=&quot;why-this-isn-t-just-a-spring-ai-feature&quot;&gt;Why this isn't just a Spring AI feature&lt;/h3&gt;
&lt;p&gt;A natural question is why durable execution lives as a separate integration rather than something Spring AI ships with directly. Schneider's answer comes down to what a workflow engine actually requires. &quot;Workflow engines are incredibly hard to get right. They require their own separate infrastructure, and Spring is just not that,&quot; he said. Bundling a database and deployment model into a lightweight developer framework would hurt adoption, not help it. Building that infrastructure in-house isn't a reasonable alternative either: Schneider pointed to Microsoft's own investment, a team of 15 engineers spending more than $10 million a year maintaining its workflow engine, as a sense of the actual cost most teams would take on trying to solve this themselves.&lt;/p&gt;
&lt;h3 id=&quot;the-claim-schneider-thinks-is-overrated&quot;&gt;The claim Schneider thinks is overrated&lt;/h3&gt;
&lt;p&gt;Asked what's overstated in the broader AI agent conversation right now, Schneider didn't hesitate: model accuracy. &quot;Models are going to continue getting better. They're going to continue being cheaper,&quot; he said. &quot;I see a lot of emphasis being put on that instead of, you know, how do you orchestrate multiple agents needing to solve a task and all of them failing at the same time.&quot; In his view, the infrastructure problem, keeping agents reliable when things break, is a bigger and less-discussed risk than whatever incremental accuracy gain the next model release brings.&lt;/p&gt;
&lt;h3 id=&quot;beyond-spring&quot;&gt;Beyond Spring&lt;/h3&gt;
&lt;p&gt;diagrid-spring-ai is one piece of a broader set of integrations Diagrid maintains across roughly ten agent frameworks spanning Python, C#, and Java, including LangChain, LangGraph, and CrewAI. Developers can try the platform directly at diagrid.io, where Schneider said quick-start guides let teams test the failure-recovery behavior themselves before committing to it in production.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25313/the-bug-thats-been-breaking-software-for-40-years-is-now-breaking-your-ai-agents-too</guid>
<pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate>
</item>
<item>
<title>Is Java Still Viable in the Era of Agentic AI?</title>
<link>https://coderlegion.com/12431/is-java-still-viable-in-the-era-of-agentic-ai</link>
<description>&lt;p&gt;If you only watched conference keynotes and social feeds, you might assume the future of agentic AI belongs entirely to Python notebooks and TypeScript frontends. Meanwhile, most systems that agents actually need to reason about and act on are still written in Java. That mismatch is a huge opportunity for Java developers.&lt;/p&gt;
&lt;p&gt;Agentic AI isn’t about yet another chatbot; it is about autonomous systems that understand goals, plan multi‑step workflows, call tools, and adapt based on feedback. The more those agents touch mission‑critical workflows—payments, logistics, fraud detection, core banking—the more they need predictable, observable, transactional backends. That’s exactly where modern Java shines.&lt;/p&gt;
&lt;p&gt;So the real question isn’t “Is Java still viable?” It is “Why would you &lt;em&gt;not&lt;/em&gt; want your agentic AI to live as close as possible to your existing Java estate?”&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;java-is-still-the-backbone-where-agents-act&quot;&gt;Java is still the backbone where agents act&lt;/h3&gt;
&lt;p&gt;Despite the hype around newer languages, multiple analyses show Java remains the backbone of enterprise applications. Across banking, healthcare, logistics, and government, the systems of record and high‑value workflows agents will operate on are overwhelmingly Java/JVM‑based.&lt;/p&gt;
&lt;p&gt;That matters for agentic AI because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agents need reliable tools: tool‑calling means hitting APIs, services, and workflows that already exist—often Spring Boot services, Jakarta EE apps, or JVM‑backed microservices.&lt;/li&gt;
&lt;li&gt;Latency and consistency matter: when agents orchestrate multi‑step workflows, you care about transactional guarantees, idempotency, and consistent state—not just “good enough” responses.&lt;/li&gt;
&lt;li&gt;Domain skills live in Java: the most valuable agents encapsulate deep domain knowledge, and that knowledge is usually encoded in existing Java services and libraries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The more “real work” agents do, the closer they get to your Java services. You can wrap those services from the outside—or you can make Java a first‑class home for the agents themselves.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-emerging-java-agentic-ai-stack&quot;&gt;The emerging Java agentic AI stack&lt;/h3&gt;
&lt;p&gt;Over the last 18–24 months, a serious Java‑native ecosystem for agentic AI has started to materialize. Instead of bolting Python micro‑projects onto your stack, you can increasingly stay in the JVM world.&lt;/p&gt;
&lt;p&gt;Notable examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Spring AI &amp;amp; agentic patterns&lt;/strong&gt;: Spring AI and the new agentic patterns series show how to build agents, define “skills,” orchestrate tasks, and even wire up agent‑to‑agent protocols using familiar Spring idioms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Quarkus + LangChain4j&lt;/strong&gt;: Community content demonstrates building reasoning, tool‑using agents with Quarkus and LangChain4j, turning annotated Java methods into callable agent tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated Java agent learning paths&lt;/strong&gt;: New courses and specializations focus on “AI agents in Java,” covering goal management, tool discovery, and multi‑agent collaboration entirely on the JVM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The message: agentic AI no longer has to be a foreign body that lives in a different language. You can build and run it where your code, tooling, and operational muscle already exist—inside Java.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;why-agentic-ai-plays-to-java-s-strengths&quot;&gt;Why agentic AI plays to Java’s strengths&lt;/h3&gt;
&lt;p&gt;Agentic systems are long‑lived, stateful, and deeply integrated. That aligns naturally with Java’s historical strengths in enterprise backends.&lt;/p&gt;
&lt;p&gt;Key advantages Java brings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mature concurrency and scaling&lt;/strong&gt;: Agent workflows involve background tasks, parallel tool calls, streaming IO, and backpressure. Java’s concurrency primitives and modern structured concurrency patterns give you robust ways to manage that complexity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stability and backward compatibility&lt;/strong&gt;: Enterprises rely on Java because they can modernize runtimes without rewriting entire codebases, which is critical when agents touch long‑lived systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Battle‑tested ecosystem&lt;/strong&gt;: Observability (Micrometer, Actuator), messaging (Kafka, Pulsar), security, and transaction management are all mature in the Java world—exactly what you want when autonomous systems start making changes in production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Agentic AI doesn’t reduce the need for these qualities; it magnifies it.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-minimal-spring-ai-agent-example&quot;&gt;A minimal Spring AI agent example&lt;/h3&gt;
&lt;p&gt;To make this concrete, here is a simplified example inspired by Spring AI agent samples. Imagine a Java “incident triage” agent that can read a goal and decide which internal tools to call. &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/spring-projects/spring-ai-examples&quot;&gt;github&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Service
public class IncidentTriageAgent {

    private final AgentClient agentClient;

    public IncidentTriageAgent(AgentClient agentClient) {
        this.agentClient = agentClient;
    }

    // Tool the agent can call
    @Tool(&quot;fetch current JVM error rate&quot;)
    public double getErrorRate(String serviceName) {
        // call Prometheus/Grafana/observability backend
        return metricsClient.queryErrorRate(serviceName);
    }

    public String triage(String description) {
        String goal = &quot;&quot;&quot;
            You are an SRE assistant for a Java microservices platform.
            Use available tools to decide:
            1) Is this incident urgent?
            2) Which service is most likely impacted?
            3) What is the first remediation step?
            Incident: %s
            &quot;&quot;&quot;.formatted(description);

        AgentClientResponse response = agentClient
            .goal(goal)
            .timeout(Duration.ofSeconds(30))
            .run();

        return response.getResult();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the agent runs &lt;em&gt;inside&lt;/em&gt; a Spring Boot service, calls Java methods as tools, and uses your existing metrics stack to reason about production incidents. You get agentic behavior without leaving the JVM or duplicating operational infrastructure.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-this-means-for-java-developers&quot;&gt;What this means for Java developers&lt;/h3&gt;
&lt;p&gt;If you are a Java developer wondering how to stay relevant in the era of agentic AI, the answer is not “switch to Python.” It is to lean into the parts of agentic systems that Java is uniquely good at.&lt;/p&gt;
&lt;p&gt;Practical next steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick a JVM‑friendly framework like Spring AI or LangChain4j and build one small agent that calls tools you already own.&lt;/li&gt;
&lt;li&gt;Model “tools” as well‑typed Java methods and services, not ad hoc shell commands.  &lt;/li&gt;
&lt;li&gt;Double down on observability, safety, and rollback paths—areas where Java and Spring Boot already excel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Agentic AI is moving from buzzword to architecture, and the systems it will depend on are overwhelmingly Java. That doesn’t make Java obsolete; it makes Java more strategically central than ever.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/12431/is-java-still-viable-in-the-era-of-agentic-ai</guid>
<pubDate>Fri, 06 Mar 2026 15:33:07 +0000</pubDate>
</item>
<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>