Java 轉(zhuǎn) AI 應用開發(fā)之區(qū)分Spring AI 中 ChatClient 與 ChatModel

本文定位:面向具備多年 Java / Spring 經(jīng)驗、正在向 AI 應用開發(fā) 延伸的高級工程師。
核心命題ChatModel 是「協(xié)議層 / 模型適配」,ChatClient 是「產(chǎn)品層 / 編排入口」。二者都來自 Spring AI 核心框架,并非 Spring AI Alibaba 獨有;Alibaba Starter 做的是把 DashScope 等實現(xiàn) 注冊為 ChatModel Bean。


一、轉(zhuǎn)型視角:為什么要分清這兩個抽象?

在企業(yè)里接入大模型時,常見兩條路徑:

  1. 最短路徑:拿到 ChatModel(如 dashscopeChatModelollamaChatModel),call(...) / stream(...) 直接對話——適合 PoC、腳本型任務(wù)、或與現(xiàn)有代碼耦合極薄的場景。
  2. 可持續(xù)路徑:在 ChatModel 之上使用 ChatClient,用鏈式 API 組合 System 指令、User 消息、模板變量、記憶、結(jié)構(gòu)化輸出 等——適合要長期維護的智能服務(wù)

當你要在項目中疊加:多輪記憶、Prompt 模板化、RAG 注入、把輸出映射成 DTO/JSON Schema 時,若只用裸 ChatModel,往往需要手寫大量組裝 Prompt、MessageChatResponse 解析的樣板代碼,改動面大、測試成本高。ChatClient 把這些交互模式收斂成 fluent API,本質(zhì)是 建立在 ChatModel 之上的高級封裝。

一句話:ChatClient 適合復雜 AI 服務(wù);ChatModel 適合簡單、貼近底層的模型調(diào)用。


二、概念對比(速查表)

維度 ChatModel ChatClient
層級 模型調(diào)用契約(多種實現(xiàn)的統(tǒng)一接口) 基于 ChatModel 的高層客戶端
典型用法 chatModel.call(text) 或傳入 Prompt chatClient.prompt().system(...).user(...).call().content()
Spring 容器 Starter 通常 自動配置并注入 ChatModel 默認不自動注冊,需 @Bean 構(gòu)建
適用場景 簡單問答、已有完整 Prompt 對象、自定義管線 模板、記憶、顧問模式、entity/JSON 映射、鏈式可讀性
心智模型 JDBC DataSource:薄、直接 JdbcTemplate:藏細節(jié)、提效

說明:具體方法名(如 call 重載、流式 API)隨 Spring AI 版本略有差異,接入時以 當前 BOM 與文檔 為準。


三、ChatModel 直連:簡單 but 薄

在前面各小節(jié)與不同廠商對接時,實質(zhì)都是在使用對應實現(xiàn)的 ChatModel,例如:

  • dashscopeChatModel(阿里云 DashScope)
  • ollamaChatModel(本地 Ollama)

通過 chatModel.call(...)、chatModel.stream(...) 直接 與模型交互,代碼路徑短,適合「只要一句話進、一句話出」的簡單大模型交互。

一旦需求升級為:多消息體系(System / User / Assistant)、可復用模板、RAG 上下文塊拼接、響應解析為業(yè)務(wù)對象,純 ChatModel 的調(diào)用點容易膨脹,審查與回歸變難——這時引入 ChatClient 更劃算。


四、ChatClient 小試牛刀:新建微服務(wù) Module

4.1 SpringAiAlibabaChatClient/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>com.msb</groupId>
        <artifactId>SpringAIAlibabaPro</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>SpringAiAlibabaChatClient</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
        引入 springai alibaba DashScope 模型適配的 Starter

        開發(fā)者開通 DashScope 靈積服務(wù)后,就能借助平臺提供的接口調(diào)用阿里云生態(tài)內(nèi)的各類大模型,還能享受模型微調(diào)、部署管理等配套服務(wù),它是銜接開發(fā)者與阿里云大模型生態(tài)的橋梁。
        DashScope本質(zhì)是面向 AI 開發(fā)者的模型服務(wù)接口層。
        DashScope(靈積)的核心價值就是為開發(fā)者搭建起對接阿里云大模型生態(tài)的橋梁。
        阿里云百煉,它是一個更大范圍的大模型服務(wù)平臺,而DashScope提供的模型服務(wù)API是其底層能力之一
        -->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
        </dependency>
    </dependencies>

</project>

4.2 application.yml

server:
  port: 8080  # 指定當前服務(wù)的端口
  servlet:
    encoding:
      enabled: true # 大模型對話中文亂碼處理
      force: true
      charset: utf-8
spring:
  application:
    name: springaialibabachatclient # 微服務(wù)名稱
  ai:
    dashscope:
      api-key: ${qwennodel}     # 大模型三件套指定
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          model: qwen3-max

生產(chǎn)注意api-key 使用環(huán)境變量或密鑰服務(wù);勿將真實密鑰寫入倉庫。


五、控制層:同一套服務(wù)里「對比」兩種用法

工程中 ChatModelChatClient 常并存:底層排查、流式實驗走 ChatModel;面向業(yè)務(wù)的鏈式編排走 ChatClient。

package com.msb.controller;


import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    // ChatModel和ChatClient都是混合使用,一般兩個我們都要,后面交替使用,所以一次性將兩個都注入
    @Autowired
    private ChatModel chatModel;
    @Autowired
    private ChatClient chatClient;

    @GetMapping(value = "/chatmodel/dochat")
    public String doChat1(@RequestParam(name = "question",defaultValue="你是誰") String question){
        String result = chatModel.call(question);
        return result;
    }

    @GetMapping("/chatclient/dochat")
    public String doChat2(@RequestParam(name = "msg",defaultValue = "你是誰") String question)
    {
        String result = chatClient.prompt().user(question).call().content();
        System.out.println("ChatClient響應:" + result);
        return result;
    }


}

鏈式調(diào)用釋義(ChatClient 路徑)

  1. chatClient.prompt()
    創(chuàng)建一個 提示詞構(gòu)建器(Prompt Builder),用于組裝發(fā)往模型的完整請求(后續(xù)可繼續(xù) .system(...)、.user(...) 等)。

  2. .user(question)
    向構(gòu)建器中加入 用戶消息,即本次要問的內(nèi)容。

  3. .call()
    執(zhí)行模型調(diào)用:發(fā)送組裝好的請求并拿到響應對象(同步路徑;流式則對應 stream() 等 API,依版本而定)。

  4. .content()
    從響應中取出 核心文本內(nèi)容,便于直接返回給前端或進入下游解析。


六、配置類:為何 ChatClient 要自己 @Bean?

要點:在常見 Spring AI Alibaba 自動配置下,ChatModel 可由 Starter 注冊進容器;ChatClient 通常不會自動注入,需要顯式用 ChatClient.builder(chatModel).build() 聲明 Bean。

package com.msb.config;

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;

@Configuration
public class LLMConfig {
    // dashscopeChatModel 是 Spring AI Alibaba 自動向容器中注冊的 ChatModel 實例。
    // 這也證明了ChatClient的構(gòu)建是基于ChatModel的
    @Bean
    public ChatClient chatClient(ChatModel dashscopeChatModel){
        return ChatClient.builder(dashscopeChatModel).build();
    }
}

若項目中存在 多個 ChatModel Bean(例如多模型路由),需在 @Bean 方法參數(shù)上使用 @Qualifier 指向具體實現(xiàn),避免注入歧義。


七、主啟動類

package com.msb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringAiAlibabaChatClientApplication {
    public static void main(String[] args)    {
        SpringApplication.run(SpringAiAlibabaChatClientApplication.class, args);
    }
}

八、訪問測試

本地啟動后,可對 同一問題 分別訪問兩條路徑,觀察行為與擴展差異:

路徑 說明
GET /chatmodel/dochat?question=你是誰 直連 ChatModel.call
GET /chatclient/dochat?msg=你是誰 ChatClient 鏈式調(diào)用

后續(xù)在 ChatClient 路徑上增加 .system("...")、接入 PromptTemplate、或與 RAG 檢索結(jié)果拼接 User 內(nèi)容,都無需推翻 ChatModel 層——底層仍是一個 ChatModel 實現(xiàn)。


九、與「提示詞工程」的銜接

本示例中 ChatClient 僅用 .user(question),等價于「單輪、單條用戶消息」。生產(chǎn)環(huán)境中通常在 同一鏈上 疊加:

  • .system(...):角色、合規(guī)邊界、輸出格式(如「只輸出 JSON」)。
  • PromptTemplate + 變量:業(yè)務(wù)字段渲染進模板(見項目內(nèi) 博客_高級Java工程師的AI應用開發(fā)入門_提示詞與RAG實踐.md)。
  • RAG:檢索結(jié)果作為 User 或獨立段落注入 Prompt,再 call() / stream()。

結(jié)論ChatModel 解決「連上哪家模型」;ChatClient 解決「怎樣穩(wěn)定、可讀、可測地把提示詞與上下文送達模型」——這是高級 Java 工程師在 AI 項目上 控制復雜度 的關(guān)鍵分層。


十、小結(jié)

  • ChatModel:Spring AI 的通用抽象,Alibaba / Ollama 等實現(xiàn)最終都落到它上面;適合簡單調(diào)用與底層定制。
  • ChatClient基于 ChatModel 的高級 API,鏈式組合 Prompt、記憶與結(jié)構(gòu)化輸出,適合 復雜 AI 服務(wù) 的長期維護。
  • 實踐建議:Boot 應用中 同時注入兩者:對比學習、排障、以及逐步把業(yè)務(wù)入口遷移到 ChatClient

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容