news 2026/9/5 2:58:32

SpringAI集成DeepSeek:从Chat到RAG的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringAI集成DeepSeek:从Chat到RAG的完整实战指南

最近在尝试将大模型能力集成到 Spring Boot 项目中时,发现虽然 OpenAI 的 API 很强大,但成本、网络和合规性常常成为拦路虎。与此同时,国产大模型如 DeepSeek 的崛起,以其出色的性能和极具竞争力的价格,为开发者提供了新的选择。如何快速、优雅地在 Spring 生态中集成这些 AI 能力,并构建起检索增强生成(RAG)等高级应用,是很多后端开发者面临的共同挑战。

本文将围绕SpringAI这一官方项目,手把手带你从零搭建一个完整的大模型应用开发环境。我们将以DeepSeek作为核心模型,贯穿ChatModel(对话)、Embedding(向量化)、RAG(知识库问答)三大核心场景,提供从环境配置、代码编写到生产级最佳实践的完整闭环教程。无论你是想为现有系统添加智能对话功能,还是希望构建一个基于私有知识库的问答助手,这篇文章都能为你提供可直接复用的解决方案。

1. SpringAI 与 DeepSeek:强强联合的技术栈

在开始动手之前,我们有必要理清几个核心概念,理解为什么选择这个技术组合。

1.1 什么是 SpringAI?

SpringAI 是 Spring 官方推出的一个项目,旨在为 Spring 应用程序集成人工智能功能提供一套简洁、一致的抽象 API。它的核心价值在于:

  • 抽象与统一:它定义了一套标准的接口(如ChatClientEmbeddingClient),让开发者无需关心底层具体是 OpenAI、Azure OpenAI、DeepSeek 还是其他任何兼容 OpenAI API 的模型服务。只需更换配置,就能切换模型提供商。
  • Spring 生态无缝集成:与 Spring Boot 的自动配置、依赖注入、外部化配置(application.yml)完美融合,开发体验非常“Spring”。
  • 功能全面:不仅支持基础的聊天补全(Chat Completion),还支持文本嵌入(Embedding)、图像生成、语音转录等,并内置了对 RAG、函数调用等高级模式的支持。
  • 活跃的社区与迭代:作为 Spring 官方项目,其版本迭代迅速,能及时跟进 AI 领域的最新进展。

简单说,SpringAI 就像 JDBC 之于数据库,它为我们操作各种大模型提供了一个统一、便捷的编程界面。

1.2 为什么选择 DeepSeek?

在众多大模型中,DeepSeek 是一个特别值得关注的选项,尤其对于国内开发者:

  1. 卓越的性能:DeepSeek 的最新模型(如 V3、V4 Flash)在多项中英文基准测试中表现优异,推理、代码、数学能力突出,完全具备生产级应用的能力。
  2. 极致的成本优势:其 API 定价远低于国际主流厂商,例如,DeepSeek-V3 的输入价格仅为 GPT-4 Turbo 的约 1/30,这使得大规模应用和频繁调用成为可能。
  3. 对国内开发者友好:无需处理复杂的网络问题,访问稳定,响应速度快。
  4. 兼容 OpenAI API:DeepSeek 提供了与 OpenAI 完全兼容的 API 接口,这意味着所有基于 OpenAI SDK 或 SpringAI(底层也是 OpenAI 协议)开发的代码,几乎可以无缝迁移到 DeepSeek。

1.3 核心概念:ChatModel, Embedding 与 RAG

  • ChatModel:指能够进行多轮对话、理解上下文的大型语言模型。在 SpringAI 中,通过ChatClient与之交互,完成问答、创作、分析等任务。
  • Embedding:指将文本、图像等数据转化为高维向量(一组数字)的技术。这个向量包含了数据的语义信息。语义相近的文本,其向量在空间中的距离也更近。这是实现语义搜索、文本分类、RAG 的基石。
  • RAG (Retrieval-Augmented Generation):检索增强生成。这是一种解决大模型“幻觉”(编造信息)和知识滞后问题的架构。其核心流程是:
    1. 索引:将私有知识库(如 PDF、Word、公司文档)通过 Embedding 模型转化为向量,并存入向量数据库(如 Pinecone、Chroma、Milvus)。
    2. 检索:当用户提问时,将问题也转化为向量,并在向量数据库中搜索与之最相关的知识片段。
    3. 增强:将检索到的相关片段作为上下文,与用户问题一起提交给 ChatModel。
    4. 生成: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: Maven
  • Language: Java
  • Spring 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 version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> <!-- 使用稳定的 3.2.x 版本 --> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>spring-ai-deepseek-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-ai-deepseek-demo</name> <description>Demo project for Spring AI with DeepSeek</description> <properties> <java.version>17</java.version> <!-- 定义 Spring AI 版本 --> <spring-ai.version>1.0.0-M3</version> <!-- 请检查官网使用最新稳定版 --> </properties> <dependencyManagement> <dependencies> <!-- 引入 Spring AI BOM 统一管理所有 AI 模块版本 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Spring AI OpenAI 模块 (兼容 DeepSeek API) --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> <!-- 后续 RAG 需要向量数据库和文件解析,可先引入 --> <!-- <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-tika-document-reader</artifactId> </dependency> --> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>

关键点说明

  1. dependencyManagement中引入spring-ai-bom,这是管理所有 SpringAI 模块版本的最佳实践。
  2. 我们依赖spring-ai-openai-spring-boot-starter。因为 DeepSeek 兼容 OpenAI API,所以使用这个 starter 即可。
  3. 向量数据库和文档读取的依赖已被注释,我们会在 RAG 章节引入。

3. 基础配置与 ChatModel 初体验

3.1 配置 DeepSeek API

src/main/resources/application.yml中配置 DeepSeek:

spring: 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 Flux<String> 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 Flux<String> 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 运行与测试

  1. 启动 Spring Boot 应用。
  2. 使用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 List<Double> embedText(String text) { EmbeddingResponse response = embeddingClient.embedForResponse(List.of(text)); // 通常返回一个 List 的 List,第一个元素就是第一个文本的向量 return response.getResults().get(0).getOutput(); } /** * 为多个文本批量生成嵌入向量(更高效) */ public List<List<Double>> embedTexts(List<String> 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) { List<Double> vector1 = embedText(text1); List<Double> vector2 = embedText(text2); return cosineSimilarity(vector1, vector2); } /** * 余弦相似度计算工具方法 */ private double cosineSimilarity(List<Double> vectorA, List<Double> 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."; List<Double> 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> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-tika-document-reader</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>

5.2 配置 PostgreSQL 与 PgVector

  1. 安装 PostgreSQL:确保本地或远程有一个 PostgreSQL 数据库(版本 >= 14)。
  2. 安装 PgVector 扩展:在数据库中执行CREATE EXTENSION IF NOT EXISTS vector;
  3. 配置连接:更新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: true

5.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()); List<Document> documents = documentReader.read(); // 3. 文本分割(防止文档过长,超出模型上下文) TokenTextSplitter textSplitter = new TokenTextSplitter(1000, 200, 10, 1000, true); // 参数:块大小、重叠大小等 List<Document> 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. 检索:在向量库中搜索与问题最相关的文档块 List<Document> 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 ResponseEntity<String> 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 ResponseEntity<String> askQuestion(@RequestBody QuestionRequest request) { String answer = ragService.askQuestion(request.getQuestion()); return ResponseEntity.ok(answer); } @PostMapping("/clear") public ResponseEntity<String> clearStore() { ragService.clearStore(); return ResponseEntity.ok("知识库已清空。"); } public record QuestionRequest(String question) {} }

5.5 运行与测试 RAG 系统

  1. 确保 PostgreSQL 运行且 PgVector 扩展已安装。
  2. 启动应用,SpringAI 会自动创建vector_store表。
  3. 使用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 'EmbeddingClient'1. SpringAI 依赖未正确引入。
2.application.yml中 OpenAI/DeepSeek 配置缺失或错误。
1. 检查pom.xmlspring-ai-openai-spring-boot-starter依赖。
2. 检查spring.ai.openai.api-keybase-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维度是 1536,text-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. 检查控制器@PostMappingproduces = "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: 30s

7.2 性能与成本优化

  • Embedding 缓存:对不变的文本(如知识库文档)进行 Embedding 后,将向量结果缓存起来(如 Redis),避免重复调用产生费用和延迟。
  • 异步处理:文档注入(Ingestion)过程耗时较长,应改为异步任务(如使用@Async或消息队列),避免阻塞 HTTP 请求。
  • 批量 Embedding:始终使用embedForResponse(List<String>)进行批量处理,而非循环调用单条接口。
  • 模型选择:根据场景选择模型。简单任务可用更小、更快的模型;复杂推理再用大模型。关注 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 知识库和其他工具来完成任务。例如:

  1. 用户提出复杂任务:“基于我们上一季度的销售报告,写一份总结邮件。”
  2. Agent 规划步骤:a. 从知识库检索销售报告。 b. 分析数据。 c. 撰写邮件草稿。
  3. Agent 调用 RAG 检索报告,调用 Python 工具分析数据,最后调用 Chat 模型撰写邮件。 SpringAI 正在积极集成对 Agent 框架的支持,这是未来可以深入探索的方向。

通过本文的教程,你已经掌握了使用 SpringAI 集成 DeepSeek 进行 Chat、Embedding 和构建 RAG 系统的全流程。从简单的对话接口到复杂的私有知识库问答,这套组合为 Java 后端开发者打开了高效开发大模型应用的大门。建议你从本文的示例代码出发,逐步将其融入你的实际业务场景,并持续关注 SpringAI 和 DeepSeek 的官方更新,以利用最新的特性和优化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 3:05:30

yolo模型学习

指令&#xff1a; 训练指令&#xff1a; yolo detect train dataH:\xxc\yolo\yolo_dataset\yolo_dataset\data.yaml modelyolov8n.pt epochs100 imgsz640 测试指令&#xff1a; yolo detect predict modelH:\xxc\yolo\ultralytics\runs\detect\train-11\weights\best.pt so…

作者头像 李华
网站建设 2026/9/4 1:32:43

零基础C语言学习路线:从环境搭建到项目实战的完整指南

这类C语言教程视频最大的价值&#xff0c;不是把知识点讲得多深奥&#xff0c;而是能不能让一个零基础的人&#xff0c;看完之后能自己动手写出代码&#xff0c;并且理解每一步在干什么。网上资源很多&#xff0c;但真正能让人“跟下来”的&#xff0c;往往需要清晰的演示、完整…

作者头像 李华
网站建设 2026/9/5 3:49:28

基于Kronos框架的AI金融量化预测:从时序模型到实战策略

简介&#xff1a;FaceCat-Kronos是一款面向个人学习者与量化交易初学者的金融时序预测工具&#xff0c;基于清华大学开源Kronos框架构建&#xff0c;融合深度学习模型对证券历史行情进行预训练与形态推演&#xff0c;旨在辅助短线交易者识别价格规律、优化策略逻辑。资源包共50…

作者头像 李华
网站建设 2026/9/4 15:25:54

游戏化盲打训练:用Python自制打字游戏提升编程效率

如果你是一名程序员&#xff0c;或者每天需要大量敲击键盘的文字工作者&#xff0c;你大概率经历过这样的场景&#xff1a;眼睛在屏幕和键盘之间来回切换&#xff0c;手指在几个常用键位上犹疑不定&#xff0c;输入一个简单的命令或句子都显得磕磕绊绊。这不仅效率低下&#xf…

作者头像 李华
网站建设 2026/9/5 12:21:33

ZYNQ 7020 UART0串口全工程详解:从MIO配置到裸机回显

简介&#xff1a;这是一份基于ZYNQ 7020 SoC的UART0串口通信完整工程包&#xff0c;面向嵌入式开发者与FPGA学习者&#xff0c;解决在Vivado 2018.2环境下从硬件配置到软件驱动的串口通信落地问题。压缩包共544个文件&#xff0c;约5.56MB&#xff0c;包含140个h头文件、91个c源…

作者头像 李华
网站建设 2026/9/2 6:17:47

基于FPGA与VHDL的FSK调制器实现:从DDS原理到硬件调试

简介&#xff1a;本资源是一份面向数字通信与FPGA开发初学者的FSK频移键控调制硬件实现方案&#xff0c;聚焦VHDL语言在FPGA平台上的工程落地&#xff0c;适用于通信原理课程设计、嵌入式系统实验及无线收发模块开发等场景。压缩包共65个文件&#xff0c;138KB&#xff0c;核心…

作者头像 李华