本文定位:面向具備多年 Java / Spring 經(jīng)驗、正在向 AI 應用開發(fā) 延伸的高級工程師。
核心命題:ChatModel是「協(xié)議層 / 模型適配」,ChatClient是「產(chǎn)品層 / 編排入口」。二者都來自 Spring AI 核心框架,并非 Spring AI Alibaba 獨有;Alibaba Starter 做的是把 DashScope 等實現(xiàn) 注冊為ChatModelBean。
一、轉(zhuǎn)型視角:為什么要分清這兩個抽象?
在企業(yè)里接入大模型時,常見兩條路徑:
-
最短路徑:拿到
ChatModel(如dashscopeChatModel、ollamaChatModel),call(...)/stream(...)直接對話——適合 PoC、腳本型任務(wù)、或與現(xiàn)有代碼耦合極薄的場景。 -
可持續(xù)路徑:在
ChatModel之上使用ChatClient,用鏈式 API 組合 System 指令、User 消息、模板變量、記憶、結(jié)構(gòu)化輸出 等——適合要長期維護的智能服務(wù)。
當你要在項目中疊加:多輪記憶、Prompt 模板化、RAG 注入、把輸出映射成 DTO/JSON Schema 時,若只用裸 ChatModel,往往需要手寫大量組裝 Prompt、Message、ChatResponse 解析的樣板代碼,改動面大、測試成本高。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ù)里「對比」兩種用法
工程中 ChatModel 與 ChatClient 常并存:底層排查、流式實驗走 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 路徑)
chatClient.prompt()
創(chuàng)建一個 提示詞構(gòu)建器(Prompt Builder),用于組裝發(fā)往模型的完整請求(后續(xù)可繼續(xù).system(...)、.user(...)等)。.user(question)
向構(gòu)建器中加入 用戶消息,即本次要問的內(nèi)容。.call()
執(zhí)行模型調(diào)用:發(fā)送組裝好的請求并拿到響應對象(同步路徑;流式則對應stream()等 API,依版本而定)。.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。