结论先行:
-
ChatClient 与 ChatModel 不是替代关系 :
ChatClient是高层业务调用 API,ChatModel是底层模型调用抽象;ChatClient通常封装ChatModel。 -
共用方式优先选"统一 AiService + 底层共用 ChatModel" :业务代码只依赖
AiService,实现层用ChatClient,避免业务到处直接绑定具体模型厂商。 -
多模型场景不要全局可变替换 ChatModel :应配置多个不可变
ChatModel/ChatClient,通过显式路由按业务选择,避免并发请求互相影响。
一. 核心区别
| 对比项 | ChatClient | ChatModel |
|---|---|---|
| 定位 | 高层业务调用 API | 底层模型调用接口 |
| 主要用途 | 组织业务对话流程 | 调用具体大模型 |
| Prompt 构建 | 提供流畅式 API | 通常接收标准化请求对象 |
| Advisor 等扩展 | 可集成 | 不属于核心职责 |
| 普通调用 | call()、content() 等 |
call(Prompt) |
| 流式调用 | stream() |
stream(Prompt) |
具体方法会因 Spring AI 版本有所差异。
简单理解:
-
ChatClient面向应用开发者,负责组织对话调用,包括 Prompt、Advisor、上下文和输出转换。 -
ChatModel是统一模型调用接口,负责生成响应、流式生成和统一模型请求,底层由 OpenAI、Anthropic、Ollama 等具体实现适配。
注意:ChatClient 不是另一个大模型,它通常是对 ChatModel 的上层封装。
二. 为什么两者都存在?
直接调用 ChatModel:
java
ChatResponse response = chatModel.call(
new Prompt("请介绍一下 Spring AI")
);
使用 ChatClient:
java
String answer = chatClient.prompt()
.user("请介绍一下 Spring AI")
.call()
.content();
ChatClient 更适合组织业务逻辑;ChatModel 更适合统一模型调用、底层适配和基础设施封装。
三. 如何做到共用?
先明确:你想共用的是模型实例、业务代码,还是整个调用流程。通常有三种方案。
方案 A:多个业务模块共用同一个 ChatModel
适合多个服务模块都需要调用同一个模型的场景。
java
@Configuration
public class AiConfig {
@Bean
public ChatClient chatClient(ChatModel chatModel) {
return ChatClient.builder(chatModel).build();
}
}
业务层注入 ChatClient;需要更底层控制的模块可以直接注入 ChatModel。这样可以共用底层模型配置和模型客户端,避免重复创建实例。
方案 B:封装统一 AI 服务(更推荐)
如果项目里有多个业务,例如客服、知识库、文本总结,不建议让业务代码到处直接依赖 ChatModel。可以统一封装:
java
public interface AiService {
String chat(String prompt);
Flux<String> stream(String prompt);
}
实现层使用 ChatClient:
java
@Service
public class DefaultAiService implements AiService {
private final ChatClient chatClient;
public DefaultAiService(ChatClient chatClient) {
this.chatClient = chatClient;
}
@Override
public String chat(String prompt) {
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
@Override
public Flux<String> stream(String prompt) {
return chatClient.prompt()
.user(prompt)
.stream()
.content();
}
}
这里的 Flux 需要 Reactor 依赖,且具体流式返回类型要与所用 Spring AI 版本匹配。
优点:
-
业务代码只依赖
AiService,不绑定具体模型厂商; -
可以统一处理日志、超时、异常、限流和监控;
-
更换模型或调整调用方式时,主要修改实现层;
-
普通调用与流式调用可以共用统一业务入口。
方案 C:共用 ChatClient,但动态切换模型
如果不同业务需要不同模型,例如普通对话使用低成本模型、复杂推理使用高性能模型,可以配置多个 ChatModel 或 ChatClient,通过路由层按业务选择。
不要简单地把一个全局可变的 ChatModel 来回替换,否则并发请求可能互相影响。更稳妥的做法是使用不可变配置和显式路由。