Spring AI RAG Demo
所属分类 AI
浏览量 9
Spring AI RAG Demo
整体链路:
上传 PDF/TXT 文档
文档分段
向量化
存入 Redis 向量库
提问自动检索知识库
LLM 回答
技术栈:
SpringBoot3.3 + SpringAI 2.0 + Ollama (Qwen) + RedisVectorStore + SpringDoc OpenAPI
一、整体依赖 pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.3.0
com.ai
spring-ai-rag-demo
0.0.1-SNAPSHOT
SpringAI RAG Demo
17
2.0.0
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-web
org.springframework.ai
spring-ai-ollama-spring-boot-starter
${spring.ai.version}
org.springframework.ai
spring-ai-redis-store-spring-boot-starter
${spring.ai.version}
org.springframework.ai
spring-ai-pdf-document-reader
${spring.ai.version}
org.springframework.ai
spring-ai-markdown-document-reader
${spring.ai.version}
com.github.xiaoymin
knife4j-openapi3-jakarta-spring-boot-starter
4.5.0
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
二、配置文件 application.yml
spring:
application:
name: spring-ai-rag
# 文件上传限制
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
# Redis向量库配置
data:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
ai:
# Ollama 配置,提前执行 ollama pull qwen:7b
ollama:
base-url: http://127.0.0.1:11434
chat:
options:
model: qwen:7b
temperature: 0.3 # 低随机性,知识库问答更严谨
embedding:
options:
model: qwen:7b
# Redis向量库参数
vectorstore:
redis:
index-name: rag_doc_index # 向量索引名称
prefix: rag:doc: # Redis Key前缀
initialize-schema: true # 自动创建向量索引
dimensions: 3584 # qwen:7b向量维度,固定
distance-type: COSINE # 余弦相似度
# 接口文档
knife4j:
enable: true
三、启动类
package com.ai.rag;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RagApplication {
public static void main(String[] args) {
SpringApplication.run(RagApplication.class, args);
}
}
四、RAG 核心配置类(构建 RAG 链路、检索增强 Advisor)
package com.ai.rag.config;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@RequiredArgsConstructor
public class RagConfig {
private final VectorStore vectorStore;
/**
* 构建带RAG知识库增强的ChatClient
* 1. SimpleLoggerAdvisor:打印请求/响应日志
* 2. QuestionAnswerAdvisor:RAG核心,自动根据问题检索向量库,把文档塞进Prompt
*/
@Bean
public ChatClient ragChatClient(ChatClient.Builder builder) {
// RAG系统提示词:严格基于知识库回答,无资料直接说不知道,禁止编造
String ragSystemPrompt = """
你是企业知识库问答助手,请严格根据上下文参考资料回答用户问题。
1. 如果参考资料没有对应信息,直接回复「暂无相关知识库资料,无法解答该问题」,禁止编造内容;
2. 回答条理清晰,重点加粗,精简话术;
3. 不要输出无关内容,不要凭空拓展。
""";
return builder
.defaultSystem(ragSystemPrompt)
// 日志拦截器
.defaultAdvisors(new SimpleLoggerAdvisor())
// RAG检索增强拦截器
.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
.build();
}
}
五、文档上传 & 向量入库 Service
package com.ai.rag.service;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.document.Document;
import org.springframework.ai.document.DocumentReader;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Service
@RequiredArgsConstructor
public class DocumentVectorService {
private final VectorStore vectorStore;
// 文本分片器:按token切割长文档,适配模型上下文窗口
private final TokenTextSplitter textSplitter = new TokenTextSplitter(800, 150, 5, 10000);
/**
* 上传文档写入向量库
*/
public void uploadAndVector(MultipartFile file) throws Exception {
DocumentReader reader;
String fileName = file.getOriginalFilename();
if (fileName.endsWith(".pdf")) {
// PDF解析
reader = new PagePdfDocumentReader(file.getResource());
} else {
// TXT/MD/Word通用解析
reader = new TikaDocumentReader(file.getResource());
}
// 读取原始文档
List originDocs = reader.get();
// 文档分段
List splitDocs = textSplitter.apply(originDocs);
// 批量写入向量库(自动向量化)
vectorStore.add(splitDocs);
}
/**
* 清空向量知识库
*/
public void clearVectorStore() {
vectorStore.deleteAll();
}
}
六、接口 Controller(文件上传、问答、流式问答)
package com.ai.rag.controller;
import com.ai.rag.service.DocumentVectorService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/ai/rag")
@RequiredArgsConstructor
public class RagController {
private final ChatClient ragChatClient;
private final DocumentVectorService documentVectorService;
@PostMapping("/upload")
@Operation(summary = "上传知识库文档(PDF/TXT/MD/Word)")
public String uploadDoc(@RequestParam("file") MultipartFile file) throws Exception {
documentVectorService.uploadAndVector(file);
return "文档上传并向量化入库成功:" + file.getOriginalFilename();
}
@DeleteMapping("/clear")
@Operation(summary = "清空全部知识库向量数据")
public String clearDoc() {
documentVectorService.clearVectorStore();
return "知识库已清空";
}
@GetMapping("/chat")
@Operation(summary = "RAG知识库同步问答")
public String chat(
@Parameter(description = "提问内容") @RequestParam String question
) {
return ragChatClient.prompt()
.user(question)
.call()
.content();
}
@GetMapping(value = "/stream/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@Operation(summary = "RAG流式问答(SSE打字机)")
public Flux streamChat(@RequestParam String question) {
return ragChatClient.prompt()
.user(question)
.stream()
.content();
}
}
七、前置环境准备
启动 Redis:本地 Redis 6.0+,无密码直接启动
启动 Ollama
# 拉取通义千问7b模型
ollama pull qwen:7b
# 启动Ollama(默认11434端口)
ollama serve
准备测试文档:新建知识库.txt写入测试文本,例如:
Spring AI是Spring官方推出的Java大模型应用开发框架,支持RAG知识库、FunctionCall工具调用、多模型适配。
RAG全称检索增强生成,用来解决大模型幻觉、私有数据问答问题。
八、测试步骤
启动 SpringBoot 项目,访问接口文档:http://127.0.0.1:8080/doc.html
调用/ai/rag/upload上传知识库.txt
调用问答接口提问:Spring AI是什么,模型会读取文档回答
提问无关内容(例如:今天天气),模型返回:暂无相关知识库资料,无法解答该问题
九、扩展优化点
元数据过滤:上传文档时绑定业务分类,检索时按分类过滤向量;
对话记忆:添加MessageChatMemoryAdvisor实现多轮对话;
文档去重:新增 MD5 文档指纹,避免重复入库;
向量库切换:替换为 Milvus/PGVector 适配生产环境;
文档异步向量化:MQ 异步处理大文件分片入库,防止接口超时;
重排序 Rerank:增加 Rerank 模型对召回文档二次排序,提升问答精度。
上一篇
BeanUtils.copyProperties 使用说明
道德经与易经
Spring AI 应用框架