{"id":3995,"date":"2026-07-27T10:00:00","date_gmt":"2026-07-27T14:00:00","guid":{"rendered":"https:\/\/www.mymiller.name\/wordpress\/?p=3995"},"modified":"2026-07-23T15:36:59","modified_gmt":"2026-07-23T19:36:59","slug":"mastering-retrieval-augmented-generation-rag-with-spring-ai","status":"publish","type":"post","link":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/mastering-retrieval-augmented-generation-rag-with-spring-ai\/","title":{"rendered":"Mastering Retrieval-Augmented Generation (RAG) with Spring AI"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Retrieval-Augmented Generation (RAG) has become the gold standard architecture for extending the capabilities of Large Language Models (LLMs) with enterprise domain knowledge. By combining the natural language understanding of LLMs with real-time retrieval from dynamic data stores, RAG eliminates hallucinations, enhances accuracy, and avoids the costly alternative of fine-tuning models on private data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With the emergence of <strong>Spring AI<\/strong>, Java developers now have a native, production-grade framework to build RAG pipelines seamlessly within the familiar Spring ecosystem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Why Spring AI for RAG?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Historically, the AI development landscape was dominated by Python tools such as LangChain and LlamaIndex. Spring AI bridges this gap for enterprise Java applications by introducing portable abstractions across:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>AI Models:<\/strong> Unified interfaces for OpenAI, Anthropic, Ollama, Bedrock, Azure OpenAI, and Hugging Face.<\/li>\n\n\n\n<li><strong>Vector Stores:<\/strong> Standardized CRUD and similarity search across PgVector, Neo4j, Pinecone, Qdrant, Milvus, Redis, Chroma, and Weaviate.<\/li>\n\n\n\n<li><strong>ETL Data Pipelines:<\/strong> Native interfaces for document loading (<code>DocumentReader<\/code>), chunking\/transformation (<code>DocumentTransformer<\/code>), and vector indexing (<code>VectorStore<\/code>).<\/li>\n\n\n\n<li><strong>Advisors:<\/strong> Modular interceptor chains (<code>QuestionAnswerAdvisor<\/code>, <code>RetrievalAugmentationAdvisor<\/code>) that automatically inject retrieved context into chat interactions.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. Key Use Cases for RAG in Enterprise Applications<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Use Case<\/strong><\/td><td><strong>Description<\/strong><\/td><td><strong>Primary Data Source<\/strong><\/td><\/tr><tr><td><strong>Enterprise Knowledge Bases<\/strong><\/td><td>HR policies, technical documentation, internal wikis, and customer support manuals.<\/td><td>PDF, Confluence, Markdown, HTML<\/td><\/tr><tr><td><strong>Customer Support Automation<\/strong><\/td><td>Intelligent chatbots providing factual product answers with exact citations.<\/td><td>Product docs, FAQs, order logs<\/td><\/tr><tr><td><strong>Legal &amp; Compliance Auditing<\/strong><\/td><td>Analyzing contracts, compliance policies, and regulatory documents for risk analysis.<\/td><td>Structured &amp; unstructured legal text<\/td><\/tr><tr><td><strong>Financial Analysis &amp; Reporting<\/strong><\/td><td>Answering questions over quarterly reports, SEC filings, and earning call transcripts.<\/td><td>PDF tables, financial filings<\/td><\/tr><tr><td><strong>Root Cause &amp; Log Analysis<\/strong><\/td><td>Querying system logs, incident reports, and architecture diagrams during outages.<\/td><td>Telemetry logs, Incident reports<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">3. Core Architecture of RAG in Spring AI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A complete Spring AI RAG pipeline consists of two primary phases: <strong>Ingestion (ETL)<\/strong> and <strong>Retrieval &amp; Generation<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-scaled.avif\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"559\" src=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-1024x559.avif\" alt=\"\" class=\"wp-image-3996\" srcset=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-1024x559.avif 1024w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-300x164.avif 300w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-768x419.avif 768w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-1536x838.avif 1536w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-2048x1117.avif 2048w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-scaled.avif 1280w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_a93u0ua93u0ua93u-scaled.avif 1920w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Key Interfaces:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>DocumentReader<\/code>: Ingests raw data from sources (e.g., <code>PagePdfDocumentReader<\/code>, <code>TikaDocumentReader<\/code>).<\/li>\n\n\n\n<li><code>DocumentTransformer<\/code>: Splits long text into manageable token chunks using strategies like <code>TokenTextSplitter<\/code>.<\/li>\n\n\n\n<li><code>EmbeddingModel<\/code>: Converts text chunks into numerical vectors (embeddings).<\/li>\n\n\n\n<li><code>VectorStore<\/code>: Stores vector embeddings along with text chunks and metadata.<\/li>\n\n\n\n<li><code>ChatClient<\/code>: Executes model interactions wrapped with RAG advisors.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">4. Vector DB vs. Graph DB (GraphRAG) Approaches<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the nature of your enterprise data, you can implement RAG using <strong>Vector Databases<\/strong>, <strong>Graph Databases<\/strong>, or a <strong>Hybrid Approach<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-scaled.avif\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"559\" src=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-1024x559.avif\" alt=\"\" class=\"wp-image-3997\" srcset=\"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-1024x559.avif 1024w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-300x164.avif 300w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-768x419.avif 768w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-1536x838.avif 1536w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-2048x1117.avif 2048w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-scaled.avif 1280w, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_5fmhq15fmhq15fmh-scaled.avif 1920w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Option A: Vector Database Approach (Standard RAG)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Vector RAG measures <strong>semantic similarity<\/strong> between the user query vector and document vector embeddings using distance metrics like Cosine Similarity or Euclidean Distance.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How It Works:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Embed text chunks into high-dimensional vectors.<\/li>\n\n\n\n<li>Embed the incoming user query.<\/li>\n\n\n\n<li>Retrieve the Top-$K$ nearest neighbor chunks.<\/li>\n\n\n\n<li>Inject retrieved text into the LLM system prompt.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Pros &amp; Cons:<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros:<\/strong> Easy to set up, highly performant on unstructured text, scales well with standard embeddings.<\/li>\n\n\n\n<li><strong>Cons:<\/strong> Struggles with complex multi-step reasoning, hierarchical logic, or understanding relationships across distant documents.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Sample Spring AI Implementation (Vector Store):<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>@Service\npublic class VectorRagService {\n\n    private final ChatClient chatClient;\n    private final VectorStore vectorStore;\n\n    public VectorRagService(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {\n        this.vectorStore = vectorStore;\n        this.chatClient = chatClientBuilder\n                .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults().withTopK(4)))\n                .build();\n    }\n\n    public String askQuestion(String question) {\n        return chatClient.prompt()\n                .user(question)\n                .call()\n                .content();\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Option B: Graph Database Approach (GraphRAG \/ Knowledge Graphs)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GraphRAG builds an explicit <strong>Knowledge Graph<\/strong> where entities (Nodes) and relationships (Edges) are extracted from documents. Retrieval is performed using graph queries (e.g., Cypher) or graph traversals rather than purely vector distance.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How It Works:<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Entity &amp; Relation Extraction:<\/strong> Use an LLM or Named Entity Recognition (NER) pipeline to parse text into <code>(Entity A) - [RELATION] -> (Entity B)<\/code> triples.<\/li>\n\n\n\n<li><strong>Graph Ingestion:<\/strong> Store nodes and relationships in a graph database like Neo4j or Memgraph.<\/li>\n\n\n\n<li><strong>Graph Retrieval:<\/strong> Convert user questions into Cypher queries or extract localized subgraphs to supply structured relational context to the LLM.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Pros &amp; Cons:<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros:<\/strong> Superior at multi-hop reasoning (e.g., <em>&#8220;Which vendor supplies parts for products impacted by Directive X?&#8221;<\/em>), transparent provenance, zero semantic drift across linked entities.<\/li>\n\n\n\n<li><strong>Cons:<\/strong> Higher ingestion costs (LLM-heavy extraction step), complex graph schema management.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Spring AI &amp; Neo4j Integration Example:<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI provides dedicated support for Neo4j Vector Stores, which combine graph traversal with vector indexes.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Configuration\npublic class GraphRagConfig {\n\n    @Bean\n    public VectorStore neo4jVectorStore(Driver driver, EmbeddingModel embeddingModel) {\n        Neo4jVectorStoreConfig config = Neo4jVectorStoreConfig.builder()\n                .withDatabaseName(\"neo4j\")\n                .withIndexName(\"custom-rag-index\")\n                .build();\n\n        return new Neo4jVectorStore(driver, embeddingModel, config, true);\n    }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For advanced GraphRAG, custom Spring services can execute Cypher queries to extract explicit subgraphs before prompting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@Service\npublic class GraphRagService {\n\n    private final Neo4jClient neo4jClient;\n    private final ChatClient chatClient;\n\n    public GraphRagService(Neo4jClient neo4jClient, ChatClient.Builder chatClientBuilder) {\n        this.neo4jClient = neo4jClient;\n        this.chatClient = chatClientBuilder.build();\n    }\n\n    public String queryGraphAndGenerate(String entityName, String userQuestion) {\n        \/\/ 1. Fetch connected relationships from Knowledge Graph\n        var graphContext = neo4jClient.query(\"\"\"\n                MATCH (e:Entity {name: $name})-&#91;r]-&gt;(related)\n                RETURN e.name + ' ' + type(r) + ' ' + related.name AS fact\n                \"\"\")\n                .bind(entityName).andWith(userQuestion)\n                .fetch().all();\n\n        String context = graphContext.stream()\n                .map(row -&gt; row.get(\"fact\").toString())\n                .collect(Collectors.joining(\"\\n\"));\n\n        \/\/ 2. Prompt LLM with explicit structured context\n        return chatClient.prompt()\n                .system(\"Use the following relational facts to answer the question:\\n\" + context)\n                .user(userQuestion)\n                .call()\n                .content();\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Option C: Hybrid Approach (Vector + Knowledge Graph)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The most resilient enterprise architecture combines both models:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Vector Search:<\/strong> Quickly finds relevant unstructured text blocks and candidate entity IDs.<\/li>\n\n\n\n<li><strong>Graph Traversal:<\/strong> Expands context around candidate entities to fetch structural relationships.<\/li>\n\n\n\n<li><strong>Reranking:<\/strong> Merges vector search results and graph properties, passes top candidates to the LLM.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">5. Building an End-to-End RAG Ingestion Pipeline in Spring AI<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Below is a complete enterprise ingestion pipeline using Spring Boot and Spring AI.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Maven Dependencies (<code>pom.xml<\/code> excerpt):<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;dependencies&gt;\n    &lt;!-- Spring AI Starter --&gt;\n    &lt;dependency&gt;\n        &lt;groupId&gt;org.springframework.ai&lt;\/groupId&gt;\n        &lt;artifactId&gt;spring-ai-openai-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- PgVector Store --&gt;\n    &lt;dependency&gt;\n        &lt;groupId&gt;org.springframework.ai&lt;\/groupId&gt;\n        &lt;artifactId&gt;spring-ai-pgvector-store-spring-boot-starter&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    &lt;!-- Document Reader (PDF) --&gt;\n    &lt;dependency&gt;\n        &lt;groupId&gt;org.springframework.ai&lt;\/groupId&gt;\n        &lt;artifactId&gt;spring-ai-pdf-document-reader&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n&lt;\/dependencies&gt;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Ingestion Service Implementation:<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>@Service\npublic class DocumentIngestionService {\n\n    private final VectorStore vectorStore;\n\n    public DocumentIngestionService(VectorStore vectorStore) {\n        this.vectorStore = vectorStore;\n    }\n\n    public void ingestPdfResource(Resource pdfResource) {\n        \/\/ 1. Read document\n        PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(\n                pdfResource,\n                PdfDocumentReaderConfig.builder()\n                        .withPageTopMargin(0)\n                        .withPageExtractedTextFormatter(new PdfDateCleaner())\n                        .build()\n        );\n        List&lt;Document&gt; rawDocuments = pdfReader.get();\n\n        \/\/ 2. Transform \/ Chunk Text\n        TokenTextSplitter textSplitter = new TokenTextSplitter(\n                800, \/\/ Chunk size in tokens\n                350, \/\/ Minimum chunk size\n                5,   \/\/ Min chunk length chars\n                100, \/\/ Token overlap\n                true \/\/ Keep separators\n        );\n        List&lt;Document&gt; chunkedDocuments = textSplitter.apply(rawDocuments);\n\n        \/\/ 3. Vectorize and Write to Vector Database\n        vectorStore.accept(chunkedDocuments);\n    }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. Advanced Production Strategies for Spring AI RAG<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Chunking Strategy Tuning:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Adjust chunk sizes based on model context windows. Standard general-purpose settings: <code>500 - 1000<\/code> tokens with <code>10-15%<\/code> overlap.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Metadata Filtering:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Use metadata tagging (<code>department<\/code>, <code>tenant_id<\/code>, <code>creation_date<\/code>) to apply precise vector search pre-filtering:<code>Filter.Expression expression = new FilterExpressionBuilder() .eq(\"department\", \"HR\") .and(new FilterExpressionBuilder().eq(\"access_level\", \"PUBLIC\")) .build(); SearchRequest searchRequest = SearchRequest.defaults() .withQuery(\"maternity leave policy\") .withFilterExpression(expression);<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Hybrid Search (Sparse + Dense):<\/strong>\n<ul class=\"wp-block-list\">\n<li>Combine lexical keyword search (BM25) with dense vector search to catch precise alphanumeric terms like product SKUs or error codes.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Re-ranking:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Retrieve a larger candidate pool (e.g., $K=20$) and pass results through a Cross-Encoder \/ Re-ranker model (e.g., Cohere Rerank) to yield the top $K=4$ most relevant chunks before prompting the LLM.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">7. Conclusion &amp; Summary Comparison<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use <strong>Vector Stores<\/strong> for standard unstructured document Q&amp;A, fast implementation cycles, and general semantic search.<\/li>\n\n\n\n<li>Use <strong>Graph Databases (GraphRAG)<\/strong> when your domain requires reasoning over complex entities, explicit relationships, compliance hierarchies, or supply chain linkages.<\/li>\n\n\n\n<li>Leverage <strong>Spring AI<\/strong> abstractions to keep your enterprise application flexible, allowing effortless switching or combining of vector stores and LLM providers.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Retrieval-Augmented Generation (RAG) has become the gold standard architecture for extending the capabilities of Large Language Models (LLMs) with enterprise domain knowledge. By combining the natural language understanding of LLMs with real-time retrieval from dynamic data stores, RAG eliminates hallucinations, enhances accuracy, and avoids the costly alternative of fine-tuning models on private data. With the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3999,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[495,443],"tags":[69,469,319],"series":[],"class_list":["post-3995","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-spring_ai","tag-java-2","tag-rag","tag-spring"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_v05lpdv05lpdv05l-scaled.avif","jetpack-related-posts":[{"id":3893,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/building-intelligent-apps-with-spring-ai\/","url_meta":{"origin":3995,"position":0},"title":"Building Intelligent Apps with Spring AI","author":"Jeffery Miller","date":"December 24, 2025","format":false,"excerpt":"In today's fast-paced world of software development, integrating artificial intelligence into applications is no longer just a trend\u2014it's a necessity. At the heart of this revolution is Generative AI, a type of artificial intelligence that can create new content, such as text, images, and code, in response to prompts. It's\u2026","rel":"","context":"In &quot;Spring AI&quot;","block_context":{"text":"Spring AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/spring_ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/08\/ai-generated-8273796_1280.avif 3x"},"classes":[]},{"id":3987,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/enterprise-ai-at-scale-why-spring-ai-and-java-are-built-for-the-long-run\/","url_meta":{"origin":3995,"position":1},"title":"Enterprise AI at Scale: Why Spring AI and Java are Built for the Long Run","author":"Jeffery Miller","date":"July 23, 2026","format":false,"excerpt":"While Python remains the undisputed king of AI research, data exploration, and model training, the landscape shifts dramatically when moving from experimental notebooks to high-throughput, mission-critical production systems. For enterprise engineering teams building user-facing applications, workflow automations, and LLM-powered services, the real challenge isn't training a model\u2014it's integrating, scaling, securing,\u2026","rel":"","context":"In &quot;AI&quot;","block_context":{"text":"AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_rht72frht72frht7-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_rht72frht72frht7-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_rht72frht72frht7-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_rht72frht72frht7-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_rht72frht72frht7-scaled.avif 3x"},"classes":[]},{"id":3965,"url":"https:\/\/www.mymiller.name\/wordpress\/angular\/bringing-worlds-to-life-integrating-ai-personas-in-multi-user-dungeons-muds\/","url_meta":{"origin":3995,"position":2},"title":"Bringing Worlds to Life: Integrating AI Personas in Multi-User Dungeons (MUDs)","author":"Jeffery Miller","date":"April 20, 2026","format":false,"excerpt":"A few weeks ago, I found myself pondering the ultimate objective for an artificial intelligence system. The answer kept returning to a single concept: the ability to truly mimic a human. This spark of an idea gave rise to a challenge\u2014I needed a sandbox where I could work with AI\u2026","rel":"","context":"In &quot;Angular&quot;","block_context":{"text":"Angular","link":"https:\/\/www.mymiller.name\/wordpress\/category\/angular\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_hsr3ethsr3ethsr3-scaled.avif 3x"},"classes":[]},{"id":3912,"url":"https:\/\/www.mymiller.name\/wordpress\/uncategorized\/spring-boot-4-0-whats-next-for-the-modern-java-architect\/","url_meta":{"origin":3995,"position":3},"title":"Spring Boot 4.0: What&#8217;s Next for the Modern Java Architect?","author":"Jeffery Miller","date":"September 24, 2025","format":false,"excerpt":"A Forward-Looking Comparison of Spring Boot 3.x and 4.0 Staying on top of the rapidly evolving Java ecosystem is paramount for any software architect. The shift from Spring Boot 2.x to 3.x brought significant changes, notably the move to Jakarta EE. Now, with the horizon of Spring Boot 4.0 and\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/09\/per-2056740_1280.avif 3x"},"classes":[]},{"id":3931,"url":"https:\/\/www.mymiller.name\/wordpress\/uncategorized\/advanced-spring-ai-creating-agentic-workflows-with-function-calling\/","url_meta":{"origin":3995,"position":4},"title":"Advanced Spring AI: Creating Agentic Workflows with Function Calling","author":"Jeffery Miller","date":"November 24, 2025","format":false,"excerpt":"The landscape of AI is rapidly evolving, moving beyond simple request-response models to more sophisticated, agentic systems. These systems empower Large Language Models (LLMs) to not just generate text, but to act within your applications, making them an active and integral part of your business logic. Spring AI is at\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/Gemini_Generated_Image_kg5i0ykg5i0ykg5i.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/Gemini_Generated_Image_kg5i0ykg5i0ykg5i.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/Gemini_Generated_Image_kg5i0ykg5i0ykg5i.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2025\/11\/Gemini_Generated_Image_kg5i0ykg5i0ykg5i.avif 2x"},"classes":[]},{"id":3991,"url":"https:\/\/www.mymiller.name\/wordpress\/spring_ai\/integrating-model-context-protocol-mcp-tooling-with-spring-ai\/","url_meta":{"origin":3995,"position":5},"title":"Integrating Model Context Protocol (MCP) Tooling with Spring AI","author":"Jeffery Miller","date":"July 24, 2026","format":false,"excerpt":"The Model Context Protocol (MCP), originally introduced by Anthropic, is an open standard designed to standardize how Large Language Models (LLMs) connect with external context sources\u2014such as databases, local file systems, third-party APIs, and custom enterprise logic. By integrating MCP support into Spring AI, Java developers can decouple tool execution\u2026","rel":"","context":"In &quot;AI&quot;","block_context":{"text":"AI","link":"https:\/\/www.mymiller.name\/wordpress\/category\/ai\/"},"img":{"alt_text":"","src":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_g6ak5ug6ak5ug6ak-scaled.avif","width":350,"height":200,"srcset":"https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_g6ak5ug6ak5ug6ak-scaled.avif 1x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_g6ak5ug6ak5ug6ak-scaled.avif 1.5x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_g6ak5ug6ak5ug6ak-scaled.avif 2x, https:\/\/www.mymiller.name\/wordpress\/wp-content\/uploads\/2026\/07\/Gemini_Generated_Image_g6ak5ug6ak5ug6ak-scaled.avif 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3995","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/comments?post=3995"}],"version-history":[{"count":1,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3995\/revisions"}],"predecessor-version":[{"id":3998,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/posts\/3995\/revisions\/3998"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media\/3999"}],"wp:attachment":[{"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/media?parent=3995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/categories?post=3995"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/tags?post=3995"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/www.mymiller.name\/wordpress\/wp-json\/wp\/v2\/series?post=3995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}