场景Spring AI RAG 检索增强生成概念、实战与完整代码https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/161055108基于上面的基础实现Graph工作流编排的简单示例。大语言模型LLM在实际应用中面临知识滞后、领域知识不足等问题。检索增强生成RAG通过“先检索外部知识再结合生成”的模式有效弥补了这些缺陷。更进一步Agent 智能体赋予了模型“思考-规划-调用工具”的自治能力使其能够灵活应对复杂任务。本文基于 Spring AI 1.1.2 Ollama 技术栈从最基础的 RAG 问答开始一步步构建出一个具备 Graph 工作流编排的智能体。文中所有代码均经过实际验证并整理了开发过程中常见的版本兼容性、API 差异等问题的解决方案。技术栈与核心概念技术组件说明Spring AI 1.1.2Java AI 集成框架提供 ChatClient、VectorStore、Advisors 等核心抽象Ollama本地大模型运行时部署 qwen2.5:7b对话和 nomic-embed-text向量化SimpleVectorStoreSpring AI 内置内存向量库开发阶段使用支持文件持久化Tika DocumentReader自动识别 PDF、Word、TXT 等格式的文档读取器QuestionAnswerAdvisorRAG 核心 Advisor自动检索向量库并将结果注入对话上下文Agent / Graph智能体能够自主决策、规划步骤、调用外部工具的自治系统Graph 是其工作流编排方式RAG 四步流程文档加载与分块 → 向量化与存储 → 语义检索 → 增强生成Agent 工作流检索知识库 → 若无结果调用天气工具 → 综合生成答案Spring AI 实现 Agent 的两种方式1. 工具调用模式简单 Agent直接在 ChatClient 中注册工具让模型自主决策调用。Spring AI 整合 Ollama 实现工具调用从入门到实战全解https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1610091532. Graph 编排型 Agent复杂多步推理使用 StateGraph 构建节点和边支持条件分支、循环适合实现 ReAct 等模式。用户提问 → 检索知识库 → [置信度低] → 调用工具 → 汇总答案↓[置信度高] → 直接生成答案注博客https://blog.csdn.net/badao_liumang_qizhi实现pom.xml 完整配置parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.4.5/version /parent groupIdcom.example/groupId artifactIdspring-ai-ollama-rag-graph/artifactId version1.0/version properties java.version17/java.version spring-ai.version1.1.2/spring-ai.version /properties !--使用 Spring AI BOM 统一管理所有模块版本 -- dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- Spring AI Ollama 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-ollama/artifactId /dependency !-- RAG Advisor核心提供 QuestionAnswerAdvisor -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-advisors-vector-store/artifactId /dependency !-- Tika 文档读取器支持 PDF、Word、TXT 等多种格式 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tika-document-reader/artifactId /dependency说明本文未使用 Elasticsearch 或 Milvus而是使用 Spring AI 内置的 SimpleVectorStore 并开启文件持久化避免了外部向量数据库的安装和版本兼容问题。若使用外部向量数据库可参考如下基于 Milvus Lite 的 Spring AI RAG 向量库实践方案与示例https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/161118610application.yml​ server: port: 886 spring: # 替换为实际密码 ai: ollama: base-url: http://localhost:11434 chat: model: qwen2.5:7b-instruct options: temperature: 0.3 # RAG 场景建议使用较低温度减少幻觉 embedding: model: nomic-embed-text # Embedding 模型用于文档向量化 options: num-batch: 4 # 一次处理的文本数量 logging: level: org.springframework.ai.rag: DEBUG org.springframework.ai.vectorstore: DEBUG ​VectorStoreConfig – 文档加载与持久化向量库package com.badao.ai.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentReader; import org.springframework.ai.reader.tika.TikaDocumentReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import java.util.List; Configuration public class VectorStoreConfig { private static final Logger logger LoggerFactory.getLogger(VectorStoreConfig.class); Value(classpath:knowledge-base/badao-internal.txt) private Resource knowledgeResource; Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { // 创建内存向量库开发演示用 return SimpleVectorStore.builder(embeddingModel).build(); } Bean public CommandLineRunner loadDocuments(VectorStore vectorStore) { return args - { // 1. 使用 Tika 读取文档自动检测文件类型 DocumentReader reader new TikaDocumentReader(knowledgeResource); ListDocument documents reader.get(); logger.info(共读取到 {} 个文档, documents.size()); // 2. 文本分块TokenTextSplitter 按语义切分更适合中文 TokenTextSplitter splitter TokenTextSplitter.builder() .withChunkSize(300) // 每个块最多 300 token .withMinChunkSizeChars(50) // 最小块字符数避免出现极短碎片替代原来 minChunkSize 的功能 .withMinChunkLengthToEmbed(5) // 保留默认过滤极短内容 .withKeepSeparator(true) // 保留原文换行等分隔符 .build(); ListDocument chunks splitter.apply(documents); logger.info(文本切分为 {} 个片段, chunks.size()); // 3. 写入向量数据库自动调用 EmbeddingModel 向量化 vectorStore.add(chunks); logger.info(向量化完成向量库初始化成功); }; } }AgentRagConfig – 工具调用模式轻量 Agent该配置类展示了 Spring AI 中最简单的 Agent 实现方式无需 Graph 工作流直接在 ChatClient 上注册工具大模型会根据用户问题自主判断是否需要调用工具以及调用哪个工具package com.badao.ai.config; import com.badao.ai.tools.WeatherTool; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class AgentRagConfig { Bean public ChatClient chatClient(ChatModel chatModel, VectorStore vectorStore, WeatherTool weatherTool) { return ChatClient.builder(chatModel) .defaultAdvisors( QuestionAnswerAdvisor.builder(vectorStore) .searchRequest(SearchRequest.builder() .similarityThreshold(0.7) .topK(3) .build()) .build() ) .defaultTools(weatherTool) // 注册Tool工具 .build(); } }WeatherTool – 天气工具类package com.badao.ai.tools; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; Component public class WeatherTool { Tool(name get_weather, description 查询指定城市的实时天气) public String getWeather(ToolParam(description 城市名称) String city) { System.out.println(调用了天气工具); // 模拟天气查询实际可对接天气API return String.format(%s当前天气晴温度22℃湿度45%%。, city); } }AgentGraphConfig – Graph 编排与 Agent 工作流package com.badao.ai.config; import com.badao.ai.tools.WeatherTool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.document.Document; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; import java.util.stream.Collectors; Configuration public class AgentGraphConfig { private static final Logger log LoggerFactory.getLogger(AgentGraphConfig.class); Bean(agentChatClient) public ChatClient agentChatClient(ChatModel chatModel, VectorStore vectorStore) { return ChatClient.builder(chatModel) .defaultAdvisors( QuestionAnswerAdvisor.builder(vectorStore) .searchRequest(SearchRequest.builder() .similarityThreshold(0.7) .topK(3) .build()) .build() ) .build(); } Bean public AgentWorkflow agentWorkflow(VectorStore vectorStore, Qualifier(agentChatClient) ChatClient chatClient, WeatherTool weatherTool) { return new AgentWorkflow(vectorStore, chatClient, weatherTool); } public static class AgentWorkflow { private final VectorStore vectorStore; private final ChatClient chatClient; private final WeatherTool weatherTool; public AgentWorkflow(VectorStore vectorStore, ChatClient chatClient, WeatherTool weatherTool) { this.vectorStore vectorStore; this.chatClient chatClient; this.weatherTool weatherTool; } public String execute(String query) { // 1. 检索 // 使用 Builder 模式正确构建 SearchRequest ListDocument docs vectorStore.similaritySearch( SearchRequest.builder() .query(query) // 设置查询文本公开方法 .similarityThreshold(0.7) .topK(3) .build() ); System.out.println(检索到文档数量docs.size()); log.info( 检索到 {} 篇相关文档, docs.size()); // 2. 条件调用工具 String toolResult null; if (docs.isEmpty()) { System.out.println(知识库无相关内容自动调用天气工具); log.info(⚠️ 知识库无相关内容自动调用天气工具); String city extractCity(query); toolResult weatherTool.getWeather(city); } // 3. 生成答案 String context docs.stream() .map(Document::getFormattedContent) .collect(Collectors.joining(\n)); String prompt buildPrompt(query, context, toolResult); return chatClient.prompt().user(prompt).call().content(); } private String extractCity(String query) { if (query.contains(北京)) return 北京; if (query.contains(上海)) return 上海; if (query.contains(青岛)) return 青岛; return 未知城市; } private String buildPrompt(String query, String context, String toolResult) { StringBuilder sb new StringBuilder(); sb.append(请基于以下信息回答用户问题。\n); if (!context.isEmpty()) { sb.append(知识库相关信息\n).append(context).append(\n); } if (toolResult ! null) { sb.append(外部工具查询结果).append(toolResult).append(\n); } sb.append(用户问题).append(query); sb.append(\n请给出简洁专业的回答。); return sb.toString(); } } }关键点这里用 Java 代码直接实现了 Graph 的三个节点检索、工具调用、生成并通过条件分支体现了智能体的“规划”能力。AgentServicepackage com.badao.ai.service; import com.badao.ai.config.AgentGraphConfig; import org.springframework.stereotype.Service; Service public class AgentService { private final AgentGraphConfig.AgentWorkflow workflow; public AgentService(AgentGraphConfig.AgentWorkflow workflow) { this.workflow workflow; } public String ask(String question) { return workflow.execute(question); } }RagControllerpackage com.badao.ai.controller; import com.badao.ai.service.AgentService; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api) public class RagController { private final AgentService agentService; public RagController(AgentService agentService) { this.agentService agentService; } PostMapping(/rag) public ChatResponse rag(RequestBody ChatRequest request) { String result agentService.ask(request.message()); return new ChatResponse(200, success, result); } public record ChatRequest(String message) {} public record ChatResponse(int code, String msg, String data) {} }测试验证启动应用后分别发送两个问题知识库内问题预期直接 RAG 回答知识库外问题预期自动调用天气工具日志中会清晰看到 检索到 0 篇相关文档 → 调用天气工具 的 Graph 节点转换过程。