一、前言

上一节课我们深入学习了底层 ChatModel,掌握了 Message 消息、Prompt 组装、模型参数、流式输出等全套底层 API,能完整看懂 AI 调用底层流程。

在实际项目开发中,频繁手动组装消息、解析返回结果代码偏繁琐。Spring AI 提供 ChatClient 上层门面封装,采用链式编程风格,代码简洁易读、开发效率更高。

本期核心学习:ChatClient 基础用法、链式调用、角色设定、参数配置、流式对话,最后对比 ChatModel 与 ChatClient 的选用场景。


二、ChatClient 基础介绍

2.1 组件概念

ChatClient 是 Spring AI 官方推荐的上层调用客户端,基于 ChatModel 底层接口封装而来,屏蔽大量底层冗余代码,简化日常对话开发。

2.2 核心优势

  1. 链式调用写法,代码逻辑连贯直观
  2. 无需手动频繁创建 Prompt、消息集合
  3. 内置消息、角色、参数、流式统一调用入口
  4. 业务开发首选,可读性与维护性更强

2.3 与 ChatModel 简单区分

  • ChatModel:底层原生接口,偏向原理学习、自定义拓展
  • ChatClient:上层封装工具,偏向业务快速开发

三、ChatClient 完整实战代码

沿用现有项目环境,编写多场景接口,覆盖基础问答、角色对话、参数定制、流式输出。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.14</version>
        <relativePath/>
    </parent>

    <groupId>demo.ai</groupId>
    <artifactId>spring-ai-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.ai.version>1.1.6</spring.ai.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring.ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-client-chat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-zhipuai</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

</project>

application.yml

spring:
  ai:
    zhipuai:
      api-key: 4281feecxxxxxx  # 从智谱AI获取的 api-key
      base-url: https://open.bigmodel.cn/api/paas
      chat:
        options:
          model: glm-4-flash
          temperature: 0.7  # 随机性 0-1 越低越严谨
server:
  servlet:
    # 解决流式输出乱码
    encoding:
      charset: UTF-8        # UTF-8字符集
      force: true           # 强制使用UTF-8
      enabled: true         # 开启 Spring Boot 内置的编码过滤器
package demo.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/client")
public class ChatClientController {

    private final ChatClient chatClient;

    // 构造器注入ChatClient构建器
    public ChatClientController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    // 1. 基础简单问答
    // http://localhost:8080/client/simple?msg=介绍Spring AI
    @GetMapping("/simple")
    public String simpleChat(@RequestParam String msg){
        return chatClient.prompt()
                .user(msg)
                .call()
                .content();
    }

    // 2. 设定系统角色对话
    // http://localhost:8080/client/role?msg=帮我查询内科挂号时间
    @GetMapping("/role")
    public String roleChat(@RequestParam String msg){
        return chatClient.prompt()
                .system("你是专业医院挂号助手,耐心解答挂号相关问题")
                .user(msg)
                .call()
                .content();
    }

    // 3. 自定义模型参数对话
    // http://localhost:8080/client/option?msg=推荐体检项目
    @GetMapping("/option")
    public String optionChat(@RequestParam String msg){
        ZhiPuAiChatOptions chatOptions = new ZhiPuAiChatOptions();
        // chatOptions.setModel("glm-4.5");
        chatOptions.setTemperature(0.9);
        chatOptions.setMaxTokens(1024);

        return chatClient.prompt()
                .system("体检咨询顾问,回答简洁实用")
                .user(msg)
                .options(chatOptions)
                .call()
                .content();
    }

    // 4. 流式实时输出对话
    // http://localhost:8080/client/stream?msg=简述挂号基本流程
    @GetMapping("/stream")
    public Flux<String> streamChat(@RequestParam String msg){
        return chatClient.prompt()
                .system("挂号流程讲解员,分段清晰讲解")
                .user(msg)
                .stream()
                .content();
    }
}

四、接口功能逐点解析

4.1 基础问答 simple

最简链式调用,仅传入用户提问,框架自动完成消息封装与结果解析,满足日常普通聊天场景。

4.2 角色设定 role

通过 .system() 方法快速设置 AI 身份与行为规范,等同于底层 SystemMessage 效果,写法更加精简。

4.3 自定义模型参数 option

内置 options 配置项。

4.4 流式输出 stream

调用 .stream() 方法即可开启流式响应,返回 Flux 数据流,实现打字机实时展示效果,适配前端聊天页面。


五、ChatClient 与 ChatModel 对比总结

表格

对比项 ChatModel ChatClient
层级位置 底层基础接口 上层封装客户端
代码风格 面向对象组装,代码偏多 链式编程,简洁优雅
消息处理 手动创建各类 Message 内置方法快速传入
参数配置 手动实例化配置类 链式直接配置
适用场景 底层学习、自定义拓展 业务开发、快速上线

六、学习踩坑小结

1. ChatClient 依靠 Builder 构造注入,不要用 @Resource 直接注入

 当然也可以使用ChatClientConfiguration,让Spring容器管理ChatClient,那么代码改造如下:

新建conf包,然后创建ChatClientConfiguration类

package demo.ai.conf;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ChatClientConfiguration {

    @Bean
    public ChatClient chatClient(ChatClient.Builder chatClientBuilder) {
        return chatClientBuilder.build();
    }
}

ChatClientController使用@Resource注解注入ChatClient

package demo.ai.controller;

import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
@RequestMapping("/client")
public class ChatClientController {

    @Resource
    private ChatClient chatClient;
    
//    private final ChatClient chatClient;

    // 构造器注入ChatClient构建器
//    public ChatClientController(ChatClient.Builder chatClientBuilder) {
//        this.chatClient = chatClientBuilder.build();
//    }

    // 1. 基础简单问答
    // http://localhost:8080/client/simple?msg=介绍Spring AI
    @GetMapping("/simple")
    public String simpleChat(@RequestParam String msg){
        return chatClient.prompt()
                .user(msg)
                .call()
                .content();
    }

    // 2. 设定系统角色对话
    // http://localhost:8080/client/role?msg=帮我查询内科挂号时间
    @GetMapping("/role")
    public String roleChat(@RequestParam String msg){
        return chatClient.prompt()
                .system("你是专业医院挂号助手,耐心解答挂号相关问题")
                .user(msg)
                .call()
                .content();
    }

    // 3. 自定义模型参数对话
    // http://localhost:8080/client/option?msg=推荐体检项目
    @GetMapping("/option")
    public String optionChat(@RequestParam String msg){
        ZhiPuAiChatOptions chatOptions = new ZhiPuAiChatOptions();
        // chatOptions.setModel("glm-4.5");
        chatOptions.setTemperature(0.9);
        chatOptions.setMaxTokens(1024);

        return chatClient.prompt()
                .system("体检咨询顾问,回答简洁实用")
                .user(msg)
                .options(chatOptions)
                .call()
                .content();
    }

    // 4. 流式实时输出对话
    // http://localhost:8080/client/stream?msg=简述挂号基本流程
    @GetMapping("/stream")
    public Flux<String> streamChat(@RequestParam String msg){
        return chatClient.prompt()
                .system("挂号流程讲解员,分段清晰讲解")
                .user(msg)
                .stream()
                .content();
    }
}

2. 链式调用顺序:prompt() → 消息 → 参数 → 调用

3. 流式接口用浏览器查看效果最佳

4. ChatClient 底层依然是 ChatModel,只是封装更优雅


七、本篇学习收获

  1. 掌握 ChatClient 注入方式与链式基础语法
  2. 熟练实现:基础问答、角色对话、参数配置、流式输出
  3. 清晰分清 ChatModel 与 ChatClient 关系与使用场景
  4. 具备企业项目中灵活选择 API 的能力

结语

从底层 ChatModel 吃透原理,再用 ChatClient 提升开发效率,是 Spring AI 最标准的学习路径。

日常业务优先使用 ChatClient,遇到定制化需求再回到 ChatModel,就能轻松搞定企业级 AI 开发。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐