【AI应用开发捷径之路】第六课:SpringAi中的对话拦截机制
原创 小数先生
定义
Spring AI中的拦截器(Advisors)是其核心架构的重要组成部分,它借鉴了Spring AOP(面向切面编程)的设计理念,为AI驱动的交互提供了强大而灵活的拦截、修改和增强能力。下面我将详细扩展这一知识点的各个方面。
Spring AI的Advisors本质上是一种声明式的拦截机制,它允许开发者在AI调用的关键生命周期节点插入自定义逻辑,而无需修改核心业务代码。这种设计带来的核心价值包括:
非侵入式增强:通过配置而非代码修改来添加功能
关注点分离:将横切关注点(如日志、监控、缓存)与业务逻辑分离
可复用性:同一Advisor可应用于多个不同的AI交互场景
组合性:多个Advisors可以组合使用,形成处理链
Spring 应用程序中的 AI 驱动交互

1、实现日志的拦截记录
调整日志的模式为DEBUG
# 日志配置用于调试
logging:
level:
org.springframework.ai: DEBUG
org.springframework.web.client: TRACE
实现代码的输出
package com.example.base;
import cn.myeasyai.FaceApplication;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = FaceApplication.class)
public class TestAdvisor {
@Autowired
DeepSeekChatModel deepSeekChatModel;
@Test
public void testAdvisor() {
ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
ChatClient build = builder
.defaultAdvisors(new SimpleLoggerAdvisor()) //加入一个日志拦截器,输出更详细的日志信息
.build();
ChatClient.CallResponseSpec content = build.prompt()
.user("你好")
.call();
String content1 = content.content();
System.out.println(content1);
}
}

2、实现敏感词拦截
new SafeGuardAdvisor(List.of("您好"))) //加入一个敏感词的拦截器,当用户输入敏感词时,会返回一个提示
package com.example.base;
import cn.myeasyai.FaceApplication;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest(classes = FaceApplication.class)
public class TestAdvisor {
@Autowired
DeepSeekChatModel deepSeekChatModel;
@Test
public void testAdvisor() {
ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
ChatClient build = builder
.defaultAdvisors(new SimpleLoggerAdvisor(),
new SafeGuardAdvisor(List.of("您好"))) //加入一个敏感词的拦截器,当用户输入敏感词时,会返回一个提示
.build();
ChatClient.CallResponseSpec content = build.prompt()
.user("您好")
.call();
String content1 = content.content();
System.out.println(content1);
}
}

3、自定义拦截器重写用户提示词
自定义拦截器重读(Re2)
重读策略的核心在于让LLMs重新审视输入问题,这借鉴了人类解决问题的思维方式。通过这种方式LLMs能够更深入地理解问题,发现复杂的模式,从而在各种推理任务中表现得更加强大。
{Input_Query}
再次阅读问题:{Input_Query}
可以基于BaseAdvisor来实现自定义Advisor,他实现了重复的代码 提供 模板方法让我们可以专注自己业务编写即可。
package cn.myeasyai.Service;
import org.springframework.ai.chat.client.ChatClientRequest;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.api.AdvisorChain;
import org.springframework.ai.chat.client.advisor.api.BaseAdvisor;
import org.springframework.ai.chat.client.advisor.api.CallAdvisor;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import java.util.Map;
public class ReReadingAdvisor implements BaseAdvisor {
private static final String DEFAULT_USER_TEXT_ADVISE = """
{re2_input_query}
Read the question again: {re2_input_query}
""";
@Override
public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {
// TODO: Implement 请求之前重写提示词
//用户提示词
String contents = chatClientRequest.prompt().getContents();
String re2InputQuery = PromptTemplate.builder().template(DEFAULT_USER_TEXT_ADVISE).build().render(Map.of("re2_input_query", contents));
ChatClientRequest build = chatClientRequest.mutate()
.prompt(Prompt.builder().content(re2InputQuery).build())
.build();
return build;
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
// TODO: Implement 响应之后重写结果
return null;
}
@Override
public int getOrder() {
return 0;
}
}
测试
package com.example.base;
import cn.myeasyai.FaceApplication;
import cn.myeasyai.Service.ReReadingAdvisor;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.deepseek.DeepSeekChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest(classes = FaceApplication.class)
public class TestAdvisor {
@Autowired
DeepSeekChatModel deepSeekChatModel;
@Test
public void testReReadingAdvisor() {
ChatClient.Builder builder = ChatClient.builder(deepSeekChatModel);
ChatClient build = builder
.defaultAdvisors(new SimpleLoggerAdvisor(),
new ReReadingAdvisor()) //重写提示词的拦截器
.build();
ChatClient.CallResponseSpec content = build.prompt()
.user("发哥帅不帅")
.call();
String content1 = content.content();
System.out.println(content1);
}
}
可以看到,用户的提示词被修改了

通过合理设计和组合Advisors,可以构建出既强大又灵活的AI服务架构,在保持代码整洁的同时,实现复杂的企业级需求。在实际应用中,建议从简单的Advisor开始,逐步构建复杂的拦截链,并始终关注性能影响和可维护性。



