
最近在尝试将大模型能力集成到 Spring Boot 项目中时发现虽然 OpenAI 的 API 很强大但成本、网络和合规性常常成为拦路虎。与此同时国产大模型如 DeepSeek 的崛起以其出色的性能和极具竞争力的价格为开发者提供了新的选择。如何快速、优雅地在 Spring 生态中集成这些 AI 能力并构建起检索增强生成RAG等高级应用是很多后端开发者面临的共同挑战。本文将围绕SpringAI这一官方项目手把手带你从零搭建一个完整的大模型应用开发环境。我们将以DeepSeek作为核心模型贯穿ChatModel对话、Embedding向量化、RAG知识库问答三大核心场景提供从环境配置、代码编写到生产级最佳实践的完整闭环教程。无论你是想为现有系统添加智能对话功能还是希望构建一个基于私有知识库的问答助手这篇文章都能为你提供可直接复用的解决方案。1. SpringAI 与 DeepSeek强强联合的技术栈在开始动手之前我们有必要理清几个核心概念理解为什么选择这个技术组合。1.1 什么是 SpringAISpringAI 是 Spring 官方推出的一个项目旨在为 Spring 应用程序集成人工智能功能提供一套简洁、一致的抽象 API。它的核心价值在于抽象与统一它定义了一套标准的接口如ChatClient、EmbeddingClient让开发者无需关心底层具体是 OpenAI、Azure OpenAI、DeepSeek 还是其他任何兼容 OpenAI API 的模型服务。只需更换配置就能切换模型提供商。Spring 生态无缝集成与 Spring Boot 的自动配置、依赖注入、外部化配置application.yml完美融合开发体验非常“Spring”。功能全面不仅支持基础的聊天补全Chat Completion还支持文本嵌入Embedding、图像生成、语音转录等并内置了对 RAG、函数调用等高级模式的支持。活跃的社区与迭代作为 Spring 官方项目其版本迭代迅速能及时跟进 AI 领域的最新进展。简单说SpringAI 就像 JDBC 之于数据库它为我们操作各种大模型提供了一个统一、便捷的编程界面。1.2 为什么选择 DeepSeek在众多大模型中DeepSeek 是一个特别值得关注的选项尤其对于国内开发者卓越的性能DeepSeek 的最新模型如 V3、V4 Flash在多项中英文基准测试中表现优异推理、代码、数学能力突出完全具备生产级应用的能力。极致的成本优势其 API 定价远低于国际主流厂商例如DeepSeek-V3 的输入价格仅为 GPT-4 Turbo 的约 1/30这使得大规模应用和频繁调用成为可能。对国内开发者友好无需处理复杂的网络问题访问稳定响应速度快。兼容 OpenAI APIDeepSeek 提供了与 OpenAI 完全兼容的 API 接口这意味着所有基于 OpenAI SDK 或 SpringAI底层也是 OpenAI 协议开发的代码几乎可以无缝迁移到 DeepSeek。1.3 核心概念ChatModel, Embedding 与 RAGChatModel指能够进行多轮对话、理解上下文的大型语言模型。在 SpringAI 中通过ChatClient与之交互完成问答、创作、分析等任务。Embedding指将文本、图像等数据转化为高维向量一组数字的技术。这个向量包含了数据的语义信息。语义相近的文本其向量在空间中的距离也更近。这是实现语义搜索、文本分类、RAG 的基石。RAG (Retrieval-Augmented Generation)检索增强生成。这是一种解决大模型“幻觉”编造信息和知识滞后问题的架构。其核心流程是索引将私有知识库如 PDF、Word、公司文档通过 Embedding 模型转化为向量并存入向量数据库如 Pinecone、Chroma、Milvus。检索当用户提问时将问题也转化为向量并在向量数据库中搜索与之最相关的知识片段。增强将检索到的相关片段作为上下文与用户问题一起提交给 ChatModel。生成ChatModel 基于提供的上下文生成更准确、可靠的答案。接下来我们将进入实战环节一步步搭建起这个技术栈。2. 环境准备与项目初始化2.1 基础环境要求JDK: 17 或更高版本推荐 17、21 LTS。构建工具: Maven 3.6 或 Gradle 7.x。本文使用 Maven 示例。IDE: IntelliJ IDEA, VS Code, Eclipse 等均可。DeepSeek API Key: 前往 DeepSeek 平台注册账号并创建 API Key。2.2 创建 Spring Boot 项目使用 Spring Initializr 或 IDE 内置工具创建项目。Project: MavenLanguage: JavaSpring Boot: 3.2.x (SpringAI 需要 Boot 3.x)Dependencies:Spring Web(用于构建 Web 接口)Lombok(简化代码可选但推荐)Spring AI(核心依赖)生成的pom.xml中已经包含了spring-boot-starter-parent。我们需要手动添加 SpringAI 的 BOM物料清单和具体模块的依赖。2.3 配置 Maven 依赖与仓库SpringAI 的版本号由独立的 BOM 管理。更新你的pom.xml文件?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version !-- 使用稳定的 3.2.x 版本 -- relativePath/ /parent groupIdcom.example/groupId artifactIdspring-ai-deepseek-demo/artifactId version0.0.1-SNAPSHOT/version namespring-ai-deepseek-demo/name descriptionDemo project for Spring AI with DeepSeek/description properties java.version17/java.version !-- 定义 Spring AI 版本 -- spring-ai.version1.0.0-M3/version !-- 请检查官网使用最新稳定版 -- /properties dependencyManagement dependencies !-- 引入 Spring AI BOM 统一管理所有 AI 模块版本 -- 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 dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency !-- Spring AI OpenAI 模块 (兼容 DeepSeek API) -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency !-- 后续 RAG 需要向量数据库和文件解析可先引入 -- !-- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pgvector-store-spring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tika-document-reader/artifactId /dependency -- /dependencies build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes /configuration /plugin /plugins /build /project关键点说明dependencyManagement中引入spring-ai-bom这是管理所有 SpringAI 模块版本的最佳实践。我们依赖spring-ai-openai-spring-boot-starter。因为 DeepSeek 兼容 OpenAI API所以使用这个 starter 即可。向量数据库和文档读取的依赖已被注释我们会在 RAG 章节引入。3. 基础配置与 ChatModel 初体验3.1 配置 DeepSeek API在src/main/resources/application.yml中配置 DeepSeekspring: application: name: spring-ai-deepseek-demo # Spring AI 配置 spring: ai: openai: # DeepSeek 的 API 基础地址 base-url: https://api.deepseek.com # 在 DeepSeek 平台获取的 API Key api-key: ${DEEPSEEK_API_KEY:your-deepseek-api-key-here} # 推荐使用环境变量 # 指定使用的模型例如 deepseek-chat, deepseek-coder 等请查阅 DeepSeek 最新文档 chat: options: model: deepseek-chat # 嵌入模型配置为后续 Embedding 做准备 embedding: options: model: text-embedding-3-small # DeepSeek 可能使用兼容 OpenAI 的嵌入模型名或自有模型需确认安全提醒永远不要将真实的 API Key 硬编码在代码或配置文件中提交到版本控制系统如 Git。上述配置中的${DEEPSEEK_API_KEY}表示从环境变量中读取。你可以在启动应用前设置环境变量或使用 IDE 的运行配置注入生产环境则使用配置中心或 Secrets 管理工具。3.2 创建第一个 Chat 对话服务让我们创建一个简单的 Service 来调用 DeepSeek 进行对话。// 文件路径src/main/java/com/example/demo/service/ChatService.java package com.example.demo.service; import lombok.RequiredArgsConstructor; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; Service RequiredArgsConstructor public class ChatService { private final ChatClient chatClient; /** * 同步调用获取完整的回复 */ public String chatSync(String message) { return chatClient.prompt() .user(message) .call() .content(); } /** * 流式调用适用于需要逐字显示的场景如聊天界面 */ public FluxString chatStream(String message) { return chatClient.prompt() .user(new UserMessage(message)) .stream() .map(response - response.getResult() ! null ? response.getResult().getOutput().getContent() : ); } /** * 带系统指令的对话可以设定 AI 的角色和行为 */ public String chatWithSystem(String systemInstruction, String userMessage) { return chatClient.prompt() .system(s - s.text(systemInstruction)) // 设置系统指令 .user(userMessage) .call() .content(); } }3.3 创建 REST 控制器暴露接口// 文件路径src/main/java/com/example/demo/controller/ChatController.java package com.example.demo.controller; import com.example.demo.service.ChatService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; RestController RequestMapping(/api/chat) RequiredArgsConstructor public class ChatController { private final ChatService chatService; PostMapping(/sync) public String chatSync(RequestBody ChatRequest request) { return chatService.chatSync(request.getMessage()); } PostMapping(value /stream, produces text/event-stream) public FluxString chatStream(RequestBody ChatRequest request) { return chatService.chatStream(request.getMessage()); } PostMapping(/with-role) public String chatWithRole(RequestBody RoleChatRequest request) { return chatService.chatWithSystem(request.getSystemInstruction(), request.getUserMessage()); } // 简单的请求体 public record ChatRequest(String message) {} public record RoleChatRequest(String systemInstruction, String userMessage) {} }3.4 运行与测试启动 Spring Boot 应用。使用curl、Postman 或任何 HTTP 客户端进行测试。测试同步接口curl -X POST http://localhost:8080/api/chat/sync \ -H Content-Type: application/json \ -d {message: 请用Java写一个Hello World程序}测试流式接口观察逐字输出效果curl -X POST http://localhost:8080/api/chat/stream \ -H Content-Type: application/json \ -d {message: 简要介绍Spring框架的核心特性} \ -N至此你已经成功在 Spring Boot 中集成了 DeepSeek 的 Chat 能力。接下来我们探索更强大的 Embedding 功能。4. 深入 Embedding文本向量化实战Embedding 是将文本转化为数值向量的过程是构建语义搜索、智能推荐和 RAG 系统的核心。4.1 Embedding 客户端配置在application.yml中我们已经配置了spring.ai.openai.embedding.options.model。SpringAI 会自动配置一个EmbeddingClientBean。4.2 创建 Embedding 服务// 文件路径src/main/java/com/example/demo/service/EmbeddingService.java package com.example.demo.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingClient; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.stereotype.Service; import java.util.List; Service Slf4j RequiredArgsConstructor public class EmbeddingService { private final EmbeddingClient embeddingClient; /** * 为单个文本生成嵌入向量 */ public ListDouble embedText(String text) { EmbeddingResponse response embeddingClient.embedForResponse(List.of(text)); // 通常返回一个 List 的 List第一个元素就是第一个文本的向量 return response.getResults().get(0).getOutput(); } /** * 为多个文本批量生成嵌入向量更高效 */ public ListListDouble embedTexts(ListString texts) { EmbeddingResponse response embeddingClient.embedForResponse(texts); return response.getResults().stream() .map(embedding - embedding.getOutput()) .toList(); } /** * 计算两个文本的余弦相似度0~1越接近1越相似 */ public double calculateSimilarity(String text1, String text2) { ListDouble vector1 embedText(text1); ListDouble vector2 embedText(text2); return cosineSimilarity(vector1, vector2); } /** * 余弦相似度计算工具方法 */ private double cosineSimilarity(ListDouble vectorA, ListDouble vectorB) { if (vectorA.size() ! vectorB.size()) { throw new IllegalArgumentException(Vectors must have the same dimension); } double dotProduct 0.0; double normA 0.0; double normB 0.0; for (int i 0; i vectorA.size(); i) { dotProduct vectorA.get(i) * vectorB.get(i); normA Math.pow(vectorA.get(i), 2); normB Math.pow(vectorB.get(i), 2); } if (normA 0 || normB 0) { return 0.0; } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); } /** * 为 Spring AI Document 对象生成嵌入向量为 RAG 准备 */ public void embedDocument(Document document) { EmbeddingResponse response embeddingClient.embedForResponse(List.of(document.getContent())); if (!response.getResults().isEmpty()) { document.setEmbedding(response.getResults().get(0).getOutput()); } } }4.3 测试 Embedding 功能可以创建一个简单的测试 Controller 或单元测试来验证。// 文件路径src/test/java/com/example/demo/service/EmbeddingServiceTest.java package com.example.demo.service; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; SpringBootTest class EmbeddingServiceTest { Autowired private EmbeddingService embeddingService; Test void testEmbedText() { String text Spring Framework provides comprehensive infrastructure support for developing Java applications.; ListDouble embedding embeddingService.embedText(text); assertThat(embedding).isNotEmpty(); assertThat(embedding.size()).isGreaterThan(100); // 向量维度通常很高如1536 System.out.println(向量维度: embedding.size()); System.out.println(前5个值: embedding.subList(0, 5)); } Test void testSimilarity() { String text1 机器学习是人工智能的一个分支。; String text2 深度学习是机器学习的一个子领域。; String text3 今天天气真好适合去公园散步。; double sim12 embeddingService.calculateSimilarity(text1, text2); double sim13 embeddingService.calculateSimilarity(text1, text3); System.out.println(相似文本相似度: sim12); // 预期较高如 0.7 System.out.println(不相关文本相似度: sim13); // 预期较低如 0.2- assertThat(sim12).isGreaterThan(sim13); } }运行测试你会看到文本被成功转换为高维向量并且语义相近的文本其向量相似度更高。这为接下来的 RAG 打下了基础——我们需要用同样的模型将知识库和问题都转化为向量然后在向量空间中找到最匹配的知识。5. 构建 RAG 知识库问答系统这是最激动人心的部分。我们将构建一个完整的 RAG 系统让模型能够基于我们提供的私有文档回答问题。5.1 引入向量数据库与文档读取依赖修改pom.xml取消注释并添加以下依赖。这里我们使用PgVector基于 PostgreSQL作为向量数据库因为它功能强大且与 SpringAI 集成好。你也可以选择 Chroma、Milvus 等。!-- 在 dependencies 部分添加 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pgvector-store-spring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-tika-document-reader/artifactId /dependency dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId scoperuntime/scope /dependency5.2 配置 PostgreSQL 与 PgVector安装 PostgreSQL确保本地或远程有一个 PostgreSQL 数据库版本 14。安装 PgVector 扩展在数据库中执行CREATE EXTENSION IF NOT EXISTS vector;。配置连接更新application.yml。# 追加到 application.yml spring: datasource: url: jdbc:postgresql://localhost:5432/rag_demo # 你的数据库 username: postgres password: yourpassword driver-class-name: org.postgresql.Driver sql: init: mode: always # 启动时初始化表结构仅用于演示生产环境慎用 # Spring AI Vector Store 配置 spring: ai: vectorstore: pgvector: # 向量维度必须与 Embedding 模型输出维度一致DeepSeek/OpenAI text-embedding-3-small 是 1536 dimensions: 1536 # 向量相似度计算方式cosine 是常用且效果好的 distance-type: cosine-distance # 初始化时删除并重建表开发环境方便生产环境不要用 initialize-schema: true5.3 核心组件文档加载、向量化与存储SpringAI 提供了VectorStore抽象和Document对象极大简化了流程。// 文件路径src/main/java/com/example/demo/service/RagService.java package com.example.demo.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.document.Document; import org.springframework.ai.reader.tika.TikaDocumentReader; import org.springframework.ai.transformer.splitter.TokenTextSplitter; import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.List; import java.util.stream.Collectors; Service Slf4j RequiredArgsConstructor public class RagService { private final VectorStore vectorStore; private final ChatClient chatClient; private final EmbeddingService embeddingService; /** * 上传文档PDF, Word, TXT等并存入向量数据库 */ public void ingestDocument(MultipartFile file) throws IOException { // 1. 保存临时文件 Path tempFile Files.createTempFile(upload-, file.getOriginalFilename()); Files.copy(file.getInputStream(), tempFile, StandardCopyOption.REPLACE_EXISTING); // 2. 使用 Tika 读取文档内容支持多种格式 TikaDocumentReader documentReader new TikaDocumentReader(tempFile.toUri().toString()); ListDocument documents documentReader.read(); // 3. 文本分割防止文档过长超出模型上下文 TokenTextSplitter textSplitter new TokenTextSplitter(1000, 200, 10, 1000, true); // 参数块大小、重叠大小等 ListDocument splitDocuments textSplitter.apply(documents); // 4. 为每个文档块生成嵌入向量并存储 splitDocuments.forEach(embeddingService::embedDocument); vectorStore.add(splitDocuments); log.info(成功注入文档: {}分割为 {} 个块, file.getOriginalFilename(), splitDocuments.size()); // 清理临时文件 Files.deleteIfExists(tempFile); } /** * 基于知识库进行问答RAG 核心 */ public String askQuestion(String question) { // 1. 检索在向量库中搜索与问题最相关的文档块 ListDocument relevantDocs vectorStore.similaritySearch( SearchRequest.query(question).withTopK(4) // 返回最相关的4个片段 ); if (relevantDocs.isEmpty()) { return 知识库中未找到相关信息。; } // 2. 构建上下文 String context relevantDocs.stream() .map(Document::getContent) .collect(Collectors.joining(\n\n---\n\n)); // 3. 构建增强后的提示词Prompt Engineering String systemPrompt 你是一个专业的助手请严格根据以下提供的信息来回答问题。 如果信息不足以回答问题请如实告知“根据已知信息无法回答该问题”不要编造信息。 相关信息 %s 用户问题%s .formatted(context, question); // 4. 调用模型生成答案 return chatClient.prompt() .system(s - s.text(systemPrompt)) .user(question) .call() .content(); } /** * 清空向量数据库用于测试或重置 */ public void clearStore() { // 注意PgVectorStore 的 deleteAll 实现可能需要检查这里演示概念 // 实际可能需要执行 SQL TRUNCATE TABLE vector_store log.warn(清空向量存储...); // vectorStore.deleteAll(); // 如果 store 实现了该方法 } }5.4 创建 RAG 控制器// 文件路径src/main/java/com/example/demo/controller/RagController.java package com.example.demo.controller; import com.example.demo.service.RagService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; RestController RequestMapping(/api/rag) RequiredArgsConstructor public class RagController { private final RagService ragService; PostMapping(/ingest) public ResponseEntityString ingestDocument(RequestParam(file) MultipartFile file) { try { ragService.ingestDocument(file); return ResponseEntity.ok(文档 file.getOriginalFilename() 已成功注入知识库。); } catch (IOException e) { return ResponseEntity.internalServerError().body(文档处理失败: e.getMessage()); } } PostMapping(/ask) public ResponseEntityString askQuestion(RequestBody QuestionRequest request) { String answer ragService.askQuestion(request.getQuestion()); return ResponseEntity.ok(answer); } PostMapping(/clear) public ResponseEntityString clearStore() { ragService.clearStore(); return ResponseEntity.ok(知识库已清空。); } public record QuestionRequest(String question) {} }5.5 运行与测试 RAG 系统确保 PostgreSQL 运行且 PgVector 扩展已安装。启动应用SpringAI 会自动创建vector_store表。使用curl或 Postman 上传一个 PDF 或 TXT 文档比如一篇技术文章或产品手册。上传文档curl -X POST http://localhost:8080/api/rag/ingest \ -H Content-Type: multipart/form-data \ -F file/path/to/your/document.pdf进行问答curl -X POST http://localhost:8080/api/rag/ask \ -H Content-Type: application/json \ -d {question: 文档中提到的核心技术是什么}现在你的模型回答将基于你上传的文档内容而不是其固有的知识有效减少了“幻觉”并提升了专业领域回答的准确性。6. 常见问题与排查思路在集成 SpringAI 与 DeepSeek 的过程中你可能会遇到以下问题问题现象常见原因解决思路启动报错No qualifying bean of type EmbeddingClient1. SpringAI 依赖未正确引入。2.application.yml中 OpenAI/DeepSeek 配置缺失或错误。1. 检查pom.xml中spring-ai-openai-spring-boot-starter依赖。2. 检查spring.ai.openai.api-key和base-url配置。调用 Chat 或 Embedding API 超时或连接失败1. 网络问题无法访问 DeepSeek API。2. API Key 无效或过期。3.base-url配置错误。1. 使用curl或浏览器测试https://api.deepseek.com连通性。2. 在 DeepSeek 平台验证 API Key。3. 确认base-url末尾没有多余的/。Embedding 维度错误如ERROR: vector must have 1536 dimensions向量数据库配置的维度 (dimensions) 与 Embedding 模型实际输出的维度不匹配。1. 确认使用的 Embedding 模型名称。2.text-embedding-3-small维度是 1536text-embedding-3-large是 3072。确保spring.ai.vectorstore.pgvector.dimensions与之对应。RAG 检索结果不相关1. 文本分割策略不合理块太大或太小。2. Embedding 模型不适合该领域语言。3. 检索返回的文档块数量 (topK) 不合适。1. 调整TokenTextSplitter的块大小和重叠大小。2. 尝试不同的 Embedding 模型如果 DeepSeek 提供多个。3. 调整withTopK()参数尝试 3-10。流式响应 (/stream) 不工作或格式不对1. 客户端未正确处理 Server-Sent Events (SSE)。2. 控制器 produces 属性未设置或设置错误。1. 确保前端使用 EventSource 或兼容 SSE 的库。2. 检查控制器PostMapping的produces text/event-stream。文档解析Tika乱码或失败1. 文档格式复杂或损坏。2. 系统缺少必要的字体或库。1. 尝试先将文档转为纯文本 (.txt) 上传测试。2. 考虑使用更专业的解析库或云服务处理特定格式。7. 最佳实践与进阶建议将 SpringAI 和 DeepSeek 用于生产环境需要考虑更多工程化细节。7.1 配置管理API Key 安全必须使用环境变量或配置中心如 Apollo, Nacos管理切勿硬编码。多环境配置为开发、测试、生产环境配置不同的application-{profile}.yml可能使用不同的模型或 API 端点。连接池与超时SpringAI 底层使用 RestTemplate 或 WebClient建议配置合理的连接超时、读取超时和重试策略。spring: ai: openai: base-url: ${DEEPSEEK_BASE_URL:https://api.deepseek.com} api-key: ${DEEPSEEK_API_KEY} chat: options: model: ${CHAT_MODEL:deepseek-chat} temperature: 0.7 # 控制创造性业务回答建议较低如0.1 max-tokens: 2000 # 可配置 HTTP 客户端 client: connect-timeout: 10s read-timeout: 30s7.2 性能与成本优化Embedding 缓存对不变的文本如知识库文档进行 Embedding 后将向量结果缓存起来如 Redis避免重复调用产生费用和延迟。异步处理文档注入Ingestion过程耗时较长应改为异步任务如使用Async或消息队列避免阻塞 HTTP 请求。批量 Embedding始终使用embedForResponse(ListString)进行批量处理而非循环调用单条接口。模型选择根据场景选择模型。简单任务可用更小、更快的模型复杂推理再用大模型。关注 DeepSeek 官方的最新模型和价格。7.3 RAG 系统优化分块策略这是 RAG 效果的关键。除了按 Token 分割可以尝试按段落、标题进行语义分割或使用更高级的SemanticTextSplitter。元数据过滤在存储 Document 时可以附加元数据如来源、章节、日期。检索时除了语义相似度还可以结合元数据进行过滤提升精度。重排序初步检索出 Top K 个片段后可以使用一个更小的、专门用于判断相关性的模型重排序模型对结果进行二次排序选取最相关的几个。多路召回结合关键词搜索如 Elasticsearch和向量搜索进行混合检索应对不同查询类型。引用溯源在返回答案时同时返回引用片段的来源信息增加可信度。7.4 监控与可观测性日志记录详细记录 Chat 和 Embedding 的请求参数、耗时、Token 使用量。这对于成本分析和调试至关重要。链路追踪在微服务架构中集成 Sleuth/Zipkin 等追踪一次 AI 调用的完整链路。指标监控通过 Micrometer 暴露 Prometheus 指标监控 API 调用成功率、延迟、Token 消耗速率等。7.5 走向 Agentic RAG基础的 RAG 是被动的问答。更高级的模式是Agentic RAG让 AI Agent 主动利用 RAG 知识库和其他工具来完成任务。例如用户提出复杂任务“基于我们上一季度的销售报告写一份总结邮件。”Agent 规划步骤a. 从知识库检索销售报告。 b. 分析数据。 c. 撰写邮件草稿。Agent 调用 RAG 检索报告调用 Python 工具分析数据最后调用 Chat 模型撰写邮件。 SpringAI 正在积极集成对 Agent 框架的支持这是未来可以深入探索的方向。通过本文的教程你已经掌握了使用 SpringAI 集成 DeepSeek 进行 Chat、Embedding 和构建 RAG 系统的全流程。从简单的对话接口到复杂的私有知识库问答这套组合为 Java 后端开发者打开了高效开发大模型应用的大门。建议你从本文的示例代码出发逐步将其融入你的实际业务场景并持续关注 SpringAI 和 DeepSeek 的官方更新以利用最新的特性和优化。