首先我们需要了解一下什么是ChatClient:
Chat Client(聊天客户端)是一个用于与大语言模型(LLM)进行交互的核心抽象接口,是一个封装了与 AI 模型通信逻辑的客户端接口,它允许开发者以“对话”的方式调用 AI 模型,发送提示词并接收结构化或非结构化的回复。
包括一些基础功能,如:
- 定制和组装模型的输入(Prompt)
- 格式化解析模型的输出(Structured Output)
- 调整模型交互参数(ChatOptions)
还支持更多高级功能:
- 聊天记忆(Chat Memory)
- 工具/函数调用(Function Calling)
- RAG
你可以理解为SpringBoot将用户与AI大模型的对话过程封装成了一个ChatClient,Chat Client 就像“电话客服系统”,你可以把它想象成一个智能客服助手:
- 你拨打电话(调用 chatClient.call())
- 说出你的问题(构造 Prompt)
- 客服听懂后回答你(AI 返回结果)
- 如果你想继续聊,可以接着说(多轮对话支持)
ChatClient屏蔽底层模型差异,提供一致的调用方式;快速接入多种 LLM(如 OpenAI、本地模型);实现上下文感知、角色设定、记忆管理等;支持自定义提示词模板、输出解析器、流式响应等;可用于构建问答系统、智能客服、内容生成等应用。
配置ChatClient
首先创建一个SpringBoot项目(SpringBoot版本要3.x,jdk要17+)
pom引入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M5.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
配置yml:
spring:
application:
name: spring-ai-demo
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY} #自己的API-KEY
model: qwen-turbo #自己选择使用的模型
#配置可以查看聊天服务的日志
logging:
level:
org.springframework.ai.chat.client: DEBUG
api-key自己到阿里云百炼配置API-KEY 创建自己的key,这里我是将key配置到了idea环境变量里面
ChatClient 的使用
你可以使用Spring默认的ChatClient
@Slf4j
@RestController
@RequestMapping("/ai/v1")
public class ChatController {
@Autowired
private ChatClient chatClient;
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/simple/chat")
public String simpleChat(String query) {
String response = chatClient.prompt()
.user(query)
.call()
.content();
return response;
}
或者根据业务需求配置ChatClient
1、设置默认的系统提示词
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
//.defaultSystem("以海盗风格回答所有问题")
.defaultSystem("你作为一个${role},请根据你的专业知识回答下面问题,如果不是你专业范围内的问题,请拒绝回答")
.bulit();
}
设置一个默认的系统提示词,用户每次提问时都会加上这个系统提示词传给模型,同时也可以用使用占位符 ${input},来动态获取用户输入,填充系统提示词
@GetMapping("/simple/chat")
public String simpleChat(String query, String role) {
String response = chatClient.prompt()
.user(query)
.system(p->p.param("role",role))
.advisors(new SimpleLoggerAdvisor())
.call()
.content();
return response;
}
回答:
2、设置默认的模型调用参数
比如模型名称、最大Token数、温度、频率惩罚等等
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
//设置默认的模型调用参数,比如模型名称、最大Token数、温度、频率惩罚等等
.defaultOptions(ChatOptions.builder()
.model("gpt-3.5-turbo")
.maxTokens(1024)
.temperature(0.7)
.build())
.build();
}
3、注册默认的工具函数
具体的如何去注册工具函数请看我下一篇讲解SpringAI——函数工具(Function Calling)
注册默认的工具函数,这样模型可以动态的调用工具函数,模型本身无法执行外部操作(如查询数据库、调用 API),通过注册函数可以让模型“调用”这些功能。函数的返回结果会插入到对话的上下文中,作为模型回答的一部分。
比如我写一个查询天气的工具函数
@Service
public class WeatherService {
public record Request(
@JsonProperty(value = "city", required = true) @JsonPropertyDescription("城市名称") String city) {
}
public String getTodayWeather(String city) {
LocalDate today = LocalDate.now();
//TODO 调用天气查询接口
String weather = "晴";
return "今天是" + today + "," + city + "的天气情况为:" + weather;
}
}
@Configuration
public class FunctionToolConfig {
@Bean
@Description("天气查询城市今天的天气")
public Function<WeatherService.Request, String> getTodayWeather(WeatherService weatherService) {
return request -> weatherService.getTodayWeather(request.city());
}
}
注册到ChatClient中
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
//name 为函数工具的唯一标识,description 为函数描述,模型通过函数描述来判断是否调用该函数,function 为函数实现
.defaultFunctions("getTodayWeather")
.build();
}
注意:
结果:
4、设置默认的用户提示词(User Prompt)
设置默认的用户提示词(User Prompt),这些提示词会在每次对话中自动附加到用户的输入前面。它可以是纯文本、资源文件或更复杂的配置。可以让模型更容易识别用户意图,尤其是在多轮对话中保持一致性。添加上下文信息:比如添加角色、时间、身份等信息,如 .defaultUser("[用户] [2025-04-05] ");引导模型输出风格:比如加一句引导语:.defaultUser("请用中文简洁回答:"); 日志记录或调试辅助在日志中区分系统提示和用户输入
@Bean
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultUser("请用中文简洁回答:")
.build();
}
如果用户问:今天的天气怎么样?
提示词会自动加上:请用中文简洁回答:今天的天气怎么样?
5、设置默认的“对话增强器”(Advisors)
在 Spring AI 中,.defaultAdvisors(...) 是 ChatClient.Builder 提供的一个配置方法,用于设置默认的“对话增强器”(Advisors)。这些 Advisor(顾问/拦截器) 会在每次调用语言模型前后自动执行一些行为,比如:
- 📝 记录日志
- ⏳ 管理对话上下文和记忆
- 🔍 内容过滤或安全检查
- ⚙️ 自定义请求/响应处理逻辑
你可以把 Advisor 理解为:类似 AOP(面向切面编程)中的拦截器,可以在请求前/后插入自定义逻辑,支持链式调用多个 Advisor 。
Spring AI 提供了一些开箱即用的 Advisor:
SimpleLoggerAdvisor:打印请求和响应内容,便于调试
MessageChatMemoryAdvisor:维护对话历史(上下文),实现多轮对话
FunctionCallbackAdvisor:支持模型调用外部函数工具(如天气查询)
PromptLengthAdvisor:控制提示词长度,避免超限
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultAdvisors(new SimpleLoggerAdvisor())
.build()
}
要打印请求响应内容需要开启日志级别为DEBUG:
#配置可以查看聊天服务的日志
logging:
level:
org.springframework.ai.chat.client: DEBUG
控制台有对应的日志输出:
其他详细配置自行了解
总结注意:
在 Spring AI 的 ChatClient 配置中,加了 .defaultXXX(...)和没加的区别在于:是否为所有请求设置了默认行为,这种设计类似于全局配置 和 局部配置。
加了defaultXXX是全局设置作用于全部请求
没有加的default只是作用与当前请求,当前请求行为会覆盖默认行
比如我默认配置为:
public ChatClient chatClient(ChatClient.Builder builder) {
return builder
.defaultSystem("以海盗风格回答所有问题")
.build();
}
使用时:
@GetMapping("/simple/chat")
public String simpleChat(String query, String role) {
String response = chatClient.prompt()
.user(query)
.system(p->p.param("role",role))
.system("你作为一个${role},请根据你的专业知识回答下面问题,如果不是你专业范围内的问题,请拒绝回答")
.call()
.content();
return response;
}
回答结果为:
所以说system()会覆盖defaultSystem()
这个只是个人理解,有错请指正