掘金 人工智能 07月08日 14:38
精控Spring AI日志
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

Spring AI默认日志无法满足需求,自定义Advisor可拦截调用前后的操作,实现权限校验、日志记录等。实现自定义Advisor需选择接口、实现拦截方法、设置执行顺序和名称。实战中可创建日志Advisor,打印Info级别日志并输出关键信息,解决Debug日志刷屏和信息杂乱问题。自定义Advisor是Spring AI的强大扩展点,可用于鉴权、计费等,提升AI应用的健壮性和灵活性。

🔍Advisor是Spring AI的调用拦截器,可在调用前后执行额外操作,如权限校验、日志记录等,满足千变万化的业务需求。

🛡️实现自定义Advisor需选择CallAroundAdvisor或StreamAroundAdvisor接口,并实现aroundCall或aroundStream方法,处理同步或流式请求。

📈通过getOrder()方法设置Advisor执行顺序,数字越小优先级越高,越先执行;通过getName()方法为Advisor命名,便于识别和管理。

📝实战中可创建日志Advisor,打印Info级别日志并输出用户提问和AI回复,解决Debug日志刷屏和信息杂乱问题,提升日志可读性。

💡自定义Advisor不仅可用于日志记录,还可用于鉴权、计费等,是Spring AI的强大扩展点,让AI应用更健壮、灵活。

还在为 Spring AI 默认的日志抓狂吗?想看日志却看不到,一开 DEBUG 就刷屏... 别慌!

今天 NEO 带你解锁一个神级操作:自定义 Advisor,让你轻松掌控 AI 调用的每一个细节!

Advisor 是什么?Spring AI 的“拦截器”

如果你玩过 Servlet 的 Filter 或者 Spring AOP 的切面,那 Advisor 对你来说就是老朋友了。

简单来说,Spring AI 的 Advisor 就是一个调用拦截器。它能在你的代码调用大模型之前之后“插一脚”,执行一些额外的操作。

想在调用前做个权限校验?或者在调用后记个详细日志?用 Advisor 就对了!

官方虽然提供了一些现成的 Advisor,但实际业务场景千变万化,总有不满足需求的时候。这时候,我们就需要自己动手,丰衣足食!

四步搞定!定制你的专属 Advisor

想拥有自己的 Advisor?跟着下面四步走,轻松搞定!

1)选择“岗哨”接口

根据你的需求,选择实现一个或两个接口:

强烈建议两个都实现,全方位无死角!

public class MyCustomAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {    // 实现方法...}

2)实现核心“拦截”方法

这是 Advisor 的灵魂所在,你可以在这里对请求和响应为所欲为。

@Overridepublic AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {    // 1. 请求到达,先处理一下(前置处理)    AdvisedRequest modifiedRequest = processRequest(advisedRequest);        // 2. 放行,让请求继续前进    AdvisedResponse response = chain.nextAroundCall(modifiedRequest);        // 3. 响应返回,再处理一下(后置处理)    return processResponse(response);}
@Overridepublic Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {    // 1. 处理请求    AdvisedRequest modifiedRequest = processRequest(advisedRequest);        // 2. 调用链并处理流式响应    return chain.nextAroundStream(modifiedRequest)               .map(response -> processResponse(response)); // 对流中每个元素进行处理}

3)排个队,定个序

通过 getOrder() 方法告诉 Spring AI 你的 Advisor 应该在什么时候执行。数字越小,优先级越高,越先被执行。

@Overridepublic int getOrder() {    // 值越小优先级越高,越先执行    return 100; }

4)取个独一无二的名字

给你的 Advisor 一个响亮的名号!

@Overridepublic String getName() {    return "NEO自定义的 Advisor";}

下面,进入实战环节!

实战:告别 DEBUG!打造 INFO 级日志神器

Spring AI 自带的 SimpleLoggerAdvisor 日志拦截器,看似贴心,实则有点“坑”——它用的是 Debug 级别输出日志。

而 Spring Boot 项目默认的日志级别是 Info,导致我们根本看不到任何日志输出!

(默认 Info 级别,看不到任何日志)

当然,你可以粗暴地修改配置文件,把日志级别调成 Debug:

logging:  level:    org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor: debug

日志是出来了,但又带来了新的问题:信息太杂乱!

(Debug 级别日志,信息过于繁杂)

为了更优雅地解决问题,我们来自己实现一个日志 Advisor:默认打印 Info 级别日志,并且只输出我们最关心的用户提问和 AI 回复

在自己项目根包下新建 advisor 包,编写我们的日志神器 MyLoggerAdvisor

/** * 自定义日志 Advisor 打印 info 级别日志、只输出单次用户提示词和 AI 回复的文本 **/@Slf4jpublic class MyLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {    /**     * 获取 Advisor 的唯一名称     */    @NotNull    @Override    public String getName() {        return this.getClass().getSimpleName();    }    /**     * 设置执行顺序,0 表示较高优先级     */    @Override    public int getOrder() {        return 0;    }    /**     * 调用前置处理:记录用户请求     */    private AdvisedRequest before(AdvisedRequest request) {        log.info("AI Request: {}", request.userText());        return request;    }    /**     * 调用后置处理:记录 AI 响应     */    private void observeAfter(AdvisedResponse advisedResponse) {        log.info("AI Response: {}", advisedResponse.response().getResult().getOutput().getContent());    }    /**     * 环绕处理(非流式)     */    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {        // 1. 调用前        advisedRequest = this.before(advisedRequest);        // 2. 放行        AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);        // 3. 调用后        this.observeAfter(advisedResponse);        return advisedResponse;    }    /**     * 环绕处理(流式)     */    public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {        // 1. 调用前        advisedRequest = this.before(advisedRequest);        // 2. 放行        Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);        // 3. 调用后,使用 MessageAggregator 聚合流式响应,然后统一记录        return (new MessageAggregator())                .aggregateAdvisedResponse(                        advisedResponses,                        this::observeAfter                );    }}

代码小贴士:在流式处理 aroundStream 中,我们用 MessageAggregator 工具类将零散的 Flux 响应聚合成一个完整的响应,这样就能在日志中打印出最终的、完整的 AI 回复,而不是一堆零散的数据块。

最后,在 App 中“装备”上我们刚出炉的日志神器:

public App(ChatModel ollamaChatModel) {    // 初始化基于内存的对话记忆    ChatMemory chatMemory = new InMemoryChatMemory();    chatClient = ChatClient.builder(ollamaChatModel)            .defaultSystem(SYSTEM_PROMPT)            .defaultAdvisors(                    new MessageChatMemoryAdvisor(chatMemory),                    // 替换掉官方的 SimpleLoggerAdvisor                    // new SimpleLoggerAdvisor()                    // 使用我们自定义的日志 Advisor                    new MyLoggerAdvisor()            )            .build();}

现在再运行程序,看看效果如何?

(效果拔群!清爽的 Info 级别日志)

看!日志变得如此清爽,只留下了我们最需要的信息。

通过自定义 Advisor,我们不仅解决了日志记录的痛点,更解锁了 Spring AI 的一个强大扩展点。无论是鉴权、计费、还是更复杂的业务逻辑,都可以通过 Advisor 优雅地实现,让你的 AI 应用更加健壮和灵活。

你还有哪些使用 Advisor 的奇思妙想?欢迎在评论区留言讨论!

如果觉得这篇文章对你有帮助,别忘了点赞在看分享三连哦!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Spring AI 自定义Advisor 拦截器 日志记录 Ai应用
相关文章