一、定位与设计哲学:底层引擎 vs 业务驾驶舱
在 Spring AI 的架构中,与大语言模型(LLM)交互的 API 被清晰地划分为两层:
二者不是替代关系,而是分层协作关系。ChatClient 内部持有 ChatModel 实例,通过 Advisor 机制横向增强能力。
二、ChatModel:直面大模型的“基础通道”
2.1 核心职责
接收
Prompt(包含UserMessage、SystemMessage等)调用底层 LLM API,返回
ChatResponse或Flux<ChatResponse>处理 Provider 特有的参数映射(如
temperature、top_p、model等)
2.2 典型用法
@Service
public class SimpleChatService {
private final ChatModel chatModel; // 自动注入具体实现,如 OpenAiChatModel
public SimpleChatService(ChatModel chatModel) {
this.chatModel = chatModel;
}
public String ask(String question) {
Prompt prompt = new Prompt(
List.of(new SystemMessage("你是一个专业的Java助手"),
new UserMessage(question))
);
ChatResponse response = chatModel.call(prompt);
return response.getResult().getOutput().getContent();
}
}2.3 适用场景与局限
✅ 适合:
简单单次问答、批量非对话式任务
自研 AI 网关/代理层,需完全控制请求生命周期
对内存/性能有极致要求,不想承担额外封装开销
❌ 局限:
无状态:每次调用独立,需手动拼接历史消息实现“多轮对话”
函数调用(Tool Calling)需手动构造
ToolDefinition和解析响应流式响应需手动处理
Flux<ChatResponse>的 delta 拼接重试、降级、日志追踪需自行集成 Resilience4j/Micrometer
三、ChatClient:面向对话场景的“高级编排器”
3.1 核心特性
Spring AI 官方推荐的生产级入口,采用链式构建模式,内置现代 LLM 应用所需的核心能力:
3.2 典型用法
@Service
public class AdvancedChatService {
private final ChatClient chatClient;
public AdvancedChatService(ChatClient.Builder builder) {
this.chatClient = builder
.defaultAdvisors(new RetryAdvisor(3, Duration.ofSeconds(1)))
.build();
}
public String askWithTools(String question) {
return chatClient.prompt()
.system("你是一个具备联网搜索和代码执行能力的助手。")
.user(question)
.functions("searchWeb", "executeCode") // 注册 Tool 名称
.advisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())) // 自动记忆
.call()
.content();
}
}3.3 适用场景与优势
✅ 适合:
聊天机器人、智能客服、Copilot 类应用
需要函数调用、多轮对话、流式输出的生产系统
追求开发效率、代码可读性与可维护性的团队
⚠️ 注意:
ChatClient.Builder每次构建会创建新实例,但底层ChatModel与线程池是共享的高级特性(如
Advisor、ChatMemory)需额外引入依赖或自行实现接口
四、核心对比:一张表看懂差异
五、如何选型?给开发者的决策树
📌 官方立场:Spring AI 团队明确推荐 新应用优先使用 ChatClient。ChatModel 主要作为 SPI(服务提供者接口)供底层实现使用,或供需要完全控制请求生命周期的场景调用。
六、实战最佳实践
6.1 依赖注入规范
@Configuration
public class AiConfig {
@Bean
public ChatClient chatClient(ChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultSystem("你是一个专业、严谨的AI助手。")
.defaultAdvisors(new RetryAdvisor(2, Duration.ofMillis(500)))
.build();
}
}✅ ChatModel 与 ChatClient 均为线程安全,可直接注入为单例。
6.2 流式输出 + SSE 场景
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamChat(@RequestParam String q) {
return chatClient.prompt().user(q).stream().content()
.map(chunk -> ServerSentEvent.builder(chunk).build());
}6.3 函数调用正确姿势
@Tool(description = "查询当前天气")
public String getWeather(@Param("city") String city) {
return "晴天,25°C";
}
// 注册 Tool
ChatClient client = ChatClient.builder(chatModel)
.defaultFunctions("getWeather") // 或传入 bean 名称
.build();6.4 性能与内存提醒
避免在每次请求中
ChatClient.builder(...).build(),应在初始化时构建并复用InMemoryChatMemory仅适用于开发/测试,生产请替换为 Redis/DB 实现流式响应注意背压(Backpressure)控制,避免 OOM
七、结语
ChatModel 与 ChatClient 的关系,正如 发动机与整车控制系统:前者提供原始动力,后者负责换挡、导航、安全辅助与用户体验。在 Spring AI 的设计哲学中,“简单场景不复杂,复杂场景可扩展” 是核心原则。
🚀 起步/业务开发:直接拥抱
ChatClient,享受声明式 API 与内置企业级能力🔧 底层定制/网关开发:下沉到
ChatModel,掌握原始控制力📦 架构演进:二者可随时切换,
ChatClient的Advisor机制让增强能力插件化
随着 Spring AI 1.0 进入 GA 阶段,ChatClient 的 API 已趋于稳定。建议在新项目中以它为默认入口,将 ChatModel 留给需要深度定制的边界场景。
📖 延伸阅读
Spring AI 官方文档:ChatClient Reference
Advisor 机制详解:Resilience & Observability
函数调用指南:Tool Calling
💬 欢迎在评论区分享你的实际使用场景与踩坑经验,我们一起构建更健壮的 AI 应用架构。
评论区