目录 一、RAG 是什么 RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索和文本生成的技术。简单说,就是先检索相关文档,再把文档内容作为上下文,让 AI 基于这些内容生成回答。
传统 AI 的问题:
知识有截止日期(训练数据的时间点)
无法获取实时信息
可能产生幻觉(编造信息)
RAG 的优势:
准确性提升 :通过检索真实文档,提供更准确的答案
知识更新 :可以检索最新的文档,保持知识更新
减少幻觉 :基于真实文档生成,减少错误信息
可解释性 :可以展示检索到的文档,提高可解释性
RAG 的应用场景:
知识问答 :基于文档库进行问答
文档摘要 :基于文档生成摘要
智能客服 :基于知识库进行客服问答
代码生成 :基于代码库生成代码
二、RAG 的核心概念 向量(Embedding):
将文本转换为数值向量
语义相似的文本,向量也相似
通过向量相似度检索相关文档
向量数据库(Vector Store):
存储文档向量和元数据
支持相似度检索
常见的有 Milvus、Pinecone、Weaviate 等
检索(Retrieval):
将用户查询转换为向量
在向量数据库中检索相似文档
返回最相关的文档片段
增强生成(Augmented Generation):
将检索到的文档作为上下文
AI 基于上下文生成回答
提高回答的准确性和相关性
三、RAG 工作流程 完整的 RAG 流程:
文档加载 :从各种来源加载文档(文件、数据库、API 等)
文档分割 :将文档分割成小块(chunks),便于检索
向量化 :使用 Embedding 模型将文档块转换为向量
存储 :将向量存储到向量数据库
查询向量化 :将用户查询转换为向量
检索 :在向量数据库中检索相似文档
增强生成 :将检索到的文档作为上下文,生成回答
流程图:
1 2 3 文档 → 分割 → 向量化 → 存储到向量数据库 ↓ 用户查询 → 向量化 → 检索相似文档 → 增强生成 → 回答
四、Spring AI RAG 组件 4.1 DocumentReader 文档读取器,负责从各种来源读取文档。
支持的格式:
文本文件(TXT、MD)
PDF 文件
HTML 页面
数据库
示例:
1 2 3 4 Resource resource = new ClassPathResource("documents/knowledge.txt" ); DocumentReader documentReader = new TextReader(resource); List<Document> documents = documentReader.get();
4.2 TextSplitter 文本分割器,负责将文档分割成小块。
为什么需要分割:
文档可能很长,不适合直接向量化
分割后可以更精确地检索相关片段
提高检索效率
分割策略:
固定大小分割:按固定 token 数或字符数分割
语义分割:按语义边界分割,保持语义完整性
自定义分割:实现自定义分割逻辑
4.3 EmbeddingModel 嵌入模型,负责将文本转换为向量。
配置示例:
1 2 spring.ai.dashscope.embedding.options.model =text-embedding-v4
使用:
1 2 3 4 5 @Autowired private EmbeddingModel embeddingModel; List<Double> embedding = embeddingModel.embed("文档内容" );
4.4 VectorStore 向量存储,负责存储和检索向量。
Spring AI 提供的实现:
SimpleVectorStore:内存向量存储(适合开发测试)
MilvusVectorStore:Milvus 向量数据库
PineconeVectorStore:Pinecone 向量数据库
使用:
1 2 3 4 @Bean public VectorStore vectorStore (EmbeddingModel embeddingModel) { return new SimpleVectorStore(embeddingModel); }
4.5 RetrievalAugmentationAdvisor 检索增强顾问,负责在生成过程中检索相关文档。
工作原理:
拦截用户查询
将查询转换为向量
在向量数据库中检索相似文档
将检索到的文档添加到 Prompt 中
调用 AI 模型生成回答
配置:
1 2 3 4 5 6 7 8 @Bean public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor ( VectorStore vectorStore) { return RetrievalAugmentationAdvisor.builder() .vectorStore(vectorStore) .topK(5 ) .build(); }
五、快速开始 5.1 依赖配置 1 2 3 4 5 6 7 8 9 10 11 <dependency > <groupId > org.springframework.ai</groupId > <artifactId > spring-ai-advisors-vector-store</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud.ai</groupId > <artifactId > spring-ai-alibaba-starter-dashscope</artifactId > </dependency >
5.2 Embedding 模型配置 1 2 3 4 5 spring.ai.dashscope.api-key =sk-your-api-key spring.ai.dashscope.embedding.options.model =text-embedding-v4
支持的 Embedding 模型:
text-embedding-v1:基础版本
text-embedding-v2:增强版本
text-embedding-v4:最新版本(推荐)
5.3 VectorStore 配置 内存向量存储(开发测试):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @SpringBootApplication public class RagApplication { @Bean public VectorStore vectorStore (EmbeddingModel embeddingModel) { return new SimpleVectorStore(embeddingModel); } @Bean public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor ( VectorStore vectorStore) { return RetrievalAugmentationAdvisor.builder() .vectorStore(vectorStore) .topK(5 ) .build(); } }
注意:
SimpleVectorStore 是内存存储,重启后数据丢失
生产环境建议使用专门的向量数据库(如 Milvus)
5.4 文档加载和索引 完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Service public class DocumentService { @Autowired private VectorStore vectorStore; @Autowired private EmbeddingModel embeddingModel; @PostConstruct public void loadDocuments () { Resource resource = new ClassPathResource("documents/knowledge.txt" ); DocumentReader documentReader = new TextReader(resource); List<Document> documents = documentReader.get(); TextSplitter textSplitter = new TokenTextSplitter() .setChunkSize(1000 ) .setChunkOverlap(200 ); List<Document> chunks = textSplitter.split(documents); vectorStore.add(chunks); log.info("文档加载完成,共 {} 个文档块" , chunks.size()); } }
关键点:
chunkSize:每个块的大小,建议 500-2000 token
chunkOverlap:块之间的重叠,避免边界信息丢失
add() 方法会自动进行向量化并存储
5.5 RAG 查询 Controller 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @RestController @RequestMapping("/api/rag") public class RagController { @Autowired private ChatModel chatModel; @Autowired private RetrievalAugmentationAdvisor retrievalAugmentationAdvisor; @GetMapping(value = "/query", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> query (@RequestParam String question) { ChatClient chatClient = ChatClient.builder(chatModel) .defaultSystem("" " 你是一个知识问答助手,请根据检索到的文档回答问题。 如果文档中没有相关信息,请明确说明。 回答时请引用文档来源。 " "" ) .defaultAdvisors(retrievalAugmentationAdvisor) .build(); return chatClient.prompt() .user(question) .stream() .content(); } }
使用示例:
1 GET /api/rag/query?question =Spring AI 是什么?
工作流程:
用户提问:”Spring AI 是什么?”
RetrievalAugmentationAdvisor 拦截查询
将查询转换为向量
在向量数据库中检索相似文档
将检索到的文档添加到 Prompt 中
AI 基于文档内容生成回答
六、文档分割策略 6.1 固定大小分割 按固定大小分割文档,简单直接。
1 2 3 4 5 TextSplitter textSplitter = new TokenTextSplitter() .setChunkSize(1000 ) .setChunkOverlap(200 ); List<Document> chunks = textSplitter.split(documents);
适用场景:
注意事项:
6.2 语义分割 按语义分割文档,保持语义完整性。
1 2 3 4 5 TextSplitter textSplitter = new SemanticTextSplitter() .setChunkSize(1000 ) .setChunkOverlap(200 ); List<Document> chunks = textSplitter.split(documents);
适用场景:
注意事项:
6.3 自定义分割器 实现自定义分割逻辑。
1 2 3 4 5 6 7 8 9 10 public class CustomTextSplitter implements TextSplitter { @Override public List<Document> split (Document document) { List<Document> chunks = new ArrayList<>(); return chunks; } }
适用场景:
七、向量检索策略 7.1 Top-K 检索 返回最相似的 K 个文档。
1 2 3 4 5 6 7 8 @Bean public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor ( VectorStore vectorStore) { return RetrievalAugmentationAdvisor.builder() .vectorStore(vectorStore) .topK(5 ) .build(); }
K 值选择:
太小:可能遗漏相关信息
太大:可能包含不相关信息,增加 token 消耗
建议:3-10 之间
7.2 相似度阈值 设置相似度阈值,只返回相似度高于阈值的文档。
1 2 3 4 5 6 List<Document> documents = vectorStore.similaritySearch( SearchRequest.query("查询内容" ) .withTopK(5 ) .withSimilarityThreshold(0.7 ) );
阈值选择:
太高:可能检索不到文档
太低:可能包含不相关文档
建议:0.6-0.8 之间
7.3 元数据过滤 根据元数据过滤文档。
1 2 3 4 5 6 7 8 9 10 Document document = new Document("内容" , Map.of("category" , "技术文档" )); vectorStore.add(document); List<Document> documents = vectorStore.similaritySearch( SearchRequest.query("查询内容" ) .withTopK(5 ) .withFilterExpression("category == '技术文档'" ) );
适用场景:
八、实际案例 场景: 基于技术文档库进行问答。
文档准备:
1 2 3 4 documents/ ├── spring -ai-basics.txt ├── spring -ai-chatclient.txt └── spring -ai-tools.txt
文档加载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Service public class DocumentService { @Autowired private VectorStore vectorStore; @PostConstruct public void loadDocuments () { List<Document> allDocuments = new ArrayList<>(); Resource resource1 = new ClassPathResource("documents/spring-ai-basics.txt" ); DocumentReader reader1 = new TextReader(resource1); allDocuments.addAll(reader1.get()); Resource resource2 = new ClassPathResource("documents/spring-ai-chatclient.txt" ); DocumentReader reader2 = new TextReader(resource2); allDocuments.addAll(reader2.get()); TextSplitter textSplitter = new TokenTextSplitter() .setChunkSize(1000 ) .setChunkOverlap(200 ); List<Document> chunks = textSplitter.split(allDocuments); vectorStore.add(chunks); log.info("文档加载完成,共 {} 个文档块" , chunks.size()); } }
查询接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @RestController @RequestMapping("/api/rag") public class RagController { @Autowired private ChatModel chatModel; @Autowired private RetrievalAugmentationAdvisor retrievalAugmentationAdvisor; @GetMapping(value = "/query", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> query (@RequestParam String question) { ChatClient chatClient = ChatClient.builder(chatModel) .defaultSystem("" " 你是一个 Spring AI 技术专家,请根据检索到的文档回答问题。 如果文档中没有相关信息,请明确说明。 回答时请引用文档来源。 " "" ) .defaultAdvisors(retrievalAugmentationAdvisor) .build(); return chatClient.prompt() .user(question) .stream() .content(); } }
使用示例:
1 2 用户:ChatClient 怎么使用?AI :[检索相关文档] 根据文档,ChatClient 的使用方式如下...
九、常见问题 9.1 检索不到相关文档 问题: 查询时检索不到相关文档。
原因:
解决:
检查文档是否已加载:查看日志
优化查询语句:使用更具体的关键词
降低相似度阈值:从 0.7 降到 0.6
9.2 检索到不相关文档 问题: 检索到的文档和查询不相关。
原因:
文档分割不合理
Embedding 模型质量不高
Top-K 值太大
解决:
优化文档分割策略:使用语义分割
使用更好的 Embedding 模型
减小 Top-K 值:从 10 降到 5
9.3 生成答案不准确 问题: AI 生成的答案不准确。
原因:
检索到的文档不准确
Prompt 设计不合理
上下文过长
解决:
提高检索质量:优化分割策略、调整 Top-K
优化 Prompt:明确指示 AI 如何使用文档
控制上下文长度:减小 Top-K 或 chunkSize
9.4 性能问题 问题: RAG 查询速度慢。
原因:
向量数据库性能问题
Embedding 模型调用慢
文档数量过多
解决:
使用高性能向量数据库(如 Milvus)
使用本地 Embedding 模型
优化文档数量:只加载必要的文档
9.5 内存占用高 问题: 使用 SimpleVectorStore 内存占用高。
原因:
解决:
生产环境使用专门的向量数据库
减少文档数量
优化文档分割:减小 chunkSize
十、最佳实践 10.1 文档质量 确保文档质量:
准确性 :文档内容准确
完整性 :文档内容完整
时效性 :及时更新文档
10.2 分割策略 选择合适的分割策略:
固定大小 :适合结构化文档
语义分割 :适合非结构化文档
自定义分割 :适合特殊需求
分割参数建议:
chunkSize:500-2000 token
chunkOverlap:100-300 token
10.3 Embedding 模型 选择合适的 Embedding 模型:
中文场景 :使用支持中文的模型
领域场景 :使用领域特定的模型
多语言场景 :使用多语言模型
10.4 向量数据库 选择合适的向量数据库:
开发测试 :SimpleVectorStore(内存)
生产环境 :Milvus、Pinecone、Weaviate 等
10.5 检索策略 优化检索策略:
Top-K 选择 :根据场景选择合适的 K 值(3-10)
相似度阈值 :设置合理的阈值(0.6-0.8)
元数据过滤 :使用元数据提高精度
10.6 Prompt 设计 优化 Prompt 设计:
明确指令 :明确指示 AI 如何使用文档
格式要求 :指定回答格式
引用要求 :要求 AI 引用文档来源
示例:
1 2 3 你是一个知识问答助手,请根据检索到的文档回答问题。 如果文档中没有相关信息,请明确说明。 回答时请引用文档来源,格式:[来源1] [来源2]
十一、总结
RAG 原理 :通过检索相关文档来增强生成过程,提高回答的准确性
核心组件 :DocumentReader、TextSplitter、EmbeddingModel、VectorStore、RetrievalAugmentationAdvisor
工作流程 :文档加载 → 文档分割 → 向量化 → 存储 → 检索 → 增强生成
文档分割 :固定大小分割、语义分割、自定义分割
向量检索 :Top-K 检索、相似度阈值、元数据过滤
配置要点 :Embedding 模型配置、VectorStore 配置、RetrievalAugmentationAdvisor 配置
最佳实践 :文档质量、分割策略、Embedding 模型、向量数据库、检索策略、Prompt 设计
RAG 是 Spring AI 的一个重要功能,可以显著提高 AI 应用的准确性和实用性。在实际项目中,需要根据具体场景选择合适的策略和参数。