大模型开发 - 10 ChatClient:Advisors API 构建可插拔、可组合的智能对话增强体系
Spring AI Advisors API:构建企业级AI应用的增强引擎 摘要:Spring AI Advisors API提供了一套可插拔的AI增强机制,通过责任链模式实现请求/响应的拦截与处理。核心特性包括:解耦业务逻辑(如记忆、RAG、安全)、组件复用、多模型兼容支持。Advisor分为流式与非流式两类,按优先级顺序执行请求处理(正序)和响应处理(逆序),通过不可变上下文共享状态。内置多种
文章目录
Pre
大模型开发 - 03 QuickStart_借助DeepSeekChatModel实现Spring AI 集成 DeepSeek
大模型开发 - 04 QuickStart_DeepSeek 模型调用流程源码解析:从 Prompt 到远程请求
大模型开发 - 05 QuickStart_接入阿里百炼平台:Spring AI Alibaba 与 DashScope SDK
大模型开发 - 06 QuickStart_本地大模型私有化部署实战:Ollama + Spring AI 全栈指南
大模型开发 - 07 ChatClient:构建统一、优雅的大模型交互接口
大模型开发 - 08 ChatClient:构建智能对话应用的流畅 API
大模型开发 - 09 ChatClient:基于 Spring AI 的多平台多模型动态切换实战
概述
在构建企业级 AI 应用时,我们常常面临这样的挑战:
- 如何在不修改核心逻辑的前提下,为对话系统添加记忆能力?
- 如何无缝集成RAG(检索增强生成) 实现知识库问答?
- 如何统一记录所有 AI 调用日志、监控性能、防止有害输出?
- 如何让同一套代码适配 DeepSeek、Ollama、OpenAI 等不同模型?
Spring AI 的 Advisors API 正是为解决这些问题而生。它借鉴了 Spring AOP 的思想,提供了一套可插拔、可组合、可观察的 AI 增强机制,让你像搭积木一样构建复杂的 AI 应用。
本文将深入剖析 Advisors API 的设计哲学、核心组件、执行流程,并通过 日志记录、Re2 推理增强、RAG 集成 三大实战案例,带你掌握这一强大工具。
一、什么是 Advisors API?
Spring AI Advisors API
提供了一种灵活而强大的方式来拦截、修改和增强 Spring 应用程序中的 AI 驱动交互。通过利用 Advisors API,开发人员可以创建更复杂、可重用和可维护的 AI 组件
Advisors 是 Spring AI 中用于拦截、修改、增强 AI 请求与响应的中间件组件。它们以责任链(Chain of Responsibility) 的形式串联执行,形成一个可扩展的处理管道。
能力 | 说明 |
---|---|
解耦 | 将通用逻辑(如记忆、检索、安全)从业务代码中剥离 |
复用 | 一个 Advisor 可被多个 ChatClient 共享 |
组合 | 多个 Advisor 可自由组合,形成复杂行为 |
可观测 | 自动集成 Micrometer,支持指标与链路追踪 |
模型无关 | 同一套 Advisor 适用于 DeepSeek、Ollama、OpenAI 等 |
可以使用 ChatClient API 配置现有顾问,如以下示例所示:
ChatMemory chatMemory = ... // Initialize your chat memory store
VectorStore vectorStore = ... // Initialize your vector store
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(), // chat-memory advisor
QuestionAnswerAdvisor.builder(vectorStore).build() // RAG advisor
)
.build();
var conversationId = "678";
String response = this.chatClient.prompt()
// Set advisor parameters at runtime
.advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, conversationId))
.user(userText)
.call()
.content();
建议在构建时使用 builder 的 defaultAdvisors()
方法注册advisor。
二、核心组件与执行流程
2.1 关键接口
所有 Advisor 都实现 org.springframework.ai.chat.client.advisor.api.Advisor
接口:
public interface Advisor extends Ordered {
String getName(); // 唯一标识
int getOrder(); // 执行顺序(越小越早)
}
根据是否支持流式响应,分为两类:
类型 | 接口 | 方法 |
---|---|---|
非流式 | CallAdvisor |
ChatClientResponse adviseCall(ChatClientRequest, CallAdvisorChain) |
流式 | StreamAdvisor |
Flux<ChatClientResponse> adviseStream(ChatClientRequest, StreamAdvisorChain) |
2.2 执行流程(责任链)
执行流程(责任链模式):
请求阶段(→):
用户 Prompt
→ Advisor 1 (order=1)
→ Advisor 2 (order=2)
→ ...
→ Framework 内置 Advisor(发送到 LLM)
响应阶段(←):
LLM Response
← ...
← Advisor 2
← Advisor 1
← 返回最终响应
关键特性:
- 请求阶段:从低 order 到高 order 依次处理
- 响应阶段:从高 order 到低 order 依次处理(栈式回溯)
- 阻断机制:任一 Advisor 可选择不调用
next()
,直接返回响应
2.3 上下文共享:adviseContext
每个 ChatClientRequest
和 ChatClientResponse
都携带一个 不可变的上下文 Map,用于在 Advisor 间传递状态:
// 读取上下文
String convId = request.adviseContext().get(ChatMemory.CONVERSATION_ID);
// 更新上下文(返回新实例)
ChatClientRequest newRequest = request.updateContext(Map.of("traceId", "123"));
⚠️ 注意:上下文是不可变的,
updateContext()
会创建新对象。
三、内置 Advisor 一览
Spring AI 提供了丰富的开箱即用 Advisor:
类别 | Advisor | 功能 |
---|---|---|
记忆管理 | MessageChatMemoryAdvisor |
将历史消息作为 Message 列表注入 Prompt |
PromptChatMemoryAdvisor |
将历史对话拼接为文本注入 System Prompt | |
VectorStoreChatMemoryAdvisor |
从向量库检索相关记忆 | |
RAG | QuestionAnswerAdvisor |
实现基础 RAG:检索 + 生成 |
RetrievalAugmentationAdvisor |
支持模块化 RAG 架构 | |
推理增强 | ReReadingAdvisor |
实现 Re2 技术:重复提问提升推理 |
安全 | SafeGuardAdvisor |
过滤有害/不当内容 |
四、实战案例 1:自定义日志 Advisor
实现一个同时支持流式与非流式的日志记录组件:
public class SimpleLoggerAdvisor implements CallAdvisor, StreamAdvisor {
private static final Logger logger = LoggerFactory.getLogger(SimpleLoggerAdvisor.class);
@Override
public String getName() {
return "SimpleLoggerAdvisor";
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 100; // 靠后执行,记录最终请求
}
// 非流式处理
@Override
public ChatClientResponse adviseCall(
ChatClientRequest request,
CallAdvisorChain chain) {
logRequest(request);
ChatClientResponse response = chain.nextCall(request);
logResponse(response);
return response;
}
// 流式处理
@Override
public Flux<ChatClientResponse> adviseStream(
ChatClientRequest request,
StreamAdvisorChain chain) {
logRequest(request);
Flux<ChatClientResponse> responses = chain.nextStream(request);
// 使用聚合器将流式响应合并为完整响应再记录
return new ChatClientMessageAggregator()
.aggregateChatClientResponse(responses, this::logResponse);
}
private void logRequest(ChatClientRequest request) {
logger.info(">>> AI Request: {}",
request.prompt().getMessages().stream()
.map(m -> m.getMessageType() + ": " + m.getText())
.collect(Collectors.joining("\n")));
}
private void logResponse(ChatClientResponse response) {
logger.info("<<< AI Response: {}", response.result().getOutput().getContent());
}
}
注册使用:
@Bean
public ChatClient chatClient(ChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultAdvisors(new SimpleLoggerAdvisor()) // 全局生效
.build();
}
💡 技巧:通过
Ordered.LOWEST_PRECEDENCE - 100
确保在所有业务 Advisor 之后执行,记录最终发往 LLM 的请求。
五、实战案例 2:Re2 推理增强 Advisor
根据论文《Re-Reading Improves Reasoning in LLMs》,通过重复提问可显著提升模型推理能力。
实现原理:将用户输入 Q
转换为:
Q
Read the question again: Q
public class ReReadingAdvisor implements CallAdvisor, StreamAdvisor {
private static final String RE2_TEMPLATE = """
{query}
Read the question again: {query}
""";
@Override
public String getName() {
return "ReReadingAdvisor";
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 100; // 尽早执行,修改原始输入
}
@Override
public ChatClientResponse adviseCall(
ChatClientRequest request,
CallAdvisorChain chain) {
String originalQuery = request.prompt().getUserMessage().getText();
String augmentedQuery = PromptTemplate.builder()
.template(RE2_TEMPLATE)
.variables(Map.of("query", originalQuery))
.build()
.render();
// 构建新请求
ChatClientRequest modifiedRequest = request.mutate()
.prompt(request.prompt().augmentUserMessage(augmentedQuery))
.build();
return chain.nextCall(modifiedRequest);
}
@Override
public Flux<ChatClientResponse> adviseStream(
ChatClientRequest request,
StreamAdvisorChain chain) {
// 流式处理逻辑同上(略)
// ...
}
}
效果对比:
输入 | 普通模型输出 | Re2 增强后输出 |
---|---|---|
“1 到 100 的和是多少?” | “5050” | “这是一个等差数列求和问题… 公式为 n(n+1)/2 … 结果是 5050” |
适用场景:数学题、逻辑推理、复杂指令理解
六、实战案例 3:动态 RAG 与记忆组合
结合内置 Advisor,实现带记忆的 RAG 系统:
@Configuration
public class AiAdvisorConfig {
@Bean
public ChatClient ragChatClient(
ChatModel chatModel,
VectorStore vectorStore, // 知识库
ChatMemory chatMemory) { // 对话记忆
return ChatClient.builder(chatModel)
.defaultAdvisors(
// 1. 先加载对话历史(高优先级)
MessageChatMemoryAdvisor.builder(chatMemory)
.withOrder(Ordered.HIGHEST_PRECEDENCE + 50)
.build(),
// 2. 再执行 RAG 检索(中等优先级)
QuestionAnswerAdvisor.builder(vectorStore)
.withOrder(Ordered.HIGHEST_PRECEDENCE + 100)
.build(),
// 3. 最后记录日志(低优先级)
new SimpleLoggerAdvisor()
)
.build();
}
}
调用时指定会话 ID:
@RestController
public class AiController {
@Autowired
private ChatClient ragChatClient;
@PostMapping("/chat")
public String chat(@RequestBody ChatRequest req) {
return ragChatClient.prompt()
.advisors(advisor ->
advisor.param(ChatMemory.CONVERSATION_ID, req.getConversationId()))
.user(req.getMessage())
.call()
.content();
}
}
🌟 执行顺序:
MessageChatMemoryAdvisor
→ 注入历史对话QuestionAnswerAdvisor
→ 检索知识库并增强 Prompt- 发送最终 Prompt 到 LLM
- 响应经日志 Advisor 返回
七、最佳实践与避坑指南
7.1 Advisor 顺序设计原则
场景 | 建议 Order |
---|---|
修改用户原始输入(如 Re2) | HIGHEST_PRECEDENCE + N |
加载上下文(记忆、用户信息) | HIGHEST_PRECEDENCE + 100 |
RAG 检索增强 | HIGHEST_PRECEDENCE + 200 |
安全校验(输入) | HIGHEST_PRECEDENCE + 300 |
日志/监控 | LOWEST_PRECEDENCE - 100 |
安全校验(输出) | LOWEST_PRECEDENCE |
7.2 流式处理注意事项
- 使用
ChatClientMessageAggregator
聚合流式响应进行整体处理 - 避免在流式 Advisor 中执行阻塞操作(使用
publishOn(Schedulers.boundedElastic())
) - 响应修改需通过
map()
而非直接赋值
7.3 性能与可观测性
- 所有 Advisor 自动集成 Micrometer,可通过
/actuator/metrics
查看:ai.advisor.duration
ai.advisor.calls
- 在
adviseContext
中传递traceId
实现全链路追踪
八、版本演进与兼容性
Spring AI Advisors API 经历了快速迭代:
版本 | 变更 |
---|---|
1.0 M2 | RequestAdvisor + ResponseAdvisor |
1.0 M3 | 合并为 CallAroundAdvisor / StreamAroundAdvisor |
1.0.0+ | 稳定版:CallAdvisor / StreamAdvisor |
迁移提示:
AdvisedRequest
→ChatClientRequest
AdvisedResponse
→ChatClientResponse
- 上下文从独立参数变为对象内嵌
九、总结
Spring AI Advisors API 是构建企业级 AI 应用的基石:
- 像 AOP 一样优雅:无侵入增强 AI 能力
- 像管道一样灵活:自由组合记忆、RAG、安全、日志等模块
- 像 Spring 一样标准:无缝集成可观测性、事务、安全等生态
更多推荐
所有评论(0)