Spring AI 实战从零构建企业级 AI 智能体应用含 RAG、Function Calling、多模态项目地址https://gitee.com/vivowushi/springai目录一、项目背景与目标1.1 项目简介1.2 学习路线图二、技术架构与选型2.1 技术栈2.2 系统架构三、核心功能模块详解3.1 项目结构3.2 Maven 依赖配置四、代码实现与最佳实践4.1 AI 配置类4.2 统一控制器设计4.3 会话管理服务五、RAG 知识库实战5.1 RAG 工作原理5.2 RAG 控制器实现5.3 知识库服务实现六、Function Calling 工具调用6.1 工具服务实现6.2 Function Calling 调用示例七、多模态能力实现7.1 文生图服务7.2 语音合成服务八、项目运行与测试8.1 环境要求8.2 配置文件8.3 启动项目8.4 接口测试九、总结与展望9.1 项目亮点9.2 技术难点与解决方案9.3 未来规划 学习资源 交流与反馈一、项目背景与目标1.1 项目简介本项目是《计算机科学与技术专业》实践课程的教学案例项目基于Spring AI AlibabaDashScopeOllama构建完整的 AI 智能体应用。项目涵盖了当前 AI 应用开发的核心技术栈大模型调用DashScope 云端 API Ollama 本地模型多轮对话会话管理、上下文记忆️Function Calling工具调用、智能决策RAG 知识库Milvus 向量数据库、文档检索多模态文生图、语音合成⚡流式响应SSE 实时输出1.2 学习路线图周次学习内容对应模块第1周Ollama 本地部署、Spring AI Alibaba 入门AiConfig.java第2周DeepSeek 聊天接口、Spring AI 核心 APIAssistantController.java第3周结构化输出、Prompt 模板、会话记忆ConversationService.java第4周Function Calling、天气查询、计算器ToolService.java第5周RAG 与 Milvus 入门、向量数据库RagController.java第6周企业级 RAG 知识库、AI 网站助手全项目整合二、技术架构与选型2.1 技术栈类别技术版本说明基础框架Spring Boot3.2.10企业级应用框架AI 框架Spring AI1.0.0Spring 官方 AI 开发框架云服务Spring AI Alibaba1.0.0.4阿里云 DashScope 集成本地模型Ollama-本地部署 DeepSeek/Qwen向量数据库Milvus2.4.4高性能向量检索编程语言Java21使用最新 LTS 版本构建工具Maven3.8依赖管理2.2 系统架构┌─────────────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Web 前端 │ │ 移动端 App │ │ 第三方系统 │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ └─────────┼─────────────────┼─────────────────┼───────────────┘ │ │ │ └─────────────────┼─────────────────┘ │ HTTP/SSE ┌───────────────────────────┼───────────────────────────────────┐ │ Spring Boot 后端 │ │ │ │ │ ┌───────────────────────┴───────────────────────────────┐ │ │ │ 控制器层 │ │ │ │ ┌────────────┐ ┌────────────┐ ┌──────────────────┐ │ │ │ │ │ Assistant │ │ RAG │ │ 其他... │ │ │ │ │ │ Controller │ │ Controller │ │ │ │ │ │ │ └─────┬──────┘ └─────┬──────┘ └──────────────────┘ │ │ │ └────────┼─────────────┼───────────────────────────────┘ │ │ │ │ │ │ ┌────────┴─────────────┴───────────────────────────────┐ │ │ │ 服务层 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ │ │ │ │ 对话服务 │ │ 图片服务 │ │ 语音服务 │ │工具服务 │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │ │ │ └───────────────────────┬───────────────────────────────┘ │ │ │ │ │ ┌───────────────────────┴───────────────────────────────┐ │ │ │ 数据访问层 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ │ │ Conversation │ │ Message │ │ Document │ │ │ │ │ │ Repository │ │ Repository │ │ Repository │ │ │ │ │ └──────────────┘ └──────────────┘ └─────────────┘ │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │ │ │ DashScope │ │ Ollama │ │ Milvus │ │ 文件存储 │ │ │ │ (云端API) │ │ (本地) │ │ (向量库) │ │ │ │ │ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │ └──────────────────────────────────────────────────────────────┘三、核心功能模块详解3.1 项目结构ai-demo/ ├── src/main/java/org/example/aidemo/ │ ├── AiDemoApplication.java # 启动类 │ ├── config/ │ │ └── AiConfig.java # AI 配置ChatClient、语音 │ ├── assistant/ │ │ └── AssistantController.java # AI 助手主控制器 │ ├── rag/ │ │ └── RagController.java # RAG 知识库控制器 │ ├── model/ # 数据模型 │ │ ├── ChatMessage.java │ │ ├── Conversation.java │ │ ├── CalculatorRequest.java │ │ ├── ImageRequest.java │ │ ├── KnowledgeDocument.java │ │ ├── SearchResult.java │ │ ├── SpeechRequest.java │ │ └── WeatherInfo.java │ └── service/ # 业务服务层 │ ├── ConversationService.java # 会话管理 │ ├── ImageService.java # 文生图 │ ├── SpeechService.java # 语音合成 │ ├── ToolService.java # 工具调用 │ ├── WebsiteAssistantService.java # 网站助手 │ └── KnowledgeBaseService.java # 知识库管理 └── src/main/resources/ └── application.yml # 配置文件3.2 Maven 依赖配置!-- pom.xml 核心依赖 -- dependencies !-- Spring Boot Web -- 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 version1.0.0/version /dependency !-- Spring AI Alibaba DashScope -- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId version1.0.0.4/version /dependency !-- Milvus 向量数据库 -- dependency groupIdio.milvus/groupId artifactIdmilvus-sdk-java/artifactId version2.4.4/version /dependency !-- Spring AI Milvus 集成 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-milvus/artifactId version1.0.0/version /dependency !-- Lombok 简化开发 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies四、代码实现与最佳实践4.1 AI 配置类Configuration public class AiConfig { /** * DashScope 聊天客户端云端 API * 支持 qwen-turbo、qwen-plus、qwen-max 等模型 */ Bean public ChatClient dashscopeChatClient(DashScopeChatModel dashScopeChatModel) { return ChatClient.builder(dashScopeChatModel).build(); } /** * Ollama 聊天客户端本地模型 * 支持 DeepSeek、Qwen2.5 等本地部署模型 */ Bean public ChatClient ollamaChatClient(OllamaChatModel ollamaChatModel) { return ChatClient.builder(ollamaChatModel).build(); } /** * 默认聊天客户端优先使用 DashScope */ Bean Primary public ChatClient defaultChatClient(DashScopeChatModel dashScopeChatModel) { return ChatClient.builder(dashScopeChatModel).build(); } /** * 语音合成服务 * 直接暴露自动配置的 DashScopeAudioSpeechModel */ Bean(dashScopeSpeechClient) public SpeechSynthesisModel dashScopeSpeechClient(DashScopeAudioSpeechModel speechModel) { return speechModel; } }4.2 统一控制器设计RestController RequestMapping(/api/assistant) public class AssistantController { private final WebsiteAssistantService websiteAssistantService; private final ConversationService conversationService; private final ImageService imageService; private final SpeechService speechService; private final ToolService toolService; private final ChatClient dashscopeChatClient; private final ChatClient ollamaChatClient; // 构造器注入推荐方式 public AssistantController( WebsiteAssistantService websiteAssistantService, ConversationService conversationService, ImageService imageService, SpeechService speechService, ToolService toolService, ChatClient dashscopeChatClient, ChatClient ollamaChatClient) { this.websiteAssistantService websiteAssistantService; // ... 其他注入 } // 基础聊天 /** * 基础聊天默认模型 */ PostMapping(/chat) public ResponseEntityMapString, String chat(RequestBody MapString, String request) { String message request.get(message); String response websiteAssistantService.chat(message); return ResponseEntity.ok(Map.of(response, response)); } /** * DashScope 模型聊天 */ PostMapping(/dashscope/chat) public ResponseEntityMapString, String dashscopeChat(RequestBody MapString, String request) { String message request.get(message); String systemPrompt request.getOrDefault(systemPrompt, 你是一个有用的AI助手。); String response dashscopeChatClient.prompt() .system(systemPrompt) .user(message) .call() .content(); return ResponseEntity.ok(Map.of(response, response)); } /** * Ollama 本地模型流式聊天SSE * 使用 Flux 实现服务端推送 */ PostMapping(/ollama/stream) public FluxString ollamaChatStream(RequestBody MapString, String request) { String message request.get(message); return ollamaChatClient.prompt() .user(message) .stream() .content(); } }4.3 会话管理服务Service public class ConversationService { // 内存存储会话生产环境建议使用数据库 private final MapString, Conversation conversations new ConcurrentHashMap(); /** * 创建新会话 */ public Conversation createConversation(String model) { String id UUID.randomUUID().toString(); Conversation conv new Conversation(); conv.setId(id); conv.setModel(model); conv.setMessages(new ArrayList()); conv.setCreatedAt(LocalDateTime.now()); conversations.put(id, conv); return conv; } /** * 多轮对话带历史上下文 */ public String multiRoundChat(String conversationId, String userMessage) { Conversation conv conversations.get(conversationId); if (conv null) { throw new RuntimeException(会话不存在); } // 添加用户消息 ChatMessage userMsg new ChatMessage(user, userMessage); conv.getMessages().add(userMsg); // 构建历史上下文 StringBuilder historyPrompt new StringBuilder(); for (ChatMessage msg : conv.getMessages()) { if (user.equals(msg.getRole())) { historyPrompt.append(用户: ).append(msg.getContent()).append(\n); } else { historyPrompt.append(助手: ).append(msg.getContent()).append(\n); } } // 调用 AI 获取回复 String response websiteAssistantService.chat(historyPrompt.toString()); // 保存助手回复 ChatMessage assistantMsg new ChatMessage(assistant, response); conv.getMessages().add(assistantMsg); return response; } }五、RAG 知识库实战5.1 RAG 工作原理┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 文档上传 │────▶│ 文本切分 │────▶│ 向量化 │ │ (PDF/Word) │ │ (Chunking) │ │ (Embedding) │ └─────────────┘ └─────────────┘ └──────┬──────┘ │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 用户提问 │────▶│ 向量检索 │────▶│ Milvus │ │ │ │ (Similarity)│ │ 向量数据库 │ └─────────────┘ └─────────────┘ └──────┬───────┘ │ ▼ ┌─────────────┐ │ 上下文组装 │ │ (Prompt) │ └──────┬──────┘ │ ▼ ┌─────────────┐ │ LLM 生成 │ │ (Answer) │ └─────────────┘5.2 RAG 控制器实现RestController RequestMapping(/api/rag) public class RagController { private final KnowledgeBaseService knowledgeBaseService; /** * 上传文本文档 */ PostMapping(/document) public ResponseEntityMapString, String uploadDocument(RequestBody KnowledgeDocument doc) { knowledgeBaseService.addDocument(doc.getTitle(), doc.getContent()); return ResponseEntity.ok(Map.of( message, 文档上传成功, title, doc.getTitle() )); } /** * 上传文件 */ PostMapping(/document/upload) public ResponseEntityMapString, String uploadFile(RequestParam(file) MultipartFile file) { try { String content new String(file.getBytes(), StandardCharsets.UTF_8); knowledgeBaseService.addDocument(file.getOriginalFilename(), content); return ResponseEntity.ok(Map.of( message, 文件上传成功, filename, file.getOriginalFilename() )); } catch (IOException e) { return ResponseEntity.badRequest().body(Map.of(error, e.getMessage())); } } /** * 知识搜索 */ GetMapping(/search) public ResponseEntityListSearchResult search(RequestParam String query) { ListSearchResult results knowledgeBaseService.search(query); return ResponseEntity.ok(results); } /** * 智能问答RAG */ PostMapping(/ask) public ResponseEntityMapString, Object ask(RequestBody MapString, String request) { String question request.get(question); MapString, Object answer knowledgeBaseService.ask(question); return ResponseEntity.ok(answer); } /** * 知识库统计 */ GetMapping(/stats) public ResponseEntityMapString, Object getStats() { MapString, Object stats knowledgeBaseService.getStats(); return ResponseEntity.ok(stats); } }5.3 知识库服务实现Service public class KnowledgeBaseService { private final VectorStore vectorStore; private final ChatClient defaultClient; /** * 添加文档到知识库 */ public void addDocument(String title, String content) { // 文本切分简单实现按段落分割 String[] chunks content.split(\n\n); for (String chunk : chunks) { if (chunk.trim().isEmpty()) continue; // 创建文档嵌入 Document document new Document(Map.of( title, title, content, chunk.trim() )); vectorStore.add(List.of(document)); } } /** * 知识搜索 */ public ListSearchResult search(String query) { ListDocument documents vectorStore.similaritySearch(query); return documents.stream() .map(doc - new SearchResult( doc.getId(), doc.getContent(), doc.getScore(), knowledge_base )) .toList(); } /** * RAG 智能问答 */ public MapString, Object ask(String question) { // 1. 检索相关文档 ListDocument relevantDocs vectorStore.similaritySearch(question); // 2. 构建上下文 StringBuilder context new StringBuilder(); for (Document doc : relevantDocs) { context.append(doc.getContent()).append(\n\n); } // 3. 构建 Prompt String prompt String.format( 基于以下知识库内容回答用户问题 知识库内容 %s 用户问题%s 请根据知识库内容准确回答如果知识库中没有相关信息请如实告知。 , context.toString(), question); // 4. 调用 LLM 生成回答 String answer defaultClient.prompt() .user(prompt) .call() .content(); // 5. 返回结果 ListString sources relevantDocs.stream() .map(Document::getContent) .toList(); return Map.of( answer, answer, sources, sources, success, true ); } }六、Function Calling 工具调用6.1 工具服务实现Service public class ToolService { private final ChatClient defaultClient; /** * 天气查询工具 */ public String queryWeather(String city) { // 模拟天气数据实际项目可接入和风天气、OpenWeather 等 API return String.format( 【天气查询结果】\n 城市: %s\n 天气: 多云转晴\n 温度: 23°C\n 湿度: 65%%\n 风力: 东北风3级, city ); } /** * 计算器工具 - 安全表达式计算 */ public String calculate(String expression) { try { // 安全校验只允许数字和运算符 if (!expression.matches([0-9\\-*/().\\s])) { return 错误表达式包含非法字符; } double result evaluateExpression(expression); return String.format(计算结果: %s %.4f, expression, result); } catch (Exception e) { return 计算错误: e.getMessage(); } } /** * 智能工具调用 - AI 自动判断调用哪个工具 */ public String smartToolCall(String userInput) { String systemPrompt 你是一个智能助手可以根据用户输入判断需要调用哪个工具。 可用工具 1. 天气查询 - 当用户询问天气时返回格式WEATHER:城市名 2. 计算器 - 当用户需要进行数学计算时返回格式CALCULATE:数学表达式 如果不需要调用工具直接回答用户问题。 只返回工具调用格式或直接回答不要有其他内容。 ; String response defaultClient.prompt() .system(systemPrompt) .user(userInput) .call() .content(); // 解析工具调用 if (response.startsWith(WEATHER:)) { String city response.substring(8).trim(); return queryWeather(city); } else if (response.startsWith(CALCULATE:)) { String expr response.substring(10).trim(); return calculate(expr); } return response; } /** * 简单表达式计算器实现 */ private double evaluateExpression(String expr) { expr expr.replaceAll(\\s, ); // 处理加减法 String[] parts expr.split((?[-])|(?[-])); double result 0; boolean isAddition true; for (String part : parts) { if (part.isEmpty()) continue; if (part.equals()) { isAddition true; continue; } if (part.equals(-)) { isAddition false; continue; } // 处理乘除 double value evaluateMulDiv(part); result isAddition ? result value : result - value; } return result; } private double evaluateMulDiv(String expr) { String[] parts expr.split((?[*/])|(?[*/])); double result Double.parseDouble(parts[0]); for (int i 1; i parts.length; i 2) { String op parts[i]; double val Double.parseDouble(parts[i 1]); result op.equals(*) ? result * val : result / val; } return result; } }6.2 Function Calling 调用示例// 使用 Spring AI 的 Function Calling 特性 Bean public ToolCallingChatClient toolCallingChatClient(ChatClient.Builder builder) { return builder .defaultTools(new WeatherFunction(), new CalculatorFunction()) .build(); } // 定义天气工具函数 public class WeatherFunction implements FunctionWeatherRequest, String { Override public String apply(WeatherRequest request) { return queryWeather(request.getCity()); } } // 定义计算器工具函数 public class CalculatorFunction implements FunctionCalculatorRequest, String { Override public String apply(CalculatorRequest request) { return calculate(request.getExpression()); } }七、多模态能力实现7.1 文生图服务Service public class ImageService { private final ChatClient dashscopeChatClient; /** * 文生图 */ public String generateImage(String prompt) { // 调用 DashScope 文生图 API ImageResponse response dashscopeChatClient.prompt() .user(生成图片 prompt) .call() .entity(ImageResponse.class); return response.getImageUrl(); } /** * 文生图优化提示词 * 先让 AI 优化提示词再生成图片 */ public String generateImageWithOptimization(String prompt) { // 1. AI 优化提示词 String enhancedPrompt dashscopeChatClient.prompt() .system(你是一个专业的 AI 绘画提示词工程师请优化用户的绘画描述使其更详细、更具艺术感。) .user(prompt) .call() .content(); // 2. 使用优化后的提示词生成图片 return generateImage(enhancedPrompt); } }7.2 语音合成服务Service public class SpeechService { Qualifier(dashScopeSpeechClient) private final SpeechSynthesisModel speechModel; /** * 文本转语音 */ public byte[] textToSpeech(String text, String voice, Double speed) { SpeechSynthesisRequest request SpeechSynthesisRequest.builder() .text(text) .voice(voice ! null ? voice : alloy) .speed(speed ! null ? speed : 1.0) .build(); SpeechSynthesisResponse response speechModel.call(request); return response.getAudioData(); } }八、项目运行与测试8.1 环境要求JDK 21Maven 3.8DashScope API Key阿里云灵积Ollama可选用于本地模型8.2 配置文件# src/main/resources/application.yml spring: application: name: ai-demo ai: # Ollama 本地模型配置 ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:3b temperature: 0.7 # DashScope 云端 API 配置 dashscope: api-key: sk-xxxxxxxxxxxxxxxx # 替换为你的 API Key chat: options: model: qwen-plus # 可选: qwen-turbo, qwen-plus, qwen-max temperature: 0.7 # Milvus 向量数据库配置 vectorstore: milvus: client: host: localhost port: 19530 database-name: ai_demo collection-name: knowledge_base embedding-dimension: 768 server: port: 80808.3 启动项目# 1. 克隆项目 git clone repository-url cd ai-demo # 2. 配置 API Key # 编辑 src/main/resources/application.yml填入 DashScope API Key # 3. 启动项目 ./mvnw spring-boot:run # 或使用 IDEA 直接运行 AiDemoApplication.java8.4 接口测试# 基础聊天 curl -X POST http://localhost:8080/api/assistant/chat \ -H Content-Type: application/json \ -d {message: 你好请介绍一下 Spring AI} # 文生图 curl -X POST http://localhost:8080/api/assistant/image/generate \ -H Content-Type: application/json \ -d {prompt: 一只可爱的猫咪在草地上玩耍} # 天气查询 curl http://localhost:8080/api/assistant/tools/weather?city南京 # 计算器 curl http://localhost:8080/api/assistant/tools/calculate?expression12*(34) # RAG 问答 curl -X POST http://localhost:8080/api/rag/ask \ -H Content-Type: application/json \ -d {question: Spring AI 是什么}九、总结与展望9.1 项目亮点多模型支持DashScope 云端 Ollama 本地灵活切换完整 AI 能力对话、文生图、语音、工具调用、RAG流式响应SSE 实现实时输出提升用户体验教学友好模块化设计对应教学实验内容企业级架构分层设计、依赖注入、配置外置9.2 技术难点与解决方案难点解决方案多模型切换使用Primary和Qualifier注解管理不同 ChatClient流式响应使用 Spring WebFlux 的FluxString返回 SSE向量数据库集成Spring AI 提供的VectorStore抽象层工具调用解析AI 返回结构化格式后端解析执行会话历史管理内存 Map 存储生产环境替换为数据库9.3 未来规划[ ] 接入真实天气 API和风天气、OpenWeather[ ] MySQL 持久化会话和知识库数据[ ] 前端页面开发Vue/React SSE 流式渲染[ ] 用户认证与权限控制Spring Security[ ] 更多工具扩展搜索、翻译、代码执行[ ] 微服务架构改造[ ] 监控与日志Micrometer Grafana 学习资源Spring AI 官方文档Introduction :: Spring AI ReferenceSpring AI Alibabahttps://github.com/alibaba/spring-ai-alibabaDashScope 开放平台大模型服务平台百炼 - 大模型应用构建 - 阿里云Milvus 文档https://milvus.io/docsOllama 官网https://ollama.com/ 交流与反馈如果你对这个项目有任何问题或建议欢迎在评论区留言交流如果觉得这篇文章对你有帮助别忘了点赞 和收藏 ⭐ 哦~项目地址https://gitee.com/vivowushi/springai
SpringAI构建智能体
Spring AI 实战从零构建企业级 AI 智能体应用含 RAG、Function Calling、多模态项目地址https://gitee.com/vivowushi/springai目录一、项目背景与目标1.1 项目简介1.2 学习路线图二、技术架构与选型2.1 技术栈2.2 系统架构三、核心功能模块详解3.1 项目结构3.2 Maven 依赖配置四、代码实现与最佳实践4.1 AI 配置类4.2 统一控制器设计4.3 会话管理服务五、RAG 知识库实战5.1 RAG 工作原理5.2 RAG 控制器实现5.3 知识库服务实现六、Function Calling 工具调用6.1 工具服务实现6.2 Function Calling 调用示例七、多模态能力实现7.1 文生图服务7.2 语音合成服务八、项目运行与测试8.1 环境要求8.2 配置文件8.3 启动项目8.4 接口测试九、总结与展望9.1 项目亮点9.2 技术难点与解决方案9.3 未来规划 学习资源 交流与反馈一、项目背景与目标1.1 项目简介本项目是《计算机科学与技术专业》实践课程的教学案例项目基于Spring AI AlibabaDashScopeOllama构建完整的 AI 智能体应用。项目涵盖了当前 AI 应用开发的核心技术栈大模型调用DashScope 云端 API Ollama 本地模型多轮对话会话管理、上下文记忆️Function Calling工具调用、智能决策RAG 知识库Milvus 向量数据库、文档检索多模态文生图、语音合成⚡流式响应SSE 实时输出1.2 学习路线图周次学习内容对应模块第1周Ollama 本地部署、Spring AI Alibaba 入门AiConfig.java第2周DeepSeek 聊天接口、Spring AI 核心 APIAssistantController.java第3周结构化输出、Prompt 模板、会话记忆ConversationService.java第4周Function Calling、天气查询、计算器ToolService.java第5周RAG 与 Milvus 入门、向量数据库RagController.java第6周企业级 RAG 知识库、AI 网站助手全项目整合二、技术架构与选型2.1 技术栈类别技术版本说明基础框架Spring Boot3.2.10企业级应用框架AI 框架Spring AI1.0.0Spring 官方 AI 开发框架云服务Spring AI Alibaba1.0.0.4阿里云 DashScope 集成本地模型Ollama-本地部署 DeepSeek/Qwen向量数据库Milvus2.4.4高性能向量检索编程语言Java21使用最新 LTS 版本构建工具Maven3.8依赖管理2.2 系统架构┌─────────────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Web 前端 │ │ 移动端 App │ │ 第三方系统 │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ └─────────┼─────────────────┼─────────────────┼───────────────┘ │ │ │ └─────────────────┼─────────────────┘ │ HTTP/SSE ┌───────────────────────────┼───────────────────────────────────┐ │ Spring Boot 后端 │ │ │ │ │ ┌───────────────────────┴───────────────────────────────┐ │ │ │ 控制器层 │ │ │ │ ┌────────────┐ ┌────────────┐ ┌──────────────────┐ │ │ │ │ │ Assistant │ │ RAG │ │ 其他... │ │ │ │ │ │ Controller │ │ Controller │ │ │ │ │ │ │ └─────┬──────┘ └─────┬──────┘ └──────────────────┘ │ │ │ └────────┼─────────────┼───────────────────────────────┘ │ │ │ │ │ │ ┌────────┴─────────────┴───────────────────────────────┐ │ │ │ 服务层 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ │ │ │ │ 对话服务 │ │ 图片服务 │ │ 语音服务 │ │工具服务 │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └─────────┘ │ │ │ └───────────────────────┬───────────────────────────────┘ │ │ │ │ │ ┌───────────────────────┴───────────────────────────────┐ │ │ │ 数据访问层 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ │ │ Conversation │ │ Message │ │ Document │ │ │ │ │ │ Repository │ │ Repository │ │ Repository │ │ │ │ │ └──────────────┘ └──────────────┘ └─────────────┘ │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │ │ │ DashScope │ │ Ollama │ │ Milvus │ │ 文件存储 │ │ │ │ (云端API) │ │ (本地) │ │ (向量库) │ │ │ │ │ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │ └──────────────────────────────────────────────────────────────┘三、核心功能模块详解3.1 项目结构ai-demo/ ├── src/main/java/org/example/aidemo/ │ ├── AiDemoApplication.java # 启动类 │ ├── config/ │ │ └── AiConfig.java # AI 配置ChatClient、语音 │ ├── assistant/ │ │ └── AssistantController.java # AI 助手主控制器 │ ├── rag/ │ │ └── RagController.java # RAG 知识库控制器 │ ├── model/ # 数据模型 │ │ ├── ChatMessage.java │ │ ├── Conversation.java │ │ ├── CalculatorRequest.java │ │ ├── ImageRequest.java │ │ ├── KnowledgeDocument.java │ │ ├── SearchResult.java │ │ ├── SpeechRequest.java │ │ └── WeatherInfo.java │ └── service/ # 业务服务层 │ ├── ConversationService.java # 会话管理 │ ├── ImageService.java # 文生图 │ ├── SpeechService.java # 语音合成 │ ├── ToolService.java # 工具调用 │ ├── WebsiteAssistantService.java # 网站助手 │ └── KnowledgeBaseService.java # 知识库管理 └── src/main/resources/ └── application.yml # 配置文件3.2 Maven 依赖配置!-- pom.xml 核心依赖 -- dependencies !-- Spring Boot Web -- 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 version1.0.0/version /dependency !-- Spring AI Alibaba DashScope -- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter-dashscope/artifactId version1.0.0.4/version /dependency !-- Milvus 向量数据库 -- dependency groupIdio.milvus/groupId artifactIdmilvus-sdk-java/artifactId version2.4.4/version /dependency !-- Spring AI Milvus 集成 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-milvus/artifactId version1.0.0/version /dependency !-- Lombok 简化开发 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies四、代码实现与最佳实践4.1 AI 配置类Configuration public class AiConfig { /** * DashScope 聊天客户端云端 API * 支持 qwen-turbo、qwen-plus、qwen-max 等模型 */ Bean public ChatClient dashscopeChatClient(DashScopeChatModel dashScopeChatModel) { return ChatClient.builder(dashScopeChatModel).build(); } /** * Ollama 聊天客户端本地模型 * 支持 DeepSeek、Qwen2.5 等本地部署模型 */ Bean public ChatClient ollamaChatClient(OllamaChatModel ollamaChatModel) { return ChatClient.builder(ollamaChatModel).build(); } /** * 默认聊天客户端优先使用 DashScope */ Bean Primary public ChatClient defaultChatClient(DashScopeChatModel dashScopeChatModel) { return ChatClient.builder(dashScopeChatModel).build(); } /** * 语音合成服务 * 直接暴露自动配置的 DashScopeAudioSpeechModel */ Bean(dashScopeSpeechClient) public SpeechSynthesisModel dashScopeSpeechClient(DashScopeAudioSpeechModel speechModel) { return speechModel; } }4.2 统一控制器设计RestController RequestMapping(/api/assistant) public class AssistantController { private final WebsiteAssistantService websiteAssistantService; private final ConversationService conversationService; private final ImageService imageService; private final SpeechService speechService; private final ToolService toolService; private final ChatClient dashscopeChatClient; private final ChatClient ollamaChatClient; // 构造器注入推荐方式 public AssistantController( WebsiteAssistantService websiteAssistantService, ConversationService conversationService, ImageService imageService, SpeechService speechService, ToolService toolService, ChatClient dashscopeChatClient, ChatClient ollamaChatClient) { this.websiteAssistantService websiteAssistantService; // ... 其他注入 } // 基础聊天 /** * 基础聊天默认模型 */ PostMapping(/chat) public ResponseEntityMapString, String chat(RequestBody MapString, String request) { String message request.get(message); String response websiteAssistantService.chat(message); return ResponseEntity.ok(Map.of(response, response)); } /** * DashScope 模型聊天 */ PostMapping(/dashscope/chat) public ResponseEntityMapString, String dashscopeChat(RequestBody MapString, String request) { String message request.get(message); String systemPrompt request.getOrDefault(systemPrompt, 你是一个有用的AI助手。); String response dashscopeChatClient.prompt() .system(systemPrompt) .user(message) .call() .content(); return ResponseEntity.ok(Map.of(response, response)); } /** * Ollama 本地模型流式聊天SSE * 使用 Flux 实现服务端推送 */ PostMapping(/ollama/stream) public FluxString ollamaChatStream(RequestBody MapString, String request) { String message request.get(message); return ollamaChatClient.prompt() .user(message) .stream() .content(); } }4.3 会话管理服务Service public class ConversationService { // 内存存储会话生产环境建议使用数据库 private final MapString, Conversation conversations new ConcurrentHashMap(); /** * 创建新会话 */ public Conversation createConversation(String model) { String id UUID.randomUUID().toString(); Conversation conv new Conversation(); conv.setId(id); conv.setModel(model); conv.setMessages(new ArrayList()); conv.setCreatedAt(LocalDateTime.now()); conversations.put(id, conv); return conv; } /** * 多轮对话带历史上下文 */ public String multiRoundChat(String conversationId, String userMessage) { Conversation conv conversations.get(conversationId); if (conv null) { throw new RuntimeException(会话不存在); } // 添加用户消息 ChatMessage userMsg new ChatMessage(user, userMessage); conv.getMessages().add(userMsg); // 构建历史上下文 StringBuilder historyPrompt new StringBuilder(); for (ChatMessage msg : conv.getMessages()) { if (user.equals(msg.getRole())) { historyPrompt.append(用户: ).append(msg.getContent()).append(\n); } else { historyPrompt.append(助手: ).append(msg.getContent()).append(\n); } } // 调用 AI 获取回复 String response websiteAssistantService.chat(historyPrompt.toString()); // 保存助手回复 ChatMessage assistantMsg new ChatMessage(assistant, response); conv.getMessages().add(assistantMsg); return response; } }五、RAG 知识库实战5.1 RAG 工作原理┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 文档上传 │────▶│ 文本切分 │────▶│ 向量化 │ │ (PDF/Word) │ │ (Chunking) │ │ (Embedding) │ └─────────────┘ └─────────────┘ └──────┬──────┘ │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 用户提问 │────▶│ 向量检索 │────▶│ Milvus │ │ │ │ (Similarity)│ │ 向量数据库 │ └─────────────┘ └─────────────┘ └──────┬───────┘ │ ▼ ┌─────────────┐ │ 上下文组装 │ │ (Prompt) │ └──────┬──────┘ │ ▼ ┌─────────────┐ │ LLM 生成 │ │ (Answer) │ └─────────────┘5.2 RAG 控制器实现RestController RequestMapping(/api/rag) public class RagController { private final KnowledgeBaseService knowledgeBaseService; /** * 上传文本文档 */ PostMapping(/document) public ResponseEntityMapString, String uploadDocument(RequestBody KnowledgeDocument doc) { knowledgeBaseService.addDocument(doc.getTitle(), doc.getContent()); return ResponseEntity.ok(Map.of( message, 文档上传成功, title, doc.getTitle() )); } /** * 上传文件 */ PostMapping(/document/upload) public ResponseEntityMapString, String uploadFile(RequestParam(file) MultipartFile file) { try { String content new String(file.getBytes(), StandardCharsets.UTF_8); knowledgeBaseService.addDocument(file.getOriginalFilename(), content); return ResponseEntity.ok(Map.of( message, 文件上传成功, filename, file.getOriginalFilename() )); } catch (IOException e) { return ResponseEntity.badRequest().body(Map.of(error, e.getMessage())); } } /** * 知识搜索 */ GetMapping(/search) public ResponseEntityListSearchResult search(RequestParam String query) { ListSearchResult results knowledgeBaseService.search(query); return ResponseEntity.ok(results); } /** * 智能问答RAG */ PostMapping(/ask) public ResponseEntityMapString, Object ask(RequestBody MapString, String request) { String question request.get(question); MapString, Object answer knowledgeBaseService.ask(question); return ResponseEntity.ok(answer); } /** * 知识库统计 */ GetMapping(/stats) public ResponseEntityMapString, Object getStats() { MapString, Object stats knowledgeBaseService.getStats(); return ResponseEntity.ok(stats); } }5.3 知识库服务实现Service public class KnowledgeBaseService { private final VectorStore vectorStore; private final ChatClient defaultClient; /** * 添加文档到知识库 */ public void addDocument(String title, String content) { // 文本切分简单实现按段落分割 String[] chunks content.split(\n\n); for (String chunk : chunks) { if (chunk.trim().isEmpty()) continue; // 创建文档嵌入 Document document new Document(Map.of( title, title, content, chunk.trim() )); vectorStore.add(List.of(document)); } } /** * 知识搜索 */ public ListSearchResult search(String query) { ListDocument documents vectorStore.similaritySearch(query); return documents.stream() .map(doc - new SearchResult( doc.getId(), doc.getContent(), doc.getScore(), knowledge_base )) .toList(); } /** * RAG 智能问答 */ public MapString, Object ask(String question) { // 1. 检索相关文档 ListDocument relevantDocs vectorStore.similaritySearch(question); // 2. 构建上下文 StringBuilder context new StringBuilder(); for (Document doc : relevantDocs) { context.append(doc.getContent()).append(\n\n); } // 3. 构建 Prompt String prompt String.format( 基于以下知识库内容回答用户问题 知识库内容 %s 用户问题%s 请根据知识库内容准确回答如果知识库中没有相关信息请如实告知。 , context.toString(), question); // 4. 调用 LLM 生成回答 String answer defaultClient.prompt() .user(prompt) .call() .content(); // 5. 返回结果 ListString sources relevantDocs.stream() .map(Document::getContent) .toList(); return Map.of( answer, answer, sources, sources, success, true ); } }六、Function Calling 工具调用6.1 工具服务实现Service public class ToolService { private final ChatClient defaultClient; /** * 天气查询工具 */ public String queryWeather(String city) { // 模拟天气数据实际项目可接入和风天气、OpenWeather 等 API return String.format( 【天气查询结果】\n 城市: %s\n 天气: 多云转晴\n 温度: 23°C\n 湿度: 65%%\n 风力: 东北风3级, city ); } /** * 计算器工具 - 安全表达式计算 */ public String calculate(String expression) { try { // 安全校验只允许数字和运算符 if (!expression.matches([0-9\\-*/().\\s])) { return 错误表达式包含非法字符; } double result evaluateExpression(expression); return String.format(计算结果: %s %.4f, expression, result); } catch (Exception e) { return 计算错误: e.getMessage(); } } /** * 智能工具调用 - AI 自动判断调用哪个工具 */ public String smartToolCall(String userInput) { String systemPrompt 你是一个智能助手可以根据用户输入判断需要调用哪个工具。 可用工具 1. 天气查询 - 当用户询问天气时返回格式WEATHER:城市名 2. 计算器 - 当用户需要进行数学计算时返回格式CALCULATE:数学表达式 如果不需要调用工具直接回答用户问题。 只返回工具调用格式或直接回答不要有其他内容。 ; String response defaultClient.prompt() .system(systemPrompt) .user(userInput) .call() .content(); // 解析工具调用 if (response.startsWith(WEATHER:)) { String city response.substring(8).trim(); return queryWeather(city); } else if (response.startsWith(CALCULATE:)) { String expr response.substring(10).trim(); return calculate(expr); } return response; } /** * 简单表达式计算器实现 */ private double evaluateExpression(String expr) { expr expr.replaceAll(\\s, ); // 处理加减法 String[] parts expr.split((?[-])|(?[-])); double result 0; boolean isAddition true; for (String part : parts) { if (part.isEmpty()) continue; if (part.equals()) { isAddition true; continue; } if (part.equals(-)) { isAddition false; continue; } // 处理乘除 double value evaluateMulDiv(part); result isAddition ? result value : result - value; } return result; } private double evaluateMulDiv(String expr) { String[] parts expr.split((?[*/])|(?[*/])); double result Double.parseDouble(parts[0]); for (int i 1; i parts.length; i 2) { String op parts[i]; double val Double.parseDouble(parts[i 1]); result op.equals(*) ? result * val : result / val; } return result; } }6.2 Function Calling 调用示例// 使用 Spring AI 的 Function Calling 特性 Bean public ToolCallingChatClient toolCallingChatClient(ChatClient.Builder builder) { return builder .defaultTools(new WeatherFunction(), new CalculatorFunction()) .build(); } // 定义天气工具函数 public class WeatherFunction implements FunctionWeatherRequest, String { Override public String apply(WeatherRequest request) { return queryWeather(request.getCity()); } } // 定义计算器工具函数 public class CalculatorFunction implements FunctionCalculatorRequest, String { Override public String apply(CalculatorRequest request) { return calculate(request.getExpression()); } }七、多模态能力实现7.1 文生图服务Service public class ImageService { private final ChatClient dashscopeChatClient; /** * 文生图 */ public String generateImage(String prompt) { // 调用 DashScope 文生图 API ImageResponse response dashscopeChatClient.prompt() .user(生成图片 prompt) .call() .entity(ImageResponse.class); return response.getImageUrl(); } /** * 文生图优化提示词 * 先让 AI 优化提示词再生成图片 */ public String generateImageWithOptimization(String prompt) { // 1. AI 优化提示词 String enhancedPrompt dashscopeChatClient.prompt() .system(你是一个专业的 AI 绘画提示词工程师请优化用户的绘画描述使其更详细、更具艺术感。) .user(prompt) .call() .content(); // 2. 使用优化后的提示词生成图片 return generateImage(enhancedPrompt); } }7.2 语音合成服务Service public class SpeechService { Qualifier(dashScopeSpeechClient) private final SpeechSynthesisModel speechModel; /** * 文本转语音 */ public byte[] textToSpeech(String text, String voice, Double speed) { SpeechSynthesisRequest request SpeechSynthesisRequest.builder() .text(text) .voice(voice ! null ? voice : alloy) .speed(speed ! null ? speed : 1.0) .build(); SpeechSynthesisResponse response speechModel.call(request); return response.getAudioData(); } }八、项目运行与测试8.1 环境要求JDK 21Maven 3.8DashScope API Key阿里云灵积Ollama可选用于本地模型8.2 配置文件# src/main/resources/application.yml spring: application: name: ai-demo ai: # Ollama 本地模型配置 ollama: base-url: http://localhost:11434 chat: options: model: qwen2.5:3b temperature: 0.7 # DashScope 云端 API 配置 dashscope: api-key: sk-xxxxxxxxxxxxxxxx # 替换为你的 API Key chat: options: model: qwen-plus # 可选: qwen-turbo, qwen-plus, qwen-max temperature: 0.7 # Milvus 向量数据库配置 vectorstore: milvus: client: host: localhost port: 19530 database-name: ai_demo collection-name: knowledge_base embedding-dimension: 768 server: port: 80808.3 启动项目# 1. 克隆项目 git clone repository-url cd ai-demo # 2. 配置 API Key # 编辑 src/main/resources/application.yml填入 DashScope API Key # 3. 启动项目 ./mvnw spring-boot:run # 或使用 IDEA 直接运行 AiDemoApplication.java8.4 接口测试# 基础聊天 curl -X POST http://localhost:8080/api/assistant/chat \ -H Content-Type: application/json \ -d {message: 你好请介绍一下 Spring AI} # 文生图 curl -X POST http://localhost:8080/api/assistant/image/generate \ -H Content-Type: application/json \ -d {prompt: 一只可爱的猫咪在草地上玩耍} # 天气查询 curl http://localhost:8080/api/assistant/tools/weather?city南京 # 计算器 curl http://localhost:8080/api/assistant/tools/calculate?expression12*(34) # RAG 问答 curl -X POST http://localhost:8080/api/rag/ask \ -H Content-Type: application/json \ -d {question: Spring AI 是什么}九、总结与展望9.1 项目亮点多模型支持DashScope 云端 Ollama 本地灵活切换完整 AI 能力对话、文生图、语音、工具调用、RAG流式响应SSE 实现实时输出提升用户体验教学友好模块化设计对应教学实验内容企业级架构分层设计、依赖注入、配置外置9.2 技术难点与解决方案难点解决方案多模型切换使用Primary和Qualifier注解管理不同 ChatClient流式响应使用 Spring WebFlux 的FluxString返回 SSE向量数据库集成Spring AI 提供的VectorStore抽象层工具调用解析AI 返回结构化格式后端解析执行会话历史管理内存 Map 存储生产环境替换为数据库9.3 未来规划[ ] 接入真实天气 API和风天气、OpenWeather[ ] MySQL 持久化会话和知识库数据[ ] 前端页面开发Vue/React SSE 流式渲染[ ] 用户认证与权限控制Spring Security[ ] 更多工具扩展搜索、翻译、代码执行[ ] 微服务架构改造[ ] 监控与日志Micrometer Grafana 学习资源Spring AI 官方文档Introduction :: Spring AI ReferenceSpring AI Alibabahttps://github.com/alibaba/spring-ai-alibabaDashScope 开放平台大模型服务平台百炼 - 大模型应用构建 - 阿里云Milvus 文档https://milvus.io/docsOllama 官网https://ollama.com/ 交流与反馈如果你对这个项目有任何问题或建议欢迎在评论区留言交流如果觉得这篇文章对你有帮助别忘了点赞 和收藏 ⭐ 哦~项目地址https://gitee.com/vivowushi/springai