第十二章 RAG 检索增强生成技术
版本标注
- Spring AI:
1.1.2- Spring AI Alibaba:
1.1.2.0章节定位
- 本章的
RetrievalAugmentationAdvisor + VectorStore仍然是经典 RAG 入门方案。- 但 Spring AI Alibaba
1.1.2.x官方代码已经进一步演进到 RAG Workflow 思路,典型流程是:Query -> Rewrite -> Retrieve -> Prepare -> Agent -> Response。- 因此,本章建议理解为“基础版 RAG”;复杂业务更推荐升级为 Graph/Workflow 版本的 RAG。
s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > [ s12 ] s13 > s14 > s15 > s16 > s17 > s18
"先查资料, 再作回答" -- RAG 的核心不是更会编, 而是更少胡说。
一、为什么需要 RAG?
1.1 AI 的知识局限
AI 大模型虽然很强,但它有以下局限:
- 知识有时效性:训练数据截止某个时间点,之后的事不知道
- 专业知识缺乏:某些垂直领域的知识可能不准确
- 企业内部信息:它不知道你公司的业务和数据
1.2 传统解决方式
微调(Fine-tuning) :让 AI 重新训练
- 缺点:成本高、需要大量数据、时间长
- 适合:通用知识需要调整的场景
1.3 RAG 的诞生
RAG(Retrieval-Augmented Generation,检索增强生成) 的核心思想是:
"不改变 AI 的基础能力,而是在它回答问题时,先去知识库查找相关信息,然后把信息连同问题一起发给 AI"
传统方式:
用户 ──→ AI ──→ 直接回答(AI靠记忆)
RAG方式:
用户 ──→ 向量搜索 ──→ 知识库查找相关信息 ──→
──→ 把"问题+找到的信息"一起发给 AI ──→ AI结合信息回答
二、RAG 工作流程
2.0 工作流化的 RAG 思路
在很多入门教程里,我们通常把 RAG 理解成:
- 用户提问
- 向量检索
- 把检索结果塞进 Prompt
- 调用 LLM 回答
这条链路没有问题,但在 Spring AI Alibaba 1.1.2.x 的官方 workflow 示例中,RAG 已经进一步升级成更可控的多步骤流程:
Query -> Rewrite -> Retrieve -> Prepare -> Agent -> Response
各步骤的含义如下:
- Rewrite:先让模型把原始问题改写成更适合检索的查询语句
- Retrieve:基于改写后的查询做向量检索
- Prepare:把命中的文档、用户问题、约束条件整理成更稳定的上下文
- Agent:再交给
ReactAgent或普通聊天模型生成最终答案
这种做法的好处是:
- 检索命中率通常更高
- Prompt 注入更清晰
- 更容易做调试、观测和节点拆分
- 后续更容易迁移到
Graph和工作流编排
所以你可以把本章先学成“基础 RAG”,再进一步理解成可拆分、可编排的工作流化 RAG。
2.1 完整的 RAG 流程
┌─────────────────────────────────────────────────────────────┐
│ RAG 完整流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 阶段一:数据准备(离线) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 文档集合 │───→│ 文本分块 │───→│ 向量化 │───→存入向量库│
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 阶段二:问答推理(在线) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 用户问题 │───→│ 向量化 │───→│ 相似度搜索│───→获取相关 │
│ └──────────┘ └──────────┘ └──────────┘ 文档 │
│ ↓ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 构建Prompt│←── │ 拼接上下文│←── │ 注入知识 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↓ │
│ ┌──────────┐ │
│ │ 调用LLM │ │
│ └──────────┘ │
│ ↓ │
│ 返回结合知识后的答案 │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 本章场景:运维故障查询
这一章不是直接让大模型“凭空回答运维问题”,而是先给它准备一份本地知识资料,再通过 RAG 的方式让它去查资料后回答。
这份资料就放在项目的 resources 目录下,文件名通常叫:
ops.txt
你可以把它理解成一份简化版的“运维故障知识库”。里面会提前写好一些故障编码及对应说明,例如:
- 故障编码:
A0001 - 故障编码:
C2222 - 对应解释:存储系统异常、网络不通、服务不可用等
也就是说,本章真正要做的事情不是“训练一个懂运维的大模型”,而是:
- 先把
ops.txt里的故障资料读出来 - 将这些文本切分、向量化并存入向量数据库
- 用户提问时,先去向量库里检索最相关的故障说明
- 再把检索结果和用户问题一起交给大模型生成答案
这样一来,用户在调用接口时,不需要自己知道完整故障说明,只需要问类似:
A0001 是什么故障?C2222 怎么处理?网络不通对应哪个故障编码?
系统就能先从 ops.txt 这份知识资料里找到相关内容,再让 AI 组织成更自然的回答。
所以这一章的场景,准确地说应该是:
基于
resources/ops.txt构建一个小型运维知识库,然后通过 RAG 实现“查故障码、问故障原因、做运维问答”的效果。
三、项目代码详解
3.1 配置类
package com.atguigu.study.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SaaLLMConfig
{
/**
* 注册 Qwen 的 ChatClient
*/
@Bean("qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("dashScopeChatModel") ChatModel chatModel)
{
return ChatClient.builder(chatModel).build();
}
/**
* 注入已经自动配置好的 VectorStore
*/
@Bean
public RagService ragService(ChatClient qwenChatClient, VectorStore vectorStore)
{
return new RagService(qwenChatClient, vectorStore);
}
}
上面这段代码想表达的重点不是“必须手写某一种向量库实现”,而是:
EmbeddingModel负责文本向量化VectorStore负责向量检索ChatClient + Advisor负责把检索结果注入到问答链路中
如果你选择 Redis、Milvus、PGVector 或其他实现,核心思路都一样。
3.2 RAG 控制器
package com.atguigu.study.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* RAG 控制器
* 展示如何使用检索增强生成来回答专业问题
*/
@RestController
public class RagController
{
@Resource(name = "qwenChatClient")
private ChatClient chatClient;
// 注入已配置的向量数据库
@Resource
private VectorStore vectorStore;
/**
* RAG 问答接口
*
* 接口:http://localhost:8012/rag4aiops?msg=00000
* 接口:http://localhost:8012/rag4aiops?msg=C2222
*
* 测试步骤:
* 1. 先调用 add 接口(如果没有历史数据)
* 2. 再调用 rag4aiops 接口询问故障码
*
* @param msg 用户的故障编码查询
* @return AI 结合知识库返回的答案
*/
@GetMapping("/rag4aiops")
public Flux<String> rag(String msg)
{
// 1. 定义系统提示词
// 告诉 AI 它的角色是"运维工程师",按照知识库中的编码给出解释
String systemInfo = """
你是一个运维工程师,按照给出的编码给出对应故障解释,否则回复找不到信息。
""";
// 2. 创建检索增强Advisor
// 这是 RAG 的核心组件!
// - VectorStoreDocumentRetriever 负责从向量数据库中检索相关内容
// - RetrievalAugmentationAdvisor 负责把检索结果注入到Prompt中
RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor.builder()
// 指定使用向量数据库进行检索
.documentRetriever(
VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.build()
)
.build();
// 3. 构建并发送请求
// 在 .advisors() 中添加 RAG Advisor
// 它会自动执行:检索 → 注入 → 调用AI → 返回结果
return chatClient
.prompt()
.system(systemInfo)
.user(msg)
.advisors(advisor) // 关键:添加RAG增强
.stream()
.content();
}
}
四、RAG 的核心组件
4.1 RetrievalAugmentationAdvisor
这是 Spring AI 提供的 RAG 增强组件,它的作用:
- 拦截用户请求
- 从向量数据库检索相关信息
- 将检索结果注入到 Prompt 中
- 调用 AI,让它基于检索结果回答
- 返回最终答案
4.2 DocumentRetriever
文档检索器,负责:
- 将用户问题转为向量
- 在向量数据库中执行相似度搜索
- 返回匹配度最高的文档
五、本章小结
5.1 核心概念
| 概念 | 说明 |
|---|---|
| RAG | 检索增强生成,让AI结合知识库回答问题 |
| VectorStore | 向量数据库,存储文档的向量 |
| RetrievalAugmentationAdvisor | RAG核心组件,自动检索+注入 |
| DocumentRetriever | 从向量数据库检索文档的组件 |
5.2 RAG 工作流程
提问 → 向量化 → 相似度搜索 → 提取相关文档 → 注入Prompt → 调用AI → 返回答案
5.3 应用场景
- 企业内部知识问答
- 产品手册查询
- 客服问答系统
- 专业领域知识库
本章重点:
- 理解 RAG 的核心原理
- 掌握 RetrievalAugmentationAdvisor 的使用
- 理解 RAG 在实际场景中的应用
下章剧透(s13):
学会了 RAG 技术后,下一章我们将学习 Tool Calling(工具调用)——让 AI 能够"调用外部函数"来完成真实任务!
📝 编辑者:Flittly
📅 更新时间:2026年4月
🔗 相关资源:Spring AI RAG 官方文档