找回密码
 立即注册
首页 业界区 业界 精控Spring AI日志

精控Spring AI日志

墨佳美 2025-10-5 16:54:31
还在为 Spring AI 默认的日志抓狂吗?想看日志却看不到,一开 DEBUG 就刷屏... 别慌!
今天 NEO 带你解锁一个神级操作:自定义 Advisor,让你轻松掌控 AI 调用的每一个细节!
Advisor 是什么?Spring AI 的“拦截器”

如果你玩过 Servlet 的 Filter 或者 Spring AOP 的切面,那 Advisor 对你来说就是老朋友了。
简单来说,Spring AI 的 Advisor 就是一个调用拦截器。它能在你的代码调用大模型之前之后“插一脚”,执行一些额外的操作。
想在调用前做个权限校验?或者在调用后记个详细日志?用 Advisor 就对了!
官方虽然提供了一些现成的 Advisor,但实际业务场景千变万化,总有不满足需求的时候。这时候,我们就需要自己动手,丰衣足食!
四步搞定!定制你的专属 Advisor

想拥有自己的 Advisor?跟着下面四步走,轻松搞定!
1)选择“岗哨”接口
根据你的需求,选择实现一个或两个接口:

  • CallAroundAdvisor:处理普通的同步请求(非流式)。
  • StreamAroundAdvisor:处理酷炫的流式请求。
强烈建议两个都实现,全方位无死角!
  1. public class MyCustomAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
  2.     // 实现方法...
  3. }
复制代码
2)实现核心“拦截”方法
这是 Advisor 的灵魂所在,你可以在这里对请求和响应为所欲为。

  • 非流式处理 (aroundCall)
  1. @Override
  2. public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
  3.     // 1. 请求到达,先处理一下(前置处理)
  4.     AdvisedRequest modifiedRequest = processRequest(advisedRequest);
  5.    
  6.     // 2. 放行,让请求继续前进
  7.     AdvisedResponse response = chain.nextAroundCall(modifiedRequest);
  8.    
  9.     // 3. 响应返回,再处理一下(后置处理)
  10.     return processResponse(response);
  11. }
复制代码

  • 流式处理 (aroundStream)
  1. @Override
  2. public Flux aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
  3.     // 1. 处理请求
  4.     AdvisedRequest modifiedRequest = processRequest(advisedRequest);
  5.    
  6.     // 2. 调用链并处理流式响应
  7.     return chain.nextAroundStream(modifiedRequest)
  8.                .map(response -> processResponse(response)); // 对流中每个元素进行处理
  9. }
复制代码
3)排个队,定个序
通过 getOrder() 方法告诉 Spring AI 你的 Advisor 应该在什么时候执行。数字越小,优先级越高,越先被执行。
  1. @Override
  2. public int getOrder() {
  3.     // 值越小优先级越高,越先执行
  4.     return 100;
  5. }
复制代码
4)取个独一无二的名字
给你的 Advisor 一个响亮的名号!
  1. @Override
  2. public String getName() {
  3.     return "NEO自定义的 Advisor";
  4. }
复制代码
下面,进入实战环节!
实战:告别 DEBUG!打造 INFO 级日志神器

Spring AI 自带的 SimpleLoggerAdvisor 日志拦截器,看似贴心,实则有点“坑”——它用的是 Debug 级别输出日志。
而 Spring Boot 项目默认的日志级别是 Info,导致我们根本看不到任何日志输出!
1.png

(默认 Info 级别,看不到任何日志)
当然,你可以粗暴地修改配置文件,把日志级别调成 Debug:
  1. logging:
  2.   level:
  3.     org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor: debug
复制代码
日志是出来了,但又带来了新的问题:信息太杂乱!
2.png

(Debug 级别日志,信息过于繁杂)
为了更优雅地解决问题,我们来自己实现一个日志 Advisor:默认打印 Info 级别日志,并且只输出我们最关心的用户提问和 AI 回复
在自己项目根包下新建 advisor 包,编写我们的日志神器 MyLoggerAdvisor:
  1. /**
  2. * 自定义日志 Advisor 打印 info 级别日志、只输出单次用户提示词和 AI 回复的文本
  3. **/
  4. @Slf4j
  5. public class MyLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {
  6.     /**
  7.      * 获取 Advisor 的唯一名称
  8.      */
  9.     @NotNull
  10.     @Override
  11.     public String getName() {
  12.         return this.getClass().getSimpleName();
  13.     }
  14.     /**
  15.      * 设置执行顺序,0 表示较高优先级
  16.      */
  17.     @Override
  18.     public int getOrder() {
  19.         return 0;
  20.     }
  21.     /**
  22.      * 调用前置处理:记录用户请求
  23.      */
  24.     private AdvisedRequest before(AdvisedRequest request) {
  25.         log.info("AI Request: {}", request.userText());
  26.         return request;
  27.     }
  28.     /**
  29.      * 调用后置处理:记录 AI 响应
  30.      */
  31.     private void observeAfter(AdvisedResponse advisedResponse) {
  32.         log.info("AI Response: {}", advisedResponse.response().getResult().getOutput().getContent());
  33.     }
  34.     /**
  35.      * 环绕处理(非流式)
  36.      */
  37.     public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
  38.         // 1. 调用前
  39.         advisedRequest = this.before(advisedRequest);
  40.         // 2. 放行
  41.         AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
  42.         // 3. 调用后
  43.         this.observeAfter(advisedResponse);
  44.         return advisedResponse;
  45.     }
  46.     /**
  47.      * 环绕处理(流式)
  48.      */
  49.     public Flux aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
  50.         // 1. 调用前
  51.         advisedRequest = this.before(advisedRequest);
  52.         // 2. 放行
  53.         Flux advisedResponses = chain.nextAroundStream(advisedRequest);
  54.         // 3. 调用后,使用 MessageAggregator 聚合流式响应,然后统一记录
  55.         return (new MessageAggregator())
  56.                 .aggregateAdvisedResponse(
  57.                         advisedResponses,
  58.                         this::observeAfter
  59.                 );
  60.     }
  61. }
复制代码
代码小贴士:在流式处理 aroundStream 中,我们用 MessageAggregator 工具类将零散的 Flux 响应聚合成一个完整的响应,这样就能在日志中打印出最终的、完整的 AI 回复,而不是一堆零散的数据块。
最后,在 App 中“装备”上我们刚出炉的日志神器:
  1. public App(ChatModel ollamaChatModel) {
  2.     // 初始化基于内存的对话记忆
  3.     ChatMemory chatMemory = new InMemoryChatMemory();
  4.     chatClient = ChatClient.builder(ollamaChatModel)
  5.             .defaultSystem(SYSTEM_PROMPT)
  6.             .defaultAdvisors(
  7.                     new MessageChatMemoryAdvisor(chatMemory),
  8.                     // 替换掉官方的 SimpleLoggerAdvisor
  9.                     // new SimpleLoggerAdvisor()
  10.                     // 使用我们自定义的日志 Advisor
  11.                     new MyLoggerAdvisor()
  12.             )
  13.             .build();
  14. }
复制代码
现在再运行程序,看看效果如何?
3.png

(效果拔群!清爽的 Info 级别日志)
看!日志变得如此清爽,只留下了我们最需要的信息。
通过自定义 Advisor,我们不仅解决了日志记录的痛点,更解锁了 Spring AI 的一个强大扩展点。无论是鉴权、计费、还是更复杂的业务逻辑,都可以通过 Advisor 优雅地实现,让你的 AI 应用更加健壮和灵活。
你还有哪些使用 Advisor 的奇思妙想?欢迎在评论区留言讨论!
如果觉得这篇文章对你有帮助,别忘了点赞在看分享三连哦!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册