在 AI 应用开发中,大模型常常面临“知识过期”和“不懂私有数据”的痛点,而检索增强生成(RAG)技术正是解决这一问题的核心方案。RAG 能够将大模型与私有知识库结合,让生成的回答更准确、更具针对性。本文将深入拆解 RAG 的技术原理与核心流程,重点讲解其与 Embedding 技术的协同逻辑,并结合智普 AI 实现本地知识库检索的完整实操,帮助大家掌握在 Spring AI 框架中开发 RAG 模块的精髓。
一、什么是 RAG?核心原理与核心价值
(一)RAG 定义
Retrieval-Augmented Generation(RAG)即检索增强生成,是一种结合“检索”与“生成”的 AI 技术。它通过在大模型生成回答前,从外部知识库中检索与用户问题相关的信息,并将这些信息作为上下文传递给大模型,从而让大模型基于外部知识生成更准确、更可靠的回答。
(二)RAG 的核心价值
RAG 的核心价值是为大模型“外接动态知识库”,在不重新训练或微调模型的前提下,低成本解决知识过期、私有数据不可用、模型幻觉与高昂成本四大核心痛点,让生成的回答更准、更新、更合规、也更易于维护。
- 解决知识局限:无需重新训练大模型,即可让其掌握私有数据(如企业文档、专业知识库)或最新信息,有效避免“知识过期”问题。
- 提升回答准确性:基于具体的外部知识生成回答,显著减少大模型“一本正经地胡说八道”(幻觉)的现象。
- 降低开发成本:无需投入海量算力进行模型微调,通过简单的知识库配置即可快速扩展大模型能力。
- 支持灵活更新:外部知识库可独立进行更新,无需改动大模型或应用代码,能够快速适配变化的业务需求。
(三)RAG 与 Embedding 的协同逻辑:语义检索的核心支撑
RAG 技术的核心在于“精准检索”,而 Embedding 技术是实现这一目标的关键前提,二者形成了“基础支撑”与“上层应用”的紧密协同关系。
简单来说,Embedding 是 RAG 技术的“语义翻译官”。它将非结构化的文本(知识库片段、用户问题)翻译成机器可理解、可计算的向量语言。如果没有 Embedding 提供的语义量化能力,RAG 就无法实现高效的“检索增强”,只能依赖大模型有限的原生知识库。
二、RAG 的核心流程
RAG 技术的完整流程可分为三个核心阶段,每个阶段都与 Embedding 技术深度协同:
(一)索引阶段:知识库向量化存储
- 将本地知识库(文档、数据库等)解析为文本片段(Chunks),再通过 Embedding 模型将这些片段转换为语义向量,并保存到向量数据库中。
(二)检索阶段:相似文本精准匹配
- 将用户提出的问题通过相同的 Embedding 模型转换为语义向量。然后,在向量数据库中,通过相似度算法(如余弦相似度)计算问题向量与所有文本片段向量的相似度,筛选出 TopK(如 Top2、Top3)个最相似的文本片段。
(三)生成阶段:结合上下文生成回答
将检索到的相关文本片段与用户问题一起作为上下文传递给大模型,辅助其生成准确回答。而这些片段之所以能精准匹配用户问题,其本质是 Embedding 技术保证了“问题语义”与“片段语义”的一致性映射。
下图展示了 AI 系统基于 RAG 处理文档并回答用户问题的完整流程图:

三、实操准备:环境配置(基于 Spring AI + 智普 AI)
(一)准备工作
需要提前完成智普 AI 账号注册与 API Key 的获取,并创建一个 Spring Boot 项目。
1. 创建 Spring Boot 项目
- 项目名称:Weiz-SpringAI-RAG
- 核心配置:JDK 17、Spring Boot 3.5.0、Maven
- 依赖选择:Spring Web(后续通过 pom.xml 补充 Embedding 相关依赖)
项目结构如下:
Weiz-SpringAI-RAG/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── weizspringai/
│ │ │ ├── WeizSpringAiRAGApplication.java
│ │ │ ├── controller/
│ │ │ └── service/
│ │ └── resources/
│ └── test/
└── pom.xml
2. 配置 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>com.example</groupId>
<artifactId>Weiz-SpringAI</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>Weiz-SpringAI-RAG</artifactId>
<name>Weiz-SpringAI-RAG</name>
<description>Weiz-SpringAI-RAG</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<!-- spring-ai-client-chat 中包括 TokenTextSplitter、TextReader、Document 等工具 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-client-chat</artifactId>
<version>${spring-ai.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3. application.properties 配置
# 应用名称
spring.application.name=Weiz-SpringAI-RAG
# 服务端口
server.port=8080
# 智普 AI 基础配置
spring.ai.zhipuai.api-key=你的智普 AI API Key
spring.ai.zhipuai.base-url=https://open.bigmodel.cn/api/paas
# Embedding 模型配置(用于文本向量化)
spring.ai.zhipuai.embedding.options.model=embedding-2
# Chat 模型配置(用于生成回答)
spring.ai.zhipuai.chat.options.model=GLM-4-Flash
注意,需将“你的智普 AI API Key”替换为实际获取的密钥。
(二)准备本地知识库文件
在 src/main/resources 目录下创建 户外旅行安全指南.txt ,作为本地知识库,内容如下:
户外旅行安全指南
----
1.露营安全
- 选址:避开低洼积水区、陡坡和可能落石的区域,优先选择平坦硬质地面。
- 防火:远离干草、枯枝等易燃物,使用炉具时保持通风,睡前彻底熄灭明火。
- 防虫:携带驱蚊液、防虫网,避免在草丛密集处搭建帐篷,睡前检查帐篷内是否有虫类。
- 应急:随身携带手电筒、急救包和足够的饮用水,提前下载离线地图。
----
2.徒步安全
- 路线规划:提前查询路线难度、天气情况,选择与自身体能匹配的路线,告知亲友行程。
- 装备要求:必须穿防滑登山鞋、戴防晒帽,携带充足食物和水,配备登山杖和护膝。
- 环境应对:遇到暴雨立即寻找高地躲避,避免涉险过河;遭遇野生动物保持冷静,切勿投喂或驱赶。
- 体能管理:保持匀速前进,每小时休息 10-15 分钟,避免过度疲劳。
----
3.城市漫游安全
- 交通:骑行遵守交通规则,不逆行、不闯红灯,佩戴安全头盔;乘坐公共交通保管好个人财物。
- 选址:避开偏僻小巷和治安较差区域,优先选择人流密集的商业街区和景点。
- 应急:保存当地派出所、医院的联系方式,携带少量现金备用,手机保持电量充足。
四、实操案例:RAG 本地知识库检索完整实现
本案例将实现 RAG 的全流程:加载本地知识库并向量化、接收用户问题并检索相似文本、结合上下文生成回答。
1. 核心工具类:复用相似度计算逻辑
可以复用上一篇文章中的 SimilarityCalculator.java 类,该类封装了余弦相似度、欧氏距离等多种主流算法,支持 RAG 检索阶段的相似度计算。
2. 编写 RagService
创建 com.example.weizspringai.service.RagService 类,整合索引、检索、生成三个RAG 核心逻辑:
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@Service
public class RagService {
// Embedding 模型(文本向量化)
private final EmbeddingModel embeddingModel;
// Chat 模型(生成回答)
private final ChatClient chatClient;
// 本地知识库文本片段
private final List<String> docChunks = new ArrayList<>();
// 文本片段对应的向量
private final List<float[]> docVectors = new ArrayList<>();
// 相似度算法(默认余弦相似度,可根据需求修改)
private final EmbeddingService.SimilarityAlgorithm similarityAlgorithm = EmbeddingService.SimilarityAlgorithm.COSINE;
// 构造方法注入依赖,初始化知识库(索引阶段)
public RagService(EmbeddingModel embeddingModel, ChatClient.Builder chatClientBuilder) throws IOException {
this.embeddingModel = embeddingModel;
this.chatClient = chatClientBuilder.build();
// 加载本地知识库文件并切分片段
loadAndSplitDocument();
}
/**
* 加载本地知识库文件,切分为文本片段(索引阶段第一步)
*/
private void loadAndSplitDocument() throws IOException {
// 读取 resources 目录下的知识库文件
Resource resource = new ClassPathResource("户外旅行安全指南.txt");
String content = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
// 按 "----" 切分文本(根据文件格式自定义切分规则)
String[] chunks = content.split("----");
for (String chunk : chunks) {
String cleanChunk = chunk.strip();
if (!cleanChunk.isBlank()) {
docChunks.add(cleanChunk);
// 文本片段向量化并缓存(索引阶段第二步、第三步)
docVectors.add(embeddingModel.embed(cleanChunk));
}
}
}
/**
* 处理用户提问,返回 RAG 增强后的回答(检索+生成阶段)
* @param question 用户问题
* @return 大模型生成的回答
*/
public String answer(String question) {
// 1. 用户问题向量化(检索阶段第一步)
float[] questionVector = embeddingModel.embed(question);
// 2. 检索 Top2 最相似的文本片段(检索阶段第二步、第三步)
List<String> topRelevantChunks = retrieveTopRelevantChunks(questionVector, 2);
// 3. 构建上下文(生成阶段第一步)
String context = String.join("\n---\n", topRelevantChunks);
// 4. 构建提示词(生成阶段第二步)
String prompt = String.format(
"以下是户外旅行安全指南的知识:\n%s\n请基于上述知识,简洁明了地回答问题:%s",
context, question
);
// 5. 调用 Chat 模型生成回答(生成阶段第三步)
return chatClient.prompt()
.system("你是户外旅行安全助手,仅基于提供的上下文回答问题,不添加额外信息。")
.user(prompt)
.call()
.content();
}
/**
* 检索 TopK 最相似的文本片段(检索阶段核心逻辑)
* @param questionVector 用户问题向量
* @param topK 返回前 K 个相似片段
* @return TopK 相似文本片段
*/
private List<String> retrieveTopRelevantChunks(float[] questionVector, int topK) {
List<ChunkSimilarity> similarityList = new ArrayList<>();
// 计算问题向量与所有文本片段向量的相似度(使用指定算法)
for (int i = 0; i < docVectors.size(); i++) {
double sim = calculateSimilarity(questionVector, docVectors.get(i));
similarityList.add(new ChunkSimilarity(i, sim));
}
// 按相似度降序排序,取前 topK 个
similarityList.sort((a, b) -> Double.compare(b.similarity, a.similarity));
return similarityList.stream()
.limit(topK)
.map(item -> docChunks.get(item.index))
.toList();
}
/**
* 相似度计算(调用工具类,支持算法切换)
*/
private double calculateSimilarity(float[] a, float[] b) {
return switch (similarityAlgorithm) {
case COSINE -> SimilarityCalculator.cosineSimilarity(a, b);
case EUCLIDEAN -> SimilarityCalculator.euclideanSimilarity(a, b);
case PEARSON -> SimilarityCalculator.pearsonCorrelation(a, b);
case MANHATTAN -> SimilarityCalculator.manhattanSimilarity(a, b);
default -> SimilarityCalculator.cosineSimilarity(a, b); // 默认 fallback 到余弦相似度
};
}
/**
* 辅助类:存储文本片段索引与相似度
*/
private static class ChunkSimilarity {
int index;
double similarity;
ChunkSimilarity(int index, double similarity) {
this.index = index;
this.similarity = similarity;
}
}
}
3. 编写 RagController
创建 com.example.weizspringai.controller.RagController 类,提供 RAG 检索接口:
import com.example.springaiembedding.service.RagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/rag")
public class RagController {
@Autowired
private RagService ragService;
/**
* RAG 本地知识库检索接口
* @param question 用户问题
* @return 包含问题与回答的响应
*/
@GetMapping("/ask")
public Map<String, String> ask(@RequestParam("question") String question) {
String answer = ragService.answer(question);
return Map.of(
"question", question,
"answer", answer
);
}
}
4. 测试 RAG 本地知识库检索
- 启动 Weiz-SpringAI-Rag 项目,浏览器访问:
http://localhost:8080/rag/ask?question=露营选址有什么安全要求?。
- 响应结果如下:
{
"question": "露营选址有什么安全要求?",
"answer": "露营选址需避开低洼积水区、陡坡和可能落石的区域,优先选择平坦硬质地面,同时要远离干草、枯枝等易燃物,避免在草丛密集处搭建帐篷。"
}
再测试其他问题,如 http://localhost:8080/rag/ask?question=徒步时遇到暴雨该怎么办? ,响应:
{
"question": "徒步时遇到暴雨该怎么办?",
"answer": "徒步遇到暴雨时,应立即寻找高地躲避,避免涉险过河,同时注意远离陡坡和可能落石的区域,确保自身安全。"
}
测试结果表明,大模型能够基于本地知识库文件的内容生成准确回答,验证了 RAG 技术的核心价值。
五、RAG 优化思路(为后续进阶铺垫)
当前 RAG 实现是一个基础版本,存在一些可优化点,为后续生产级应用铺垫思路:
-
文本切分策略优化
当前按固定符号切分,可优化为按 Token 数量切分(如每段 400-800 字符),或使用语义分割模型,避免语义断裂,保证块内信息的完整性。
-
向量数据库集成
当前使用内存缓存向量,仅适用于小型知识库。生产环境需替换为 Milvus、Pinecone、Redis 或 PostgreSQL(pgvector)等专业向量数据库,以支持海量数据的高效存储与检索。
-
相似度阈值过滤
在检索阶段,可以设置一个相似度阈值(如 0.7)。仅保留相似度高于此阈值的文本片段作为上下文,避免引入低相关性的噪声信息,影响回答质量。
-
上下文扩展
检索到最相关的核心片段后,可以同时获取其前后相邻的文本片段,以提供更完整的背景信息,提升生成答案的语义连贯性和丰富度。
-
引入 Spring AI 开箱即用 RAG 组件
Spring AI 框架提供了如 VectorStore、RetrievalAugmentor 等更高级的抽象和开箱即用的 RAG 组件。这些组件可以大幅简化开发流程,内置了自动化的文档加载、索引、检索优化和提示词工程等功能,更能适应生产级复杂场景的需求。
-
算法动态选择
根据知识库的具体类型(如短文本问答、长篇专业文档、稀疏特征数据),可以设计策略自动匹配最优的相似度算法。例如,处理专业文档时优先使用皮尔逊相关系数,而处理稀疏向量时则考虑杰卡德相似度。
总结
本文深入解析了 RAG 技术的核心原理、工作流程,重点厘清了其与 Embedding 技术的协同逻辑,并通过 Spring AI 结合智普 AI 实现了 RAG 本地知识库检索的完整案例。RAG 技术通过“检索外部知识 + 增强生成能力”的模式,有效解决了大模型的知识局限问题。而 Embedding 技术提供的语义向量化能力,无疑是 RAG 实现精准检索的核心基石。
核心结论如下:
- RAG 的核心价值在于“无需微调,快速扩展大模型能力”,非常适配私有数据、最新知识等动态场景。
- Embedding 是 RAG 的“语义基础”,其生成的向量质量直接决定了检索阶段的精准度,进而对最终回答的准确性产生决定性影响。
- 基础版 RAG 实现相对简单,但若要应用于生产环境,必须关注文本切分、向量数据库集成、检索算法优化等关键点,以全面提升系统的稳定性、效率与准确性。
后续我们将针对这些优化点展开更详细的讲解,帮助大家构建健壮、高效的生产级 RAG 应用。如果你想深入探讨更多 AI 与开发技术,欢迎来 云栈社区 交流分享。