Spring AI 实战笔记:两种内置 Advisor 快速实现 RAG 检索增强
前言
之前手写 RAG 总要自己写向量检索、手动拼接 Prompt、处理空上下文等逻辑,重复且容易出问题。Spring AI 官方提供了封装好的 Advisor 组件,基于 ChatClient 的拦截机制,几行配置就能落地一套完整的 RAG 流程。
本文基于 Spring AI 1.0.0-SNAPSHOT 版本,搭配 DeepSeek 大模型与内存向量库,演示 QuestionAnswerAdvisor 与 RetrievalAugmentationAdvisor 两种官方 RAG 实现方式,附完整代码、原理解析与踩坑总结。
一、项目环境与依赖
1. 基础环境
- Spring Boot 3.5.3
- JDK 17
- Spring AI 1.0.0-SNAPSHOT
- 底层模型:DeepSeek 对话模型 + Embedding 向量模型
2. pom.xml 核心依赖
通过 BOM 统一管理 Spring AI 版本,两个 RAG Advisor 分属不同依赖包,注意不要漏导。
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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.3</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>SpringAIRAGWithAdvisor</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<!-- Spring AI 版本统一管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- DeepSeek 模型启动器:自动装配 ChatModel + EmbeddingModel -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-deepseek</artifactId>
</dependency>
<!-- QuestionAnswerAdvisor 所属依赖包 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<!-- RetrievalAugmentationAdvisor 所属依赖包(RAG 核心抽象) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
</dependencies>
<!-- SNAPSHOT 版本仓库 -->
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases><enabled>false</enabled></releases>
</repository>
<repository>
<id>central-portal-snapshots</id>
<name>Central Portal Snapshots</name>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</project>
3. 必补配置:application.yml
代码中通过构造器注入的 EmbeddingModel 和 DeepSeekChatModel 都依赖自动装配,必须在配置文件中填写 API 信息,否则启动会报 Bean 找不到。
yaml
spring:
ai:
deepseek:
api-key: 你的 DeepSeek API Key
base-url: https://api.deepseek.com
chat:
options:
model: deepseek-chat
embedding:
options:
model: deepseek-embedding
二、核心概念扫盲
1. Advisor 拦截机制
Spring AI 的 ChatClient 提供了类似 Spring MVC Interceptor 的 Advisor 机制,可以在大模型请求发起前、响应返回后做切面增强。
RAG 的本质就是一个前置拦截器:
- 拦截用户提问
- 去向量库检索相关文档
- 将文档拼入提问/系统提示
- 把增强后的请求发给大模型
官方把这套流程封装成了专门的 RAG Advisor,不用我们手写拼接逻辑。
2. 两种 RAG Advisor 对比
很多人容易搞混这两个类,直接上核心差异:
| 对比项 | QuestionAnswerAdvisor | RetrievalAugmentationAdvisor |
|---|---|---|
| 所属依赖 | spring-ai-advisors-vector-store |
spring-ai-rag |
| 定位 | 高度封装的开箱即用问答RAG | 模块化可定制的RAG增强器 |
| 内部结构 | 内置检索逻辑 + 内置QA提示词模板 | 拆分为「文档检索器」+「查询增强器」,可独立替换 |
| 定制能力 | 弱,仅支持调整检索参数 | 强,可自定义检索逻辑、查询改写、上下文拼接规则 |
| 适用场景 | 快速Demo、简单知识库问答 | 生产级定制化RAG、需扩展重排/多轮改写的场景 |
三、完整代码实现
1. 向量库初始化:启动写入测试数据
使用 Spring AI 自带的 SimpleVectorStore 内存向量库,无需额外部署中间件,适合本地演示。项目启动时自动写入测试文档并完成向量化。
java
package com.qcby.springairagwithadvisor.config;
import jakarta.annotation.PostConstruct;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class VectorStoreInitializer {
private final VectorStore vectorStore;
public VectorStoreInitializer(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
@PostConstruct
public void init() {
System.out.println("初始化向量数据,写入到 SimpleVectorStore 内存中...");
List<Document> docs = List.of(
new Document("Spring AI 是一个开源 AI 集成项目"),
new Document("Milvus 是一款高性能向量数据库"),
new Document("DeepSeek 是一个开源大语言模型")
);
vectorStore.add(docs);
System.out.println("SimpleVectorStore 初始化完成,已写入 " + docs.size() + " 条文档。");
}
}
知识点补充:
Document是 Spring AI 中文本的最小单元,包含内容、元数据、唯一IDvectorStore.add()会自动调用EmbeddingModel生成向量,再存入向量库SimpleVectorStore是纯内存实现,服务重启数据会丢失,生产请替换为 Milvus/PGVector
2. AI 核心配置类:两种 Advisor 装配
这是整个项目的核心,分别配置向量库、两种 RAG Advisor 以及 ChatClient。
java
package com.qcby.springairagwithadvisor.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.generation.augmentation.ContextualQueryAugmenter;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AIConfig {
private final EmbeddingModel embeddingModel;
public AIConfig(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
/**
* 内存向量库
*/
@Bean
public VectorStore vectorStore() {
return SimpleVectorStore.builder(embeddingModel).build();
}
/**
* 方式一:QuestionAnswerAdvisor - 开箱即用问答型RAG
*/
@Bean
public QuestionAnswerAdvisor questionAnswerAdvisor(VectorStore vectorStore) {
return QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder()
.similarityThreshold(0.5d) // 相似度阈值,过滤低相关文档
.topK(6) // 返回最相关的前6条
.build())
.build();
}
/**
* 方式二:RetrievalAugmentationAdvisor - 模块化可定制RAG
*/
@Bean
public RetrievalAugmentationAdvisor retrievalAugmentationAdvisor(VectorStore vectorStore) {
// 1. 文档检索器:负责向量相似度搜索
VectorStoreDocumentRetriever retriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.5)
.topK(6)
.build();
// 2. 查询增强器:负责把检索到的上下文拼入用户提问
ContextualQueryAugmenter augmenter = ContextualQueryAugmenter.builder()
.allowEmptyContext(true) // 无匹配文档时不报错,正常放行
.build();
return RetrievalAugmentationAdvisor.builder()
.documentRetriever(retriever)
.queryAugmenter(augmenter)
.build();
}
/**
* 聊天客户端:配置默认系统提示
*/
@Bean
public ChatClient chatClient(DeepSeekChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultSystem("你是一个助手,回答用户问题时不要提及回复是从上下文信息中获取的," +
"不要回答你不知道的问题,如果你不知道答案,就回答:抱歉,我不清楚这个问题。")
.build();
}
}
关键知识点:
- QuestionAnswerAdvisor:内部自带了一套标准的 QA Prompt 模板,会自动把检索到的文档作为上下文注入系统提示,开发者完全不用管 Prompt 拼接。
- RetrievalAugmentationAdvisor :Spring AI 新 RAG 模块的标准抽象,把「检索」和「增强」拆成了独立组件:
DocumentRetriever可替换:支持混合检索、自定义重排策略QueryAugmenter可替换:支持查询改写、多轮上下文压缩等高级玩法
similarityThreshold:余弦相似度阈值,取值 0~1,阈值越高召回越精准但容易漏内容,需要根据模型调优。
3. 接口层:两种 RAG 效果对比
写两个测试接口,分别挂载不同的 Advisor,直观对比两种实现的效果。
java
package com.qcby.springairagwithadvisor.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
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.List;
@RestController
@RequestMapping("/ai")
public class RagController {
@Autowired
private ChatClient chatClient;
@Autowired
private QuestionAnswerAdvisor qaAdvisor;
@Autowired
private RetrievalAugmentationAdvisor ragAdvisor;
/**
* 方式一:QuestionAnswerAdvisor
*/
@GetMapping("/chat1")
public String ask1(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.advisors(List.of(qaAdvisor))
.call()
.content();
}
/**
* 方式二:RetrievalAugmentationAdvisor
*/
@GetMapping("/chat2")
public String ask2(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.advisors(List.of(ragAdvisor))
.call()
.content();
}
}
四、效果测试
测试1:知识库内问题
请求:GET /ai/chat1?message=Spring AI是什么
两个接口均返回正确结果:
Spring AI 是一个开源 AI 集成项目。
说明 RAG 检索生效,模型正确读取了向量库中的私有知识。

测试2:知识库外问题
请求:GET /ai/chat2?message=今天北京天气怎么样
返回:
抱歉,我不清楚这个问题。
说明相似度过滤与系统提示生效,模型不会凭空编造答案。
五、踩坑与注意事项
-
依赖不要导错
QuestionAnswerAdvisor不在spring-ai-rag包中,必须单独引入spring-ai-advisors-vector-store,否则会报类找不到。 -
Embedding 模型必须一致
写入向量库和查询时必须使用同一个 Embedding 模型,否则向量空间不匹配,检索完全失效。
-
SimpleVectorStore 仅用于演示
纯内存实现,重启数据丢失,并发能力弱,生产环境务必替换为持久化向量数据库。
-
Advisor 是请求级生效
.advisors()只对当前本次请求生效,不会修改 ChatClient 全局配置;也可以在ChatClient.builder()中通过defaultAdvisors()设置全局默认 RAG。
六、总结
- 快速上手、简单 Demo :选
QuestionAnswerAdvisor,零 Prompt 开发,开箱即用。 - 生产定制、流程扩展 :选
RetrievalAugmentationAdvisor,模块化设计方便后续接入重排、查询改写、多轮记忆等能力。 - Spring AI 的 Advisor 机制把 RAG 从「手写业务逻辑」变成了「配置组件」,大幅降低了落地门槛,也让代码结构更清晰易维护。
