SpringAI——ChatClient 的配置与使用

该文章已生成可运行项目,

首先我们需要了解一下什么是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() 

这个只是个人理解,有错请指正 

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值