Spring AI 实战系列(二):ChatClient封装,告别大模型开发样板代码


系列栏目: Spring AI

Spring AI 实战教程(一)入门示例

Spring AI 实战系列(二):ChatClient封装,告别大模型开发样板代码

Spring AI 实战系列(三):多模型共存+双版本流式输出

Spring AI 实战系列(四):Prompt工程深度实战
在本系列的第一篇教程中,我们完成了 Spring AI与阿里云百炼大模型的基础集成:

  • 基于spring-ai-alibaba-starter-dashscope官方 Starter 完成了项目工程化搭建
  • 通过ChatModel原子API实现了基础的同步对话与流式响应接口
  • 完成了API Key的环境变量安全注入,避免了密钥硬编码的安全风险

但在实际业务开发中我们很快会发现:**ChatModel**虽然提供了极致的底层灵活性,但面对复杂的业务场景时,需要我们手动组装提示词、处理消息结构、解析模型输出、串联对话记忆 / 向量检索等组件,会产生大量重复的样板代码,开发效率低且不易维护。

本篇我们就来学习 Spring AI 提供的Fluent流式 API ------ ChatClient,它完美解决了上述痛点,在不丢失灵活性的前提下,将大模型交互的开发效率提升一个量级。

一、ChatClient 核心定位:从原子 API 到工程化封装

1.1 什么是 ChatClient

**ChatClient**是 Spring AI提供的高层级Fluent API,它底层基于ChatModel原子能力,将大模型交互全流程的组件协调、样板代码全部封装,为开发者提供了声明式、链式的开发体验。

如果把ChatModel比作JDBC的原生Connection,需要自己处理 SQL 拼接、结果集解析;那**ChatClient**就是 MyBatis/MyBatis-Plus,把底层繁琐的操作全部收敛,让开发者只需要关注核心业务逻辑。

1.2 ChatClient 核心优势

能力维度 ChatModel 原子 API ChatClient Fluent API
代码量 复杂场景需要大量样板代码,手动组装 Message、处理 Prompt 链式调用一行完成全流程,无冗余代码
提示词管理 每次调用手动拼接系统提示、用户提示,无统一管理能力 支持全局默认提示词、动态参数模板,一次配置全局生效
输出解析 需手动处理字符串转 JSON、实体映射、格式校验 内置结构化输出能力,一键映射为 Java 实体 / 集合,自动约束模型输出格式
高级能力 对话记忆、RAG 检索、函数调用需手动串联组件 内置 Advisor 切面机制,一行配置开启记忆、RAG、日志、限流等能力
编程模型 同步 / 流式能力分离,API 不统一 同步call()、流式stream()统一 API,无缝切换

1.3 核心能力全景

ChatClient 不仅封装了基础对话能力,还覆盖了企业级大模型应用的全场景需求:

  • 基础能力:提示词定制、模型参数调优、同步 / 流式响应
  • 结构化输出:自动将模型返回映射为 Java 实体类、泛型集合
  • 全局默认配置:统一系统提示词、模型参数、函数定义,一次配置全局生效
  • 高级扩展:通过 Advisor 机制,一键集成聊天记忆、RAG 检索、日志监控、函数调用等能力

二、实战落地:基于阿里云百炼的 ChatClient 集成

本次实战完全承接上一篇的项目工程,无需从零搭建,所有代码可直接复制运行。

2.1 环境前提

  • 已完成 JDK 17+、Spring Boot 3.2.x 环境搭建
  • 已配置阿里云百炼API Key环境变量DASHSCOPE_API_KEY
  • 已在pom.xml中引入spring-ai-alibaba-starter-dashscope核心依赖

2.2 第一步:ChatClient 全局 Bean 配置

Spring AI不会自动装配ChatClient实例,只会自动装配ChatClient.Builder构建器,我们需要在配置类中手动创建ChatClient的 Bean 并注入 Spring 容器。

修改我们的配置类LLMConfig.java,完整代码如下:

java 复制代码
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Spring AI 大模型配置类
 */
@Configuration
public class SaaLLMConfig {

    /**
     * 阿里云百炼API实例,负责与百炼服务通信
     * 从系统环境变量读取API Key,避免硬编码泄露
     */
    @Bean
    public DashScopeApi dashScopeApi() {
        return DashScopeApi.builder()
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .build();
    }

    /**
     * 全局ChatClient实例,基于阿里云百炼ChatModel构建
     */
    @Bean
    public ChatClient dashScopeChatClient(ChatModel dashscopeChatModel) {
        return ChatClient
                // 基于已自动装配的ChatModel构建Builder
                .builder(dashscopeChatModel)
                // 可选:全局默认系统提示词,所有调用都会自动携带
                .defaultSystem("你是一个专业的Java后端开发工程师,擅长Spring生态技术栈,回答问题简洁、专业、有可落地的代码示例")
                // 可选:全局默认模型参数,统一管理,避免每次调用重复配置
                .defaultOptions(DashScopeChatOptions.builder()
                        .withModel("qwen-turbo")
                        .withTemperature(0.7)
                        .withMaxTokens(2000)
                        .build())
                // 构建ChatClient实例
                .build();
    }
}

关键说明

  1. 这里的ChatModel会由spring-ai-alibaba自动装配,无需我们手动创建
  2. 通过defaultSystem设置全局系统提示词,统一模型的角色定位,所有调用都会自动携带
  3. 通过defaultOptions设置全局模型参数,统一管理模型版本、温度、最大 Token 数,避免硬编码分散在业务代码中

2.3 第二步:基础接口开发,对比 ChatModel 与 ChatClient

我们创建ChatClientController,同时提供ChatClientChatModel的调用接口,直观对比两者的开发体验。

java 复制代码
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * ChatClient 实战接口
 */
@RestController
public class ChatClientController {

    // 注入原生ChatModel,用于对比
    @Resource
    private ChatModel chatModel;

    // 注入我们配置的ChatClient实例
    @Resource
    private ChatClient dashScopeChatClient;

    /**
     * ChatClient 同步对话接口
     */
    @GetMapping("/chatclient/dochat")
    public String doChat(@RequestParam(name = "msg", defaultValue = "你是谁") String msg) {
        // ChatClient 链式调用,一行完成请求组装、调用、结果提取
        String result = dashScopeChatClient
                .prompt() // 创建提示词构建器
                .user(msg) // 设置用户输入
                .call() // 同步调用大模型
                .content(); // 提取响应的文本内容
        System.out.println("ChatClient响应:" + result);
        return result;
    }

    /**
     * ChatModel 同步对话接口(对比用)
     */
    @GetMapping("/chatmodelv2/dochat")
    public String doChat2(@RequestParam(name = "msg", defaultValue = "你是谁") String msg) {
        // ChatModel 原生调用,简单场景下一行完成,但复杂场景需要大量样板代码
        String result = chatModel.call(msg);
        System.out.println("ChatModel响应:" + result);
        return result;
    }
}

接口测试 :启动项目后,访问http://localhost:8003/chatclient/dochat?msg=用Spring Boot写一个Hello World接口,可以看到ChatClient会自动携带我们配置的全局系统提示词,以 Java 工程师的专业视角返回结果,代码简洁且行为统一。

三、实践注意

  1. 全局配置统一管理将系统提示词、模型参数、重试策略等全部在 ChatClient Bean 中统一配置,避免硬编码分散在业务代码中,便于后续维护与迭代。

  2. 多模型实例隔离 若项目同时对接多个大模型(如阿里云百炼 + 本地 Ollama),需为每个模型创建独立的 ChatClient Bean,通过@Qualifier注解区分注入,避免 Bean 冲突。

  3. 日志与监控集成 通过SimpleLoggerAdvisor开启请求与响应的日志打印,同时通过 Advisor 切面统一统计 Token 消耗、请求耗时,对接 Prometheus 等监控系统。

  4. 异常统一处理封装 ChatClient 调用的通用异常处理,针对大模型调用超时、限流、API 密钥错误、输出解析失败等场景做统一的降级与容错处理。

  5. 提示词模板外部化 复杂的系统提示词不要硬编码在 Java 代码中,放到application.yml配置文件或独立的资源文件中,通过@ValueResource注入,便于产品与运营同学修改优化。

四、避坑指南

  1. 坑点 1:ChatClient 无法直接 @Resource 注入 Spring AI 不会自动装配 ChatClient 的 Bean,只会自动装配ChatClient.Builder,必须在配置类中通过 Builder 手动构建 ChatClient Bean,否则会出现注入失败的异常。

  2. 坑点 3:多模型场景下的 Bean 注入歧义 若项目中存在多个 ChatModel 实例,构建 ChatClient 时必须通过@Qualifier明确指定注入的ChatModel,否则 Spring会抛出NoUniqueBeanDefinitionException异常。

  3. 坑点 4:环境变量 API Key 读取失败 System.getenv()读取的是系统环境变量,IDE 本地运行时,需要在启动配置的 Environment variables 中添加DASHSCOPE_API_KEY,否则会出现 API Key 为空的错误。

下篇预告

本篇我们掌握了ChatClient的核心用法,实现了比ChatModel更优雅、更易维护的大模型交互代码。

下篇我们将深入Spring AI实战核心能力:一套代码实现多个大模型无缝共存与动态切换,同时带来 ChatModel与ChatClient双版本流式输出完整实现,解决长文本生成的用户体验痛点。

传送门:Spring AI 实战系列(三):多模型共存+双版本流式输出

如果本文对你有帮助,欢迎点赞、收藏、评论,跟着系列教程一步步完成Spring AI应用。

相关推荐
张较瘦_2 小时前
[论文阅读] AI + 软件工程 | 从1对1到规模化,Lacy用AI+专家代码漫游重构软件入职指导
人工智能·重构·软件工程
imuliuliang2 小时前
Spring Boot(快速上手)
java·spring boot·后端
va学弟2 小时前
Java 网络通信编程(8):完善 UDP 协议
java·开发语言·udp
夫礼者2 小时前
【极简监控】打破中间件黑盒:用 Micrometer 打造“SLF4J式”的降维打击Metrics监控体系
java·中间件·监控·metrics·micrometer
yashuk2 小时前
Spring Boot 3.4 正式发布,结构化日志!
java·spring boot·后端
卖报的大地主2 小时前
视觉生成底层技术发展脉络与研究图谱
人工智能·深度学习·计算机视觉
AI科技星2 小时前
基于v≡c光速螺旋理论的正确性证明:严格遵循科学方法论的完整路径
c语言·开发语言·人工智能·线性代数·算法·机器学习·数学建模
RFdragon6 小时前
分享本周所学——三维重建算法3D Gaussian Splatting(3DGS)
人工智能·线性代数·算法·机器学习·计算机视觉·矩阵·paddlepaddle
星河耀银海6 小时前
3D效果:HTML5 WebGL结合AI实现智能3D场景渲染
前端·人工智能·深度学习·3d·html5·webgl