资讯动态

Spring AI + RAG实战:构建Java智能知识库应用

发布时间:2026/8/22 7:39:39 来源:尧图企业网站定制
在实际 Java 后端项目中集成大语言模型LLM时开发者常常面临一个困境是直接调用模型 API 完成简单问答还是需要构建一套复杂的、能理解私有数据的智能系统。前者功能单一后者则涉及向量数据库、语义检索、上下文管理等一系列复杂组件学习曲线陡峭。Spring AI 及其生态项目 Spring AI Alibaba 的出现正是为了解决这个痛点它们旨在为 Java 开发者提供一套标准化、声明式的 API将 RAG、Function Calling、智能体Agent等复杂 AI 能力像使用 Spring Data 操作数据库一样简单。本文将以一个“智能客服知识库”为场景带你从零开始整合 Spring AI、Spring AI Alibaba、向量数据库构建一个完整的 RAG 应用。你会理解如何将本地文档转化为知识如何让大模型基于你的知识回答问题并最终通过一个 RESTful API 提供服务。整个过程将严格遵循工程实践涵盖环境搭建、核心概念、代码实现、问题排查和生产建议。1. 理解技术栈为什么是 Spring AI Spring AI Alibaba RAG在开始写代码之前必须理清这几个核心组件的关系和各自扮演的角色。混淆概念会导致依赖冲突和配置错误。1.1 Spring AIJava 生态的 AI 应用开发框架Spring AI 是 Spring 官方社区推出的项目其目标不是创造新的大模型而是为各种 AI 服务如 OpenAI、Azure OpenAI、Ollama 等提供统一的抽象接口。它的核心价值在于便携性通过更换一个spring-ai-*starter 的依赖就能从 OpenAI 切换到 Anthropic 或本地部署的 Ollama业务代码几乎不用改动。模版化提供了ChatClient、EmbeddingClient、VectorStore等高级接口简化了对话、嵌入向量生成、向量存储等操作。数据工程内置了文档加载、分割、转换等工具是构建 RAG 管道的基础。你可以把它类比为 Spring Data JPA它定义了一套操作数据库的规范而具体连接 MySQL 还是 PostgreSQL则由不同的实现如 Hibernate来完成。1.2 Spring AI Alibaba连接阿里云百炼等国内服务的桥梁Spring AI Alibaba 是阿里云对 Spring AI 抽象接口的具体实现。由于网络和政策原因直接使用海外的 AI 服务可能存在不便。Spring AI Alibaba 的主要作用包括实现 Spring AI 接口它提供了针对阿里云百炼平台包括通义千问、DeepSeek 等模型的ChatClient和EmbeddingClient实现。简化配置将阿里云所需的 AK/SK、Endpoint 等配置集成到 Spring Boot 的application.yml中。功能扩展在遵循 Spring AI 核心抽象的基础上可能会提供一些平台特有的高级功能。选择它意味着你决定使用阿里云百炼作为后端的模型服务提供商。如果你的模型服务是 OpenAI API 或本地部署的 Ollama则应选择对应的spring-ai-openai或spring-ai-ollamastarter。1.3 RAG让大模型“读懂”你私有知识的关键技术检索增强生成Retrieval-Augmented Generation, RAG是当前让大模型应用落地的核心技术。其核心思想不是重新训练模型而是在提问时动态地从外部知识库中检索相关文档片段并将其作为上下文连同问题一起交给模型从而生成更准确、更相关的回答。一个典型的 RAG 流程分为两个阶段知识库构建索引阶段加载从 PDF、Word、TXT、网页等来源加载文档。分割将长文档切分成语义连贯的片段如按段落或固定字符数。嵌入使用嵌入模型Embedding Model将文本片段转换为高维向量。存储将文本片段及其对应的向量存储到向量数据库如 Redis, Pinecone, PGVector中。问答检索与生成阶段提问用户提出一个问题。检索将问题同样转换为向量在向量数据库中搜索最相似的几个文本片段。增强将检索到的文本片段作为“参考依据”和原始问题组合形成新的提示词Prompt。生成将增强后的提示词发送给大语言模型生成最终答案。通过 RAG你可以低成本地让模型掌握最新的、未训练过的、或高度专业化的知识。1.4 技术选型与关系梳理基于以上概念我们本次实战的技术选型如下表所示组件具体选型作用备注AI 框架Spring AI提供统一的 AI 应用开发抽象和核心 API必选定义编程模型模型服务实现Spring AI Alibaba实现 Spring AI 接口连接阿里云百炼平台可选可替换为其他实现向量数据库Redis (Spring AI Redis VectorStore)存储和检索文档向量可选也可用 PGVector、Chroma 等文档处理Spring AI Document Readers加载和分割本地文档框架内置Web 框架Spring Boot Spring Web提供 RESTful API构建服务端点项目构建Maven 或 Gradle依赖管理它们之间的关系是Spring Boot 应用通过 Spring AI 的 API 进行编程。Spring AI Alibaba 作为“驱动程序”将 API 调用转换为对阿里云百炼的请求。向量数据库 Redis 作为外部知识存储。RAG 是使用这些组件构建出来的应用模式。2. 环境准备与项目初始化在开始编码前需要准备好开发环境和项目骨架。版本对齐是避免后续诡异问题的第一步。2.1 环境与工具清单请确保你的开发环境满足以下要求JDK: 17 或 21推荐 17长期支持版本。Maven: 3.6 或 Gradle。IDE: IntelliJ IDEA推荐或 VS Code with Java Extension Pack。Redis: 5.0 版本用于向量存储。你需要一个可访问的 Redis 实例可以是本地的 Docker 容器也可以是云服务。阿里云账号并开通百炼平台服务获取 API-KEY 和接入点Endpoint。这是使用 Spring AI Alibaba 的前提。2.2 创建 Spring Boot 项目使用 Spring Initializr 或 IDE 内置的 Spring Boot 项目创建向导生成一个基础项目。关键依赖选择Project: MavenLanguage: JavaSpring Boot: 3.2.x (确保与 Spring AI 版本兼容下文会说明)Dependencies:Spring Web(构建 API)Spring Data Redis(连接 Redis)Lombok(可选简化代码)生成项目后你需要手动在pom.xml中添加 Spring AI 和 Spring AI Alibaba 的依赖。版本兼容性至关重要请访问 Spring AI 官方文档 查看当前稳定版本与 Spring Boot 的对应关系。假设我们使用 Spring Boot 3.2.5 和 Spring AI 1.0.0 M3请根据实际情况调整添加以下依赖到pom.xmlproperties spring-ai.version1.0.0-M3/spring-ai.version /properties dependencies !-- Spring Boot 基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency !-- Spring AI 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-core/artifactId version${spring-ai.version}/version /dependency !-- Spring AI Alibaba 实现 -- dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-bailian-spring-boot-starter/artifactId version1.0.0-M3/version !-- 版本需与 spring-ai 对齐 -- /dependency !-- Spring AI Redis Vector Store -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-redis-store-spring-boot-starter/artifactId version${spring-ai.version}/version /dependency !-- 文档加载器例如处理PDF -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-pdf-document-reader/artifactId version${spring-ai.version}/version /dependency /dependencies注意Spring AI 和 Spring AI Alibaba 的版本必须严格匹配且与 Spring Boot 版本兼容。错误的版本组合会导致ClassNotFoundException或配置属性不生效。建议始终从官方仓库或文档获取最新的稳定版本信息。2.3 配置应用程序在src/main/resources/application.yml中配置 Redis 连接和阿里云百炼的认证信息。spring: application: name: ai-knowledge-base-demo # Redis 配置 (向量数据库) data: redis: host: localhost # 你的 Redis 地址 port: 6379 password: # 如果有密码 database: 0 # 建议使用独立的 database # 连接池配置生产环境建议配置 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 # Spring AI Alibaba 配置 (阿里云百炼) spring: ai: alibaba: bailian: access-key-id: your-access-key-id # 替换为你的 AccessKey ID access-key-secret: your-access-key-secret # 替换为你的 AccessKey Secret chat: endpoint: dashscope.aliyuncs.com # 百炼服务端点 options: model: qwen-max # 使用的模型例如 qwen-max, qwen-plus, qwen-turbo temperature: 0.7 # 创造性0-1越高越随机 embedding: endpoint: dashscope.aliyuncs.com options: model: text-embedding-v2 # 嵌入模型关键配置解释spring.data.redis向量数据将存储在这里。确保 Redis 服务已启动且网络可达。spring.ai.alibaba.bailian.access-key-id/secret这是访问阿里云服务的凭证务必妥善保管不要提交到代码仓库。建议使用环境变量或配置中心管理。chat.options.model指定用于对话的模型。qwen-max能力最强但可能更贵qwen-turbo速度更快成本更低根据场景选择。embedding.options.model指定用于生成文本向量的模型。对话模型和嵌入模型通常是分开的这里使用的是百炼的文本嵌入模型。3. 构建 RAG 知识库从文档到向量有了基础项目后我们首先实现 RAG 流程的“索引阶段”即构建知识库。我们将创建一个服务能够读取本地文档处理并存储到 Redis 向量数据库中。3.1 设计文档处理流程我们创建一个DocumentService来封装整个处理流程。其核心步骤对应 RAG 索引阶段加载Load使用DocumentReader如PagePdfDocumentReader读取文件。分割Split使用TokenTextSplitter或RecursiveCharacterTextSplitter将文档切成小段。嵌入Embed调用EmbeddingClient为每个文本段生成向量。存储Store使用VectorStore将文本段 向量 元数据存入数据库。3.2 实现 DocumentService首先Spring AI Alibaba 的 starter 会自动为我们配置好ChatClient和EmbeddingClient的 Bean。我们需要注入EmbeddingClient和VectorStore。import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.document.Document; import org.springframework.ai.reader.pdf.PagePdfDocumentReader; import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig; 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 java.io.IOException; import java.util.List; Service Slf4j RequiredArgsConstructor public class DocumentService { // VectorStore 接口由 spring-ai-redis-store 自动配置提供 Redis 实现 private final VectorStore vectorStore; /** * 处理并存储单个 PDF 文件到向量数据库 * param pdfResource PDF 文件资源 * return 存储的文档数量 */ public int processAndStorePdf(Resource pdfResource) throws IOException { log.info(开始处理 PDF 文件: {}, pdfResource.getFilename()); // 1. 加载使用 PDF 阅读器 PdfDocumentReaderConfig config PdfDocumentReaderConfig.builder() .withPageTopMargin(0) // 页面边距配置根据实际文档调整 .withPageBottomMargin(0) .build(); PagePdfDocumentReader pdfReader new PagePdfDocumentReader(pdfResource, config); ListDocument rawDocuments pdfReader.get(); log.info(PDF 加载完成共 {} 页, rawDocuments.size()); // 2. 分割使用 TokenTextSplitter (按 Token 数分割更适配 LLM) // 也可以使用 RecursiveCharacterTextSplitter (按字符递归分割) TokenTextSplitter textSplitter new TokenTextSplitter(); // 参数说明 // chunkSize: 每个片段的最大 Token 数。模型有上下文限制不宜过大。 // chunkOverlap: 相邻片段重叠的 Token 数避免语义被硬切断。 textSplitter.setChunkSize(1000); textSplitter.setChunkOverlap(200); ListDocument splitDocuments textSplitter.apply(rawDocuments); log.info(文档分割完成共生成 {} 个文本片段, splitDocuments.size()); // 3. 嵌入 存储VectorStore.add 方法会自动调用注入的 EmbeddingClient 生成向量并存储 vectorStore.add(splitDocuments); log.info(文档向量已成功存储到 Redis); return splitDocuments.size(); } /** * 从向量数据库中搜索与查询相似的文档片段 * param query 查询文本 * param topK 返回最相似的前 K 个结果 * return 相关的文档列表 */ public ListDocument searchSimilarDocuments(String query, int topK) { SearchRequest request SearchRequest.query(query).withTopK(topK); // similarityThreshold 可以设置相似度阈值过滤掉低分结果 // request.withSimilarityThreshold(0.7); return vectorStore.similaritySearch(request); } /** * 清空向量数据库中的全部数据谨慎使用 */ public void clearVectorStore() { vectorStore.delete(List.of()); // 传入空列表表示删除所有 // 或者使用特定实现的方法如 ((RedisVectorStore)vectorStore).flushDb(); log.warn(向量数据库已清空); } }代码关键点解析依赖注入VectorStore是一个接口Spring AI Redis starter 会自动配置一个基于 Redis 的实现并注入进来。它内部已经绑定了我们配置的EmbeddingClient阿里云百炼的嵌入模型。文档加载PagePdfDocumentReader是 Spring AI 提供的 PDF 阅读器它按页将 PDF 转换为Document对象。Document对象包含文本内容和可选的元数据。文本分割TokenTextSplitter是按 Token 数进行分割的策略更符合大语言模型的处理单元。chunkSize和chunkOverlap是两个关键参数chunkSize决定每个片段的大小。太小会丢失上下文太大会超出模型上下文限制且检索精度下降。通常设置在 500-2000 tokens 之间。chunkOverlap片段间的重叠部分。这能保证一个完整的句子或概念不会被刚好切在边界而丢失信息。存储vectorStore.add(documents)是核心。这个方法会遍历每个Document调用EmbeddingClient将其文本内容转换为向量然后将(文本, 向量, 元数据)作为一个条目存入 Redis。检索vectorStore.similaritySearch(request)是核心检索方法。它先将查询文本query通过同样的EmbeddingClient转换为向量然后在 Redis 中执行向量相似度搜索如余弦相似度返回最相似的topK个文档片段。3.3 创建管理 API为了便于测试我们创建一个简单的 REST 控制器提供上传 PDF 构建知识库和清空知识库的端点。import lombok.RequiredArgsConstructor; import org.springframework.core.io.Resource; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; 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; RestController RequestMapping(/api/knowledge) RequiredArgsConstructor public class KnowledgeBaseController { private final DocumentService documentService; PostMapping(/upload-pdf) public ResponseEntityString uploadPdf(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest().body(文件为空); } try { // 将上传的文件保存为临时文件 Path tempFile Files.createTempFile(upload-, .pdf); Files.copy(file.getInputStream(), tempFile, StandardCopyOption.REPLACE_EXISTING); Resource pdfResource new org.springframework.core.io.UrlResource(tempFile.toUri()); int storedCount documentService.processAndStorePdf(pdfResource); // 清理临时文件 Files.deleteIfExists(tempFile); return ResponseEntity.ok(String.format(成功处理并存储了 %d 个文档片段。, storedCount)); } catch (IOException e) { return ResponseEntity.internalServerError().body(文件处理失败: e.getMessage()); } } DeleteMapping(/clear) public ResponseEntityString clearKnowledgeBase() { documentService.clearVectorStore(); return ResponseEntity.ok(知识库已清空); } }现在你可以启动应用使用 Postman 或 curl 向POST /api/knowledge/upload-pdf上传一个 PDF 文件例如公司产品手册后端服务会自动将其内容切片、向量化并存入 Redis。使用redis-cli连接你的 Redis执行KEYS *可以看到 Spring AI 创建的一些键如spring:ai:*:index和spring:ai:*:embeddings这证明数据已成功入库。4. 实现 RAG 问答检索与生成知识库构建完成后下一步是实现问答流程。我们将创建一个RagService它负责接收用户问题从向量库检索相关上下文并调用大模型生成答案。4.1 设计提示词模板RAG 的核心之一是如何将检索到的上下文和原始问题组合成一个有效的提示词Prompt。一个通用的模板如下请基于以下上下文信息回答问题。如果上下文信息不足以回答问题请直接回答“根据已知信息无法回答该问题”。 上下文信息 {context} 问题 {question} 请用中文回答在 Spring AI 中我们可以使用PromptTemplate来管理这个模板。4.2 实现 RagServiceimport lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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.prompt.PromptTemplate; import org.springframework.ai.document.Document; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; Service Slf4j RequiredArgsConstructor public class RagService { private final ChatClient chatClient; // 由 Spring AI Alibaba 自动配置 private final DocumentService documentService; // 定义提示词模板 private static final String PROMPT_TEMPLATE 请严格基于以下提供的上下文信息来回答问题。如果上下文信息中没有包含答案所需的信息请直接回答“根据提供的资料我无法回答这个问题”。不要编造信息。 上下文信息 {context} 问题 {question} 请用中文给出清晰、准确的回答 ; /** * 基于知识库进行问答 * param question 用户问题 * return 模型生成的答案 */ public String askQuestion(String question) { log.info(接收到问题: {}, question); // 1. 检索从向量库中查找与问题相关的文档片段 int topK 5; // 检索最相关的5个片段 ListDocument relevantDocs documentService.searchSimilarDocuments(question, topK); if (relevantDocs.isEmpty()) { return 知识库中未找到相关信息无法回答该问题。; } // 2. 构建上下文将检索到的文档内容合并成一个字符串 String context relevantDocs.stream() .map(Document::getContent) .collect(Collectors.joining(\n\n---\n\n)); log.debug(检索到的上下文:\n{}, context); // 3. 填充提示词模板 PromptTemplate promptTemplate new PromptTemplate(PROMPT_TEMPLATE); MapString, Object model new HashMap(); model.put(context, context); model.put(question, question); Prompt prompt promptTemplate.create(model); // 4. 调用大模型生成答案 ChatResponse response chatClient.prompt(prompt) .call() .chatResponse(); // 使用默认的模型参数在配置中定义的temperature等 String answer response.getResult().getOutput().getContent(); log.info(生成的答案: {}, answer); return answer; } }代码关键点解析依赖注入ChatClient是 Spring AI 的核心对话接口由 Spring AI Alibaba starter 根据application.yml的配置提供连接阿里云百炼的具体实现。检索调用之前实现的documentService.searchSimilarDocuments(question, topK)。topK是一个重要参数它决定了提供给模型的上下文量。太少可能信息不足太多可能引入噪声并增加 token 消耗。需要根据实际效果调整。上下文构建将多个文档片段用分隔符连接起来。清晰的分隔符如\n\n---\n\n有助于模型区分不同的来源片段。提示词工程模板中的指令非常关键。“严格基于上下文”和“无法回答时直接说明”的指令能有效减少模型“幻觉”即编造信息。这是生产级 RAG 必须考虑的部分。调用模型chatClient.prompt(prompt).call()是标准的调用方式。返回的ChatResponse包含了完整的响应信息我们从中提取出最终的文本答案。4.3 创建问答 API最后我们暴露一个简单的 HTTP 端点来接收用户提问。import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/rag) RequiredArgsConstructor public class RagController { private final RagService ragService; PostMapping(/ask) public ResponseEntityAnswerResponse askQuestion(RequestBody QuestionRequest request) { String answer ragService.askQuestion(request.getQuestion()); return ResponseEntity.ok(new AnswerResponse(answer)); } // 简单的请求/响应对象 public record QuestionRequest(String question) {} public record AnswerResponse(String answer) {} }现在完整的 RAG 流程已经打通。你可以启动 Spring Boot 应用。通过/api/knowledge/upload-pdf上传你的知识文档如product_manual.pdf。等待控制台日志显示处理完成。向/api/rag/ask发送一个 JSON 请求如{question: 你们产品的主要特性是什么}。服务会从 PDF 中检索相关信息并调用阿里云百炼的模型生成一个基于文档内容的回答。5. 核心配置、参数调优与生产级考量一个能跑通的 Demo 和一个健壮的生产应用之间隔着许多细节。本章节将深入探讨关键配置、参数调优以及上线前必须考虑的问题。5.1 关键配置参数详解以下配置参数直接影响应用的效果、性能和成本需要根据实际情况仔细调整。配置项位置说明与建议spring.ai.alibaba.bailian.chat.options.modelapplication.yml对话模型。qwen-max能力强qwen-turbo响应快成本低。根据问答复杂度选择。spring.ai.alibaba.bailian.chat.options.temperatureapplication.yml创造性 (0~1)。对于知识库问答建议较低 (0.1~0.3)使答案更确定、更基于上下文。创意生成可调高。chunkSizeTokenTextSplitter文本分割大小。这是最重要的参数之一。建议 500-1500 tokens。需考虑模型上下文窗口如 8K, 32K和嵌入模型限制。chunkOverlapTokenTextSplitter分割重叠。通常为chunkSize的 10%-20%。确保语义完整性。topKRagService.searchSimilarDocuments检索返回的文档数量。通常 3-10。太少信息不全太多可能包含无关信息并增加 token 消耗。需要实验。similarityThresholdSearchRequest相似度阈值。低于此值的检索结果将被过滤。可用于提高答案相关性但可能在某些问题上返回空结果。5.2 生产环境部署 checklist将本应用部署到生产环境前请逐一核对以下清单[ ]敏感信息管理AK/SK 等密钥必须从application.yml移除使用环境变量SPRING_AI_ALIBABA_BAILIAN_ACCESS-KEY-ID或专业的配置中心/密钥管理服务。[ ]Redis 高可用生产环境 Redis 应配置为主从、哨兵或集群模式并设置合理的持久化策略。连接池参数需要优化。[ ]异常处理与降级ChatClient和EmbeddingClient的调用可能因网络、限流、服务不可用而失败。必须添加重试、熔断、降级逻辑如使用 Resilience4j 或 Sentinel。在无法调用 AI 服务时应有友好的错误提示或备用回答。[ ]日志与监控记录关键操作的日志如文档处理状态、问答请求和响应摘要。集成监控如 Micrometer Prometheus跟踪 API 延迟、Token 消耗、向量检索耗时等指标。[ ]限流与鉴权问答 API 可能被滥用。需要集成 Spring Security 进行 API 鉴权并使用网关或ControllerAdvice实现限流。[ ]文档预处理优化简单的按页或按 Token 分割可能不够智能。对于复杂文档如带目录的书籍、多格式混合的网页可能需要先做结构解析提取标题、段落再进行语义分割。[ ]多轮对话支持当前是单轮问答。若要支持多轮对话需要在检索时考虑历史对话上下文并将其也作为输入的一部分。这涉及更复杂的上下文管理。5.3 性能与成本优化建议批量处理文档vectorStore.add支持批量操作但一次传入过多文档可能导致内存溢出或 API 限流。建议分批处理每批 50-100 个文档。向量索引优化确保 Redis 有足够内存存储向量。对于大规模知识库百万级向量需要考虑专门的向量数据库如 Milvus, Qdrant, Weaviate它们对向量检索有更好的优化。缓存策略对于高频的、相同或相似的问题可以在应用层如 Redis 或 Caffeine缓存最终的答案避免重复的检索和模型调用显著降低延迟和成本。异步处理文档上传和向量化过程可以改为异步任务如使用Async或消息队列避免阻塞 HTTP 请求提升用户体验。6. 常见问题排查与调试指南在实际开发和运行中你可能会遇到以下问题。这里提供排查思路。6.1 启动与配置类问题问题现象可能原因检查与解决应用启动失败报NoSuchBeanDefinitionException或ClassNotFoundExceptionSpring AI 或 Spring AI Alibaba 版本不兼容。1. 检查pom.xml中所有spring-ai-*和spring-ai-alibaba-*依赖版本是否严格一致且与 Spring Boot 兼容。2. 查看官方文档或仓库的 Release Notes 确认版本匹配关系。连接阿里云百炼失败报认证错误AK/SK 配置错误或服务未开通。1. 检查access-key-id和access-key-secret是否正确注意空格和大小写。2. 登录阿里云控制台确认百炼服务已开通且该 AK 有相应权限。3. 尝试在代码外使用 curl 命令调用百炼 API验证凭证有效性。Redis 连接失败Redis 服务未启动或配置的主机/端口/密码错误。1. 使用redis-cli -h host -p port -a password手动连接测试。2. 检查 Spring Boot 日志中的 Redis 连接信息。6.2 文档处理与检索问题问题现象可能原因检查与解决上传 PDF 后问答结果完全不相关1. 文本分割不合理 (chunkSize过大或过小)。2. 嵌入模型不适合该类型文本。3. 检索的topK值不合适。1.检查分割结果在DocumentService中打印splitDocuments的内容看是否被合理切分。2.调整参数尝试减小chunkSize(如 500) 并增加chunkOverlap(如 100)。3.检查检索结果在RagService中打印relevantDocs的内容看检索到的片段是否真的与问题相关。如果不相关可能是嵌入模型对该领域文本表征能力弱。模型回答“无法回答”但知识库中明明有相关内容1. 检索到的上下文质量差。2. 提示词模板指令太严格或模糊。3. 相似度阈值similarityThreshold设得过高。1.优化检索尝试增加topK(如从 3 到 10)让模型看到更多上下文。2.优化提示词微调提示词模板例如将“严格基于”改为“请参考以下信息”或明确要求“结合上下文和你自己的知识”。3.调整阈值暂时移除similarityThreshold或将其调低 (如 0.5)。处理大型 PDF 时内存溢出或超时一次性加载和嵌入整个大文件。1.分批处理在DocumentService中实现分批读取、分割和存储的逻辑。2.异步处理将文档处理改为异步任务并监控其进度。6.3 模型响应问题问题现象可能原因检查与解决回答包含大量与上下文无关的“幻觉”信息1.temperature参数过高。2. 提示词约束力不够。3. 模型本身特性。1.降低创造性将temperature设置为 0.1 或 0.2。2.强化提示词在提示词开头使用更强烈的指令如“你必须且只能使用以下上下文信息回答问题禁止使用外部知识。”3.后处理过滤对模型返回的答案可以再用一个分类器判断其是否忠实于上下文。响应速度很慢1. 网络延迟。2. 检索的topK过大导致上下文过长模型处理耗时增加。3. 使用了较慢的模型如qwen-max。1.优化上下文长度减少topK或chunkSize缩短总上下文 tokens。2.切换模型对于实时性要求高的场景尝试qwen-turbo。3.启用流式响应如果前端支持使用chatClient.stream()实现流式输出提升用户体验。6.4 调试技巧开启详细日志在application.yml中设置logging.level.org.springframework.aiDEBUG可以查看 Spring AI 内部的关键操作日志如向量化、检索的详情。检查向量存储使用 Redis 可视化工具或redis-cli查看spring:ai:*相关的键确认数据是否成功写入。隔离测试单独编写测试类分别测试EmbeddingClient.embed(“测试文本”)和VectorStore.similaritySearch确保这两个基础功能正常工作。7. 扩展方向从 RAG 到智能体与复杂应用基于当前搭建的 RAG 知识库你可以向更复杂的 AI 应用演进。7.1 集成 Function Calling 与 ToolsSpring AI 支持将 Java 方法暴露为“工具”Tool让大模型在对话中根据需要调用。例如你可以在问答过程中让模型决定是否需要查询数据库、调用外部 API 或执行计算。// 1. 定义一个工具例如查询天气 Bean public FunctionCallback weatherFunction() { return FunctionCallback.builder() .name(getWeather) .description(根据城市名称查询实时天气) .responseConverter((response) - response) // 自定义响应转换 .function((city) - { // 实现具体的天气查询逻辑 return 上海晴25°C; }) .build(); } // 2. 在调用 ChatClient 时注册工具 ChatResponse response chatClient.prompt(userPrompt) .tools(weatherFunction()) // 注册工具 .call() .chatResponse();这样当用户问“上海天气怎么样”时模型可能会自动调用getWeather工具并将结果整合到最终回答中。7.2 构建智能体工作流智能体是能自主规划、调用工具、完成复杂任务的 AI 系统。你可以利用 Spring AI 的Agent抽象将 RAG 检索、Function Calling、条件判断等组合成一个工作流。例如一个客服智能体可以1先检索知识库2如果找到答案直接回复3如果没找到调用“转人工”或“创建工单”的工具。7.3 实现更复杂的检索策略混合检索结合向量检索语义相似和关键词检索BM25提升召回率。重排序先用向量检索召回大量候选文档如 top 50再用一个更精细的模型或规则对结果进行重排序选取 top 3 给大模型。元数据过滤在存储文档时为其添加元数据如文档类型、创建日期、部门。检索时可以同时进行向量相似度搜索和元数据过滤。7.4 前端交互与流式输出当前 API 是同步阻塞的。对于长文本生成可以改造为 Server-Sent Events 流式接口实现打字机效果。GetMapping(value /ask-stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString askQuestionStream(RequestParam String question) { return chatClient.prompt(question) .stream() .content(); }通过本次从零到一的构建你不仅掌握了一个可运行的 RAG 知识库应用更理解了 Spring AI 如何通过抽象简化 AI 集成以及 RAG 管道中每个环节的配置与调优要点。在实际项目中请务必关注生产清单中的安全、性能和监控项并根据具体的业务数据和问答效果持续迭代你的分割策略、检索参数和提示词模板。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价