文章目录
- [Spring AI 常用 Advisor:ChatClient 增强链路与 RAG 挂载](#Spring AI 常用 Advisor:ChatClient 增强链路与 RAG 挂载)
-
- [一、Advisor 是什么?](#一、Advisor 是什么?)
-
- [1 三种挂载方式](#1 三种挂载方式)
- [二、常用 Advisor 总览](#二、常用 Advisor 总览)
-
- [1 Maven 依赖](#1 Maven 依赖)
- [三、RAG 类 Advisor](#三、RAG 类 Advisor)
-
- [1 QuestionAnswerAdvisor:最简 Naive RAG](#1 QuestionAnswerAdvisor:最简 Naive RAG)
- [2 RetrievalAugmentationAdvisor:模块化 RAG](#2 RetrievalAugmentationAdvisor:模块化 RAG)
- [3 RetrievalRerankAdvisor:检索 + 百炼 Rerank](#3 RetrievalRerankAdvisor:检索 + 百炼 Rerank)
- [4 RAG 三者怎么选?](#4 RAG 三者怎么选?)
- [四、记忆类 Advisor](#四、记忆类 Advisor)
-
- [1 MessageChatMemoryAdvisor](#1 MessageChatMemoryAdvisor)
- [2 VectorStoreChatMemoryAdvisor](#2 VectorStoreChatMemoryAdvisor)
- [五、工具与调试类 Advisor](#五、工具与调试类 Advisor)
-
- [1 ToolCallingAdvisor](#1 ToolCallingAdvisor)
- [2 SimpleLoggerAdvisor](#2 SimpleLoggerAdvisor)
- [六、推理与安全类 Advisor](#六、推理与安全类 Advisor)
-
- [1 ReReadingAdvisor(Re2)](#1 ReReadingAdvisor(Re2))
- [2 SafeGuardAdvisor](#2 SafeGuardAdvisor)
- [七、组合示例:记忆 + RAG](#七、组合示例:记忆 + RAG)
- 八、小结
Spring AI 常用 Advisor:ChatClient 增强链路与 RAG 挂载
技术栈:Java 21 / Spring Boot 4.1 / Spring AI 2.0.0-M1 / spring-ai-alibaba 2.0.0-M1.1。
官方参考:Advisors API · Retrieval Augmented Generation · ChatClient
一、Advisor 是什么?
Advisor 是挂在 ChatClient 上的拦截增强器 :在请求发往 LLM 之前(before)和收到回复之后(after)修改 Prompt / Response。
| 概念 | 说明 |
|---|---|
| Advisor 链 | 多个 Advisor 按 getOrder() 排序,值越小越先执行 before |
ChatClientRequest |
未密封的 Prompt + context Map,Advisor 间可共享状态 |
before / after |
改 Prompt / 改 Response;RAG 类 Advisor 主要在 before 里检索并增强用户消息 |
1 三种挂载方式
| 方式 | API | 适用 |
|---|---|---|
| 单次 | .prompt().advisors(...) |
某次调用才需要增强 |
| 默认 | ChatClient.builder(...).defaultAdvisors(...) |
整个 Client 统一行为 |
| 运行时参数 | .advisors(a -> a.param(key, value)) |
动态 filter、conversationId 等 |
java
// 默认挂载 + 运行时传参
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(qaAdvisor)
.build();
String answer = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "session-001"))
.user("你好")
.call()
.content();
二、常用 Advisor 总览
| Advisor | 来源 | 分类 | 作用 |
|---|---|---|---|
QuestionAnswerAdvisor |
Spring AI | RAG | Naive RAG:VectorStore 检索 → 拼 Prompt |
RetrievalAugmentationAdvisor |
Spring AI | RAG | 模块化 RAG:Query 改写 / 多路检索 / 后处理可拼装 |
RetrievalRerankAdvisor |
spring-ai-alibaba | RAG | 检索 → 百炼 Rerank → 生成 |
MessageChatMemoryAdvisor |
Spring AI | 记忆 | 把历史消息注入 Prompt |
VectorStoreChatMemoryAdvisor |
Spring AI | 记忆 | 从 VectorStore 检索相关历史 |
ToolCallingAdvisor |
Spring AI | 工具 | 自动执行 Function Calling 循环 |
SimpleLoggerAdvisor |
Spring AI | 调试 | 打印 request / response |
ReReadingAdvisor |
Spring AI | 推理 | Re2 重读策略,增强推理 |
SafeGuardAdvisor |
Spring AI | 安全 | 拦截有害内容 |
text
QuestionAnswerAdvisor → 检索 → 拼 Prompt → 生成
RetrievalAugmentationAdvisor → 预处理 → 检索 → 后处理 → 增强 → 生成
RetrievalRerankAdvisor → 检索 → 百炼重排 → 拼 Prompt → 生成
1 Maven 依赖
xml
<!-- RAG:QuestionAnswerAdvisor、VectorStoreChatMemoryAdvisor -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<!-- RAG:RetrievalAugmentationAdvisor -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-rag</artifactId>
</dependency>
<!-- RAG:RetrievalRerankAdvisor -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>2.0.0-M1.1</version>
</dependency>
| 类 | 包名 |
|---|---|
QuestionAnswerAdvisor |
org.springframework.ai.chat.client.advisor.vectorstore |
RetrievalAugmentationAdvisor |
org.springframework.ai.rag.advisor |
RetrievalRerankAdvisor |
com.alibaba.cloud.ai.advisor |
MessageChatMemoryAdvisor |
org.springframework.ai.chat.client.advisor |
ToolCallingAdvisor |
org.springframework.ai.chat.client.advisor |
SimpleLoggerAdvisor |
org.springframework.ai.chat.client.advisor |
ReReadingAdvisor |
需自行实现或引用示例(见官方文档) |
三、RAG 类 Advisor
1 QuestionAnswerAdvisor:最简 Naive RAG
向量检索 → 把文档拼进 Prompt → 调用 LLM。无 Rerank、无 Query 改写。
java
SearchRequest request = SearchRequest.builder()
.topK(5) // 最多返回 5 条文档
.similarityThreshold(0.45) // 相似度下限
.build();
// 单次挂载
String answer = ChatClient.builder(chatModel)
.build()
.prompt()
.user("请基于资料详细解释机器学习") // 用户问题
.advisors(QuestionAnswerAdvisor.builder(vectorStore) // 本次调用才挂载 QA Advisor
.searchRequest(request)
.build())
.call()
.content();
java
// 默认挂载
QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore) // 向量库作为检索源
.searchRequest(SearchRequest.builder().topK(5).similarityThreshold(0.45).build()) // 检索参数
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(qaAdvisor) // 整个 Client 默认走 RAG
.build();
java
// 运行时 metadata 过滤
String answer = chatClient.prompt()
.user("请介绍 Spring AI") // 用户问题
.advisors(a -> a.param(QuestionAnswerAdvisor.FILTER_EXPRESSION, "source == 'doc.md'")) // 只检索 source=doc.md 的文档
.call()
.content();
| Builder 方法 | 说明 |
|---|---|
searchRequest(SearchRequest) |
topK、similarityThreshold、filter |
promptTemplate(PromptTemplate) |
自定义模板,需含 {query}、{question_answer_context} |
2 RetrievalAugmentationAdvisor:模块化 RAG
基于 Modular RAG 架构,Builder 拼装:Query 变换 → DocumentRetriever → DocumentPostProcessor → QueryAugmenter。
Naive RAG:
java
Advisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore) // 检索来源
.similarityThreshold(0.45) // 相似度下限
.topK(5) // 最多 5 条
.build())
.build();
String answer = ChatClient.builder(chatModel)
.build()
.prompt()
.advisors(ragAdvisor) // 挂载模块化 RAG Advisor
.user("什么是机器学习?")
.call()
.content();
允许空检索结果时也回答:
java
Advisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.45)
.topK(5)
.build())
.queryAugmenter(ContextualQueryAugmenter.builder()
.allowEmptyContext(true) // 检索为空时仍允许 LLM 回答
.build())
.build();
Advanced RAG:检索前改写 Query:
java
Advisor ragAdvisor = RetrievalAugmentationAdvisor.builder()
.queryTransformers(RewriteQueryTransformer.builder()
.chatClientBuilder(ChatClient.builder(chatModel).build().mutate()) // 用 LLM 改写 Query
.build())
.documentRetriever(VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.similarityThreshold(0.45)
.topK(5)
.build())
.build();
| Builder 方法 | 说明 |
|---|---|
documentRetriever(...) |
检索来源,常用 VectorStoreDocumentRetriever |
queryTransformers(...) |
检索前改写 Query |
queryExpander(...) |
一扩多 Query |
queryAugmenter(...) |
如何把检索文档拼进 Prompt |
documentPostProcessors(...) |
检索后处理,可在此做 Rerank |
3 RetrievalRerankAdvisor:检索 + 百炼 Rerank
Alibaba 扩展:VectorStore 初检 → DashScope RerankModel 精排 → Prompt → LLM 。详见 RAG检索与Rerank重排序.md。
java
RetrievalRerankAdvisor rerankAdvisor = new RetrievalRerankAdvisor(
vectorStore, // 初检来源
rerankModel, // 百炼 Rerank 模型
SearchRequest.builder().topK(5).similarityThreshold(0.45).build() // 初检参数
);
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(rerankAdvisor) // 默认走 检索→重排→生成
.build();
String answer = chatClient.prompt()
.user("什么是机器学习?") // 实际 query 以 user 消息为准
.call()
.content();
| 构造参数 | 说明 | 默认值 |
|---|---|---|
vectorStore |
初检来源 | --- |
rerankModel |
DashScopeRerankModel |
--- |
searchRequest |
topK、similarityThreshold | 空 SearchRequest |
promptTemplate |
RAG Prompt 模板 | 内置英文模板 |
minScore |
Rerank 得分下限 | 0.1 |
SearchRequest.query为占位,实际以.user("...")为准。
4 RAG 三者怎么选?
| 场景 | 推荐 |
|---|---|
| 快速验证、代码最少 | QuestionAnswerAdvisor |
| Query 改写 / 多路检索 / 空上下文策略 | RetrievalAugmentationAdvisor |
| 初检噪声多,需要百炼 Rerank | RetrievalRerankAdvisor |
四、记忆类 Advisor
多轮对话需要把历史消息注入 Prompt,常用两个 Advisor。
1 MessageChatMemoryAdvisor
从 ChatMemory 读取历史,以 Message 列表 形式追加到 Prompt(保留 user/assistant 结构)。
java
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(20) // 滑动窗口最多保留 20 条消息
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) // 注入对话记忆
.build();
String answer = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "user-123")) // 区分不同用户/会话
.user("我叫小明")
.call()
.content();
| 运行时参数 | 说明 |
|---|---|
ChatMemory.CONVERSATION_ID |
会话 ID,区分不同用户 / 会话 |
2 VectorStoreChatMemoryAdvisor
把对话历史存入 VectorStore,检索时按语义找相关历史注入 system 文本(适合长对话、历史很多)。
需 spring-ai-advisors-vector-store 依赖,与 QuestionAnswerAdvisor 共用 VectorStore 基础设施。
五、工具与调试类 Advisor
1 ToolCallingAdvisor
ChatClient 默认自动注册,负责 Function Calling 循环:模型请求工具 → 执行 → 结果回传 → 直到不再调用工具。
java
// 显式注册工具,ToolCallingAdvisor 自动生效
String answer = ChatClient.builder(chatModel)
.build()
.prompt()
.tools(new DateTimeTools()) // 注册可调用工具
.user("现在几点?") // 模型可能触发工具调用
.call()
.content();
| 配置项 | 说明 | 默认 |
|---|---|---|
spring.ai.chat.client.tool-calling.enabled |
是否自动注册 | true |
spring.ai.chat.client.tool-calling.advisor-order |
链中执行顺序 | HIGHEST_PRECEDENCE + 300 |
禁用自动注册(自行控制工具循环):
java
chatClient.prompt()
.advisors(AdvisorParams.toolCallingAdvisorAutoRegister(false)) // 禁用自动工具循环
.user("...")
.call();
2 SimpleLoggerAdvisor
打印 request / response,调试 Advisor 链和 Prompt 拼装结果。建议放在链末尾。
java
String answer = ChatClient.builder(chatModel)
.build()
.prompt()
.advisors(new SimpleLoggerAdvisor()) // 打印 request/response,便于调试
.user("你好")
.call()
.content();
六、推理与安全类 Advisor
1 ReReadingAdvisor(Re2)
把用户问题重复一遍拼进 Prompt,提升 LLM 推理准确率(论文:Re-Reading Improves Reasoning in LLMs)。
java
// 官方示例为自定义类,核心 before 逻辑:
// augmentedUserText = "{query}\nRead the question again: {query}"
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(new ReReadingAdvisor()) // Re2 重读策略,增强推理
.build();
2 SafeGuardAdvisor
简单内容安全拦截,防止模型生成有害内容(具体规则由实现配置)。
七、组合示例:记忆 + RAG
Advisor 按注册顺序执行;常见生产组合:先记忆,再检索。
java
ChatMemory chatMemory = MessageWindowChatMemory.builder().maxMessages(20).build(); // 对话记忆
QuestionAnswerAdvisor qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().topK(5).similarityThreshold(0.45).build())
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // ① 先注入历史
qaAdvisor, // ② 再检索资料拼 Prompt
new SimpleLoggerAdvisor() // ③ 最后打日志(可选)
)
.build();
String answer = chatClient.prompt()
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "session-001")) // 指定会话
.user("继续上一题,再详细说说迁移学习") // 可引用上文 + 新知识库检索
.call()
.content();
#mermaid-svg-dPAkGLzFONBPV6iw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dPAkGLzFONBPV6iw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dPAkGLzFONBPV6iw .error-icon{fill:#552222;}#mermaid-svg-dPAkGLzFONBPV6iw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dPAkGLzFONBPV6iw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dPAkGLzFONBPV6iw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dPAkGLzFONBPV6iw .marker.cross{stroke:#333333;}#mermaid-svg-dPAkGLzFONBPV6iw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dPAkGLzFONBPV6iw p{margin:0;}#mermaid-svg-dPAkGLzFONBPV6iw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dPAkGLzFONBPV6iw .cluster-label text{fill:#333;}#mermaid-svg-dPAkGLzFONBPV6iw .cluster-label span{color:#333;}#mermaid-svg-dPAkGLzFONBPV6iw .cluster-label span p{background-color:transparent;}#mermaid-svg-dPAkGLzFONBPV6iw .label text,#mermaid-svg-dPAkGLzFONBPV6iw span{fill:#333;color:#333;}#mermaid-svg-dPAkGLzFONBPV6iw .node rect,#mermaid-svg-dPAkGLzFONBPV6iw .node circle,#mermaid-svg-dPAkGLzFONBPV6iw .node ellipse,#mermaid-svg-dPAkGLzFONBPV6iw .node polygon,#mermaid-svg-dPAkGLzFONBPV6iw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dPAkGLzFONBPV6iw .rough-node .label text,#mermaid-svg-dPAkGLzFONBPV6iw .node .label text,#mermaid-svg-dPAkGLzFONBPV6iw .image-shape .label,#mermaid-svg-dPAkGLzFONBPV6iw .icon-shape .label{text-anchor:middle;}#mermaid-svg-dPAkGLzFONBPV6iw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dPAkGLzFONBPV6iw .rough-node .label,#mermaid-svg-dPAkGLzFONBPV6iw .node .label,#mermaid-svg-dPAkGLzFONBPV6iw .image-shape .label,#mermaid-svg-dPAkGLzFONBPV6iw .icon-shape .label{text-align:center;}#mermaid-svg-dPAkGLzFONBPV6iw .node.clickable{cursor:pointer;}#mermaid-svg-dPAkGLzFONBPV6iw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dPAkGLzFONBPV6iw .arrowheadPath{fill:#333333;}#mermaid-svg-dPAkGLzFONBPV6iw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dPAkGLzFONBPV6iw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dPAkGLzFONBPV6iw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dPAkGLzFONBPV6iw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dPAkGLzFONBPV6iw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dPAkGLzFONBPV6iw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dPAkGLzFONBPV6iw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dPAkGLzFONBPV6iw .cluster text{fill:#333;}#mermaid-svg-dPAkGLzFONBPV6iw .cluster span{color:#333;}#mermaid-svg-dPAkGLzFONBPV6iw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dPAkGLzFONBPV6iw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dPAkGLzFONBPV6iw rect.text{fill:none;stroke-width:0;}#mermaid-svg-dPAkGLzFONBPV6iw .icon-shape,#mermaid-svg-dPAkGLzFONBPV6iw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dPAkGLzFONBPV6iw .icon-shape p,#mermaid-svg-dPAkGLzFONBPV6iw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dPAkGLzFONBPV6iw .icon-shape .label rect,#mermaid-svg-dPAkGLzFONBPV6iw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dPAkGLzFONBPV6iw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dPAkGLzFONBPV6iw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dPAkGLzFONBPV6iw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户消息
MessageChatMemoryAdvisor
QuestionAnswerAdvisor / RetrievalRerankAdvisor
SimpleLoggerAdvisor
ChatModel
回答
八、小结
| 需求 | 推荐 Advisor |
|---|---|
| 最简 RAG | QuestionAnswerAdvisor |
| 可拼装 RAG 流水线 | RetrievalAugmentationAdvisor |
| RAG + 百炼 Rerank | RetrievalRerankAdvisor |
| 多轮对话 | MessageChatMemoryAdvisor |
| Function Calling | ToolCallingAdvisor(默认已有) |
| 调试 Prompt | SimpleLoggerAdvisor |