Spring AI 里 ChatClient 和 ChatModel 有什么区别?什么时候该用哪个?

结论先行:

  1. ChatClient 与 ChatModel 不是替代关系 :ChatClient 是高层业务调用 API,ChatModel 是底层模型调用抽象;ChatClient 通常封装 ChatModel。

  2. 共用方式优先选"统一 AiService + 底层共用 ChatModel" :业务代码只依赖 AiService,实现层用 ChatClient,避免业务到处直接绑定具体模型厂商。

  3. 多模型场景不要全局可变替换 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 来回替换,否则并发请求可能互相影响。更稳妥的做法是使用不可变配置和显式路由。

相关推荐
小成202303202651 小时前
C++~05异常处理
开发语言·c++
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 圈子功能的表设计方案
java·开发语言·交友
Pniubi1 小时前
事务(Spring&MySQL)
数据库·sql·spring
文丑颜不良啊1 小时前
LeetCode601~625题目解析
java·leetcode
文丑颜不良啊2 小时前
LeetCode651~675题目解析
java·leetcode
frjc2 小时前
Spring WebFlux SSE 长连接,可以替换为 Java 21 虚拟线程吗?
java·人工智能·spring·ai·ai编程
轻舟技术A2 小时前
Rust 重写 Pi:会话启动耗时降 91%,就绪内存少 78%
开发语言·后端·rust
chansonzhang2 小时前
Multi-Agent
ai·强化学习·multi-agent