1. Spring AI Advisor 框架深度解析
作为一名长期从事企业级AI应用开发的工程师,我一直在寻找能够简化AI集成同时又保持灵活性的框架。Spring AI的Advisor机制完美解决了这个痛点,它提供了一种优雅的方式来增强和控制AI模型的行为。下面我将从实际应用角度,全面剖析这个强大的中间件机制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Advisor 核心架构与设计哲学
2.1 什么是Advisor?
Advisor本质上是Spring AI中的AOP(面向切面编程)实现,专门为AI操作设计的拦截器链。与传统的Spring AOP不同,它针对AI场景做了深度优化:
- 双向拦截:既能处理请求也能处理响应
- 流式支持:原生支持流式API调用场景
- 上下文感知:内置上下文传递机制
- 顺序控制:通过Ordered接口精确控制执行顺序
2.2 核心组件详解
2.2.1 基础接口体系
java复制public interface CallAroundAdvisor extends Ordered {
ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain);
}
public interface StreamAroundAdvisor extends Ordered {
Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain);
}
关键设计要点:
ChatClientRequest封装了原始请求数据ChatClientResponse封装了模型返回结果AdvisorChain实现了责任链模式,确保多个Advisor可以串联执行
2.2.2 执行流程示意图
plaintext复制 +-------------------+ +-------------------+
Request -> | Advisor A (order=1)| ----> | Advisor B (order=2)| ----> LLM调用
+-------------------+ +-------------------+
|
+-------------------+ +-------------------+
Response <-| Advisor B (order=2)| <---- | Advisor A (order=1)| <----
+-------------------+ +-------------------+
提示:order值越小优先级越高,先执行的Advisor后获得响应处理机会
3. 实战:开发自定义Advisor
3.1 日志记录Advisor进阶实现
基础版的日志记录虽然简单,但在生产环境中需要更多考量:
java复制public class AdvancedLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ObjectMapper mapper = new ObjectMapper();
@Override
public String getName() {
return "AdvancedLogger";
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 最先执行
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
logRequest(request);
long start = System.currentTimeMillis();
try {
ChatClientResponse response = chain.adviseCall(request);
logResponse(response, System.currentTimeMillis() - start);
return response;
} catch (Exception e) {
logger.error("Processing failed", e);
throw e;
}
}
private void logRequest(ChatClientRequest request) {
if (logger.isDebugEnabled()) {
try {
String json = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(request);
logger.debug("Inbound Request:\n{}", json);
} catch (JsonProcessingException e) {
logger.warn("Failed to serialize request", e);
}
}
}
// 类似实现logResponse...
}
关键增强点:
- 结构化JSON日志输出
- 执行耗时统计
- 异常处理
- 日志级别控制
3.2 敏感词过滤Advisor
企业级应用中,内容安全是重中之重:
java复制public class ContentFilterAdvisor implements CallAroundAdvisor {
private final SensitiveWordFilter filter;
public ContentFilterAdvisor(SensitiveWordFilter filter) {
this.filter = filter;
}
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String userInput = request.getPrompt().getUserMessage().getText();
if (filter.containsSensitiveWords(userInput)) {
throw new ContentSecurityException("Input contains sensitive content");
}
return chain.adviseCall(request);
}
// 实现其他必要方法...
}
4. 内置Advisor深度解析
4.1 Chat Memory Advisors对比
Spring AI提供了三种对话记忆管理策略:
| Advisor类型 | 实现方式 | 适用场景 | 优缺点 |
|---|---|---|---|
| MessageChatMemory | 以消息列表形式追加 | 对话型应用 | 保留完整上下文,但token消耗大 |
| PromptChatMemory | 合并到系统提示 | 摘要型应用 | 节省token,可能丢失细节 |
| VectorStoreChatMemory | 向量存储检索 | 知识密集型 | 支持大数据量,有检索延迟 |
配置示例:
java复制@Bean
public ChatClient chatClient(ChatModel model, ChatMemory memory, VectorStore vectorStore) {
return ChatClient.builder(model)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(memory).build(),
VectorStoreChatMemoryAdvisor.builder(vectorStore).build()
)
.build();
}
4.2 RAG增强实现原理
QuestionAnswerAdvisor的工作流程:
- 用户提问:"Spring AI的主要特点是什么?"
- Advisor从VectorStore检索相关文档片段
- 构建增强提示:
code复制请基于以下上下文回答问题: {{检索到的文档}} 问题:{{原始问题}} - 将增强后的提示发送给LLM
性能优化技巧:
- 设置合理的topK参数(通常3-5个片段足够)
- 对检索结果做长度裁剪
- 添加片段来源标记便于验证
5. 递归Advisor高级应用
5.1 多跳RAG实现
传统RAG的局限在于无法进行递进式查询。通过递归Advisor可以实现:
java复制public class MultiHopRagAdvisor implements CallAroundAdvisor {
private final VectorStore store;
private final int maxHops;
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String currentQuery = extractQuery(request);
List<Document> context = new ArrayList<>();
for (int i = 0; i < maxHops; i++) {
// 检索
List<Document> chunks = store.similaritySearch(currentQuery);
context.addAll(chunks);
// 判断是否需要继续
if (!needFurtherQuery(context, currentQuery)) {
break;
}
// 生成新查询
currentQuery = generateNewQuery(context, currentQuery);
}
// 构建最终请求
ChatClientRequest enhancedRequest = buildRagRequest(request, context);
return chain.adviseCall(enhancedRequest);
}
// 辅助方法实现...
}
5.2 自我反思式优化
让模型自我评估并改进回答质量的模式:
java复制public class SelfReflectionAdvisor implements CallAroundAdvisor {
private static final String REFLECTION_PROMPT = """
请评估以下回答的质量,指出不足之处并给出改进建议:
问题:%s
回答:%s
改进后的回答应该是:
""";
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
ChatClientResponse initialResponse = chain.adviseCall(request);
if (isHighConfidence(initialResponse)) {
return initialResponse;
}
String reflectionPrompt = String.format(REFLECTION_PROMPT,
request.getPrompt().getUserMessage().getText(),
initialResponse.getContent());
ChatClientRequest reflectionRequest = request.mutate()
.prompt(new Prompt(reflectionPrompt))
.build();
return chain.adviseCall(reflectionRequest);
}
}
6. 性能优化与最佳实践
6.1 Advisor排序策略
合理的执行顺序对系统性能影响巨大:
- 安全相关(最高优先级)
- 日志记录
- 输入预处理
- 记忆/上下文管理
- RAG检索
- 输出后处理
典型配置:
java复制.defaultAdvisors(
new ContentFilterAdvisor(), // order=0
new AdvancedLoggerAdvisor(), // order=100
MessageChatMemoryAdvisor.builder(memory).withOrder(200).build(),
QuestionAnswerAdvisor.builder(vectorStore).withOrder(300).build()
)
6.2 流式处理优化
处理流式响应时的注意事项:
- 使用背压控制防止内存溢出
- 避免在流处理中进行阻塞操作
- 考虑使用响应式缓存
java复制public Flux<ChatClientResponse> adviseStream(ChatClientRequest request, StreamAdvisorChain chain) {
return chain.adviseStream(request)
.doOnNext(response -> {
// 非阻塞处理
executor.submit(() -> auditService.log(response));
})
.onBackpressureBuffer(1000, // 合理设置缓冲区
overflow -> logger.warn("Buffer overflow"));
}
7. 企业级应用场景
7.1 合规审计系统
结合Advisor实现完整的AI调用审计:
java复制public class AuditAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
private final AuditService auditService;
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String auditId = auditService.startAudit(request);
try {
ChatClientResponse response = chain.adviseCall(request);
auditService.logSuccess(auditId, response);
return response;
} catch (Exception e) {
auditService.logFailure(auditId, e);
throw e;
}
}
// 流式实现类似...
}
7.2 多租户隔离
通过Advisor实现租户级隔离:
java复制public class TenantAwareAdvisor implements CallAroundAdvisor {
@Override
public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) {
String tenantId = TenantContext.getCurrentTenant();
if (!modelAccessService.hasAccess(tenantId, request.getModel())) {
throw new AccessDeniedException("Tenant not authorized for this model");
}
// 添加租户标记
ChatClientRequest tenantRequest = request.mutate()
.addContext("tenantId", tenantId)
.build();
return chain.adviseCall(tenantRequest);
}
}
8. 疑难问题排查指南
8.1 常见问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| Advisor未执行 | 1. 未正确注册 2. Order值设置过大 |
1. 检查defaultAdvisors调用 2. 降低Order值 |
| 上下文丢失 | 1. 未正确传递context 2. 使用了不可变context |
1. 使用updateContext方法 2. 检查mutate()调用 |
| 流式响应中断 | 1. 阻塞操作 2. 缓冲区溢出 |
1. 改用异步处理 2. 调整缓冲区大小 |
8.2 性能调优实战
案例:某电商客服系统响应延迟高
排查过程:
- 通过日志Advisor记录各环节耗时
- 发现VectorStore检索占用了70%时间
- 优化方案:
- 为向量存储添加缓存层
- 优化检索topK参数
- 实现异步预检索
优化后效果:
- 平均响应时间从1200ms降至400ms
- 99线从2500ms降至800ms
关键配置:
java复制CachingVectorStore cachedStore = new CachingVectorStore(primaryStore,
cacheManager, Duration.ofMinutes(30));
QuestionAnswerAdvisor advisor = QuestionAnswerAdvisor.builder(cachedStore)
.withTopK(3) // 原为5
.build();
9. 版本迁移指南
从1.0 M2升级到1.1.3的主要变更:
-
接口重构:
RequestAdvisor→CallAroundAdvisorResponseAdvisor功能合并到上述接口
-
上下文管理:
java复制// 旧版 public interface RequestAdvisor { void adviseRequest(Request request, Map<String, Object> context); } // 新版 public interface CallAroundAdvisor { ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain); } -
流式处理:
- 移除了
StreamResponseMode - 统一使用
Flux响应式编程模型
- 移除了
迁移步骤建议:
- 先实现新接口适配层
- 逐步替换旧实现
- 充分测试流式场景
10. 扩展思考:Advisor模式的价值
在实际项目中采用Advisor架构后,我们获得了以下收益:
-
关注点分离:各功能模块解耦,例如:
- 安全团队维护ContentFilterAdvisor
- AI团队专注RAG优化
- DevOps团队管理日志Advisor
-
可观测性提升:
- 通过Advisor链天然形成调用轨迹
- 便于实现细粒度监控
-
业务灵活性:
- 快速启用/禁用特定功能
- 支持动态配置Advisor顺序
一个典型的团队协作场景:
java复制ChatClient client = ChatClient.builder(model)
.defaultAdvisors(
securityTeam.getContentFilter(),
aiTeam.getRagAdvisor(),
opsTeam.getMonitoringAdvisor()
)
.build();
这种架构特别适合中大型AI应用,既能保持架构整洁,又能满足各方的定制需求。
