弗兰的悲惨之旅
99.73M · 2026-04-04
s01 > s02 > [ s03 ] s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > s18
很多初学者看到 Spring AI 同时提供了 ChatModel 和 ChatClient 都会问:
这一章我们就来彻底搞清楚这个问题!
让我用一个生活化的比喻来解释:
ChatModel(对话模型) 就相当于手机的「原始电话功能」
ChatClient(对话客户端) 相当于「智能手机」
在电话基础上,增加了:
功能更丰富,使用更便捷
ChatModel 是 Spring AI 的核心底层接口,它直接封装了与 AI 模型的通信。
大白话解释:把 ChatModel 想象成"AI 模型的翻译官",你给它发中文,它能听懂;AI 返回的内容,它也能翻译成 Java 对象给你。
public interface ChatModel extends Model, ChatOptionsDesktop {
// 核心方法就两个:
// 方法1:一次性返回完整结果
ChatResponse call(Prompt prompt);
// 方法2:流式返回(一个字一个字吐出来)
Flux<ChatResponse> stream(Prompt prompt);
}
| 特点 | 说明 |
|---|---|
| 底层接口 | 直接与 AI 服务商通信 |
| 功能单一 | 只负责发送消息、接收回复 |
| 灵活度高 | 可以精确控制请求的每个细节 |
| 使用难度 | 需要了解 Prompt、Message 等概念 |
// 使用 ChatModel 调用 AI
@RestController
public class ChatModelController
{
@Resource
private ChatModel chatModel;
@GetMapping("/chatmodel/hello")
public String hello(String msg)
{
// ChatModel 的调用方式:直接传入字符串
String result = chatModel.call(msg);
return result;
}
}
ChatClient 是构建在 ChatModel 之上的高级 API,它提供了链式调用(Builder模式)的便捷写法。
大白话解释:ChatClient 就像一个"智能点餐机",不仅能帮你叫外卖,还支持:
// ChatClient 的经典使用方式:链式调用
String result = chatClient.prompt() // 第一步:创建提示词
.system("你是一个Java助手") // 第二步:设置系统提示词
.user("什么是反射?") // 第三步:设置用户问题
.call() // 第四步:执行调用
.content(); // 第五步:获取结果
这种链式写法比原生 ChatModel 更加直观易读。
// 使用 ChatClient 调用 AI
@RestController
public class ChatClientController
{
// 注意:ChatClient 不能直接注入,需要通过 Builder 构建
private final ChatClient dashScopeChatClient;
// 构造函数注入,并构建 ChatClient
public ChatClientController(ChatModel dashScopeChatModel)
{
// 通过 ChatModel 创建 ChatClient
this.dashScopeChatClient = ChatClient.builder(dashScopeChatModel).build();
}
@GetMapping("/chatclient/hello")
public String hello(String msg)
{
// 链式调用,语义清晰
String result = dashScopeChatClient.prompt()
.user(msg) // 设置用户消息
.call() // 调用 AI
.content(); // 获取文本内容
return result;
}
}
| 特性 | ChatModel | ChatClient |
|---|---|---|
| 层级 | 底层接口 | 高级封装 |
| API 风格 | 直接调用 | 链式 Builder |
| 系统提示词 | 需手动构造 Prompt 对象 | .system() 方法直接设置 |
| 模板变量 | 不支持 | 支持 .param() 替换占位符 |
| 结构化输出 | 需额外配置 | .entity() 方法直接映射 |
| 对话记忆 | 不支持 | 支持 Advisor 扩展 |
| 工具调用 | 需手动配置 | 支持 .tools() 方法 |
| 适用场景 | 需要精确控制的底层开发 | 快速构建 AI 功能 |
使用 ChatModel 的场景:
使用 ChatClient 的场景:
很多初学者误以为 ChatModel 功能太简单,做不到 ChatClient 的那些高级功能。其实 ChatModel 通过手写样板代码完全可以实现相同的功能,只不过代码量会多一些。
让我们对比一下两者的实现方式:
ChatClient 的写法(简洁) :
String result = chatClient.prompt()
.system("你是一个专业的Java工程师") // 系统提示词
.user("什么是反射?") // 用户问题
.call()
.content();
ChatModel 的写法(样板代码多) :
// ChatModel 需要手动构造 Prompt 对象
// 第一步:创建系统消息
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(
"你是一个专业的%s", "Java工程师" // 模板变量
);
Message systemMessage = systemPromptTemplate.createMessage(
Map.of("role", "professional", "specialty", "Java工程师")
);
// 第二步:创建用户消息
UserMessage userMessage = new UserMessage("什么是反射?");
// 第三步:组合成对话消息列表
List<Message> messages = new ArrayList<>();
messages.add(systemMessage);
messages.add(userMessage);
// 第四步:创建 Prompt 对象
Prompt prompt = new Prompt(messages);
// 第五步:调用并获取结果
ChatResponse response = chatModel.call(prompt);
String result = response.getResult().getOutput().getText();
从上面的对比可以看出:
虽然 ChatModel 代码多,但它给了你最大的控制权:
SAA-03ChatModelChatClient/
├── pom.xml # 依赖配置
├── src/main/java/com/atguigu/study/
│ ├── config/
│ │ └── SaaLLMConfig.java # 配置文件
│ ├── controller/
│ │ ├── ChatClientController.java # ChatClient 示例
│ │ ├── ChatClientControllerV2.java # ChatClient V2写法
│ │ └── ChatModelController.java # ChatModel 示例
│ └── Saa03ChatModelChatClientApplication.java
package com.atguigu.study.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;
/**
* 配置类:基于自动注入的 ChatModel 构建 ChatClient
*/
@Configuration
public class SaaLLMConfig
{
/**
* 创建一个命名的 ChatClient(基于 dashScopeChatModel)
* 名称为 "dashScopeChatClient"
*/
@Bean("dashScopeChatClient")
public ChatClient dashScopeChatClient(ChatModel dashScopeChatModel)
{
return ChatClient.builder(dashScopeChatModel).build();
}
}
package com.atguigu.study.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;
/**
* 使用 @Autowired 注入 ChatClient
*/
@RestController
public class ChatClientControllerV2
{
// 直接注入已注册的 ChatClient Bean
@Autowired
private ChatClient chatClient;
@GetMapping("/chatclientv2/dochat")
public String doChat(@RequestParam(name = "msg", defaultValue = "2加9等于几") String msg)
{
// 简洁的链式调用
return chatClient.prompt()
.user(msg) // 设置用户消息
.call() // 调用
.content(); // 获取文本内容
}
}
@GetMapping("/stream")
public Flux<String> stream(String msg)
{
return chatClient.prompt()
.user(msg)
.stream() // 开启流式模式
.content();
}
// 更加简洁的 Lambda 写法
@GetMapping("/chat")
public String chat(String msg)
{
return chatClient.prompt(msg).call().content();
}
// 或者更复杂点
ChatResponse response = chatClient.prompt()
.system("你是一个专业的%s", "Java工程师")
.user(msg)
.call()
.chatResponse();
String result = response.getResult().getOutput().getText();
| 概念 | 说明 |
|---|---|
| ChatModel | 底层AI调用接口,直接与模型通信 |
| ChatClient | 高级封装,提供链式调用的便捷API |
| @Bean | Spring 中用于注册组件的注解 |
| 链式调用 | 通过 Builder 模式实现的方法链 |
┌─────────────────────────────────────────────────┐
│ 选择决策树 │
│ │
│ 需要精细控制底层请求? ──YES──→ 使用 ChatModel │
│ │ │
│ NO │
│ ↓ │
│ 直接开发AI应用功能? ──YES──→ 使用 ChatClient │
│ │
└─────────────────────────────────────────────────┘
本章重点:
下章剧透(s04):