Spring AI ChatModel 与 ChatClient 完整核心解析

一、Spring AI 整体分层概览

Spring AI 是 Spring 官方推出的大模型集成框架,统一屏蔽 OpenAI、通义千问、文心一言、Claude、Ollama 等各类大模型厂商底层 API 差异,提供一套标准化 AI 开发编程模型。
 
整个对话能力核心分为两层:
  1. 底层抽象:ChatModel:大模型统一能力接口,定义所有对话模型通用行为;
  2. 上层门面:ChatClient:基于 ChatModel 封装的流式构建器,简化调用、提示词管理、参数配置、工具调用,业务开发首选。
二者关系:ChatClient 持有 ChatModel 实例,是 ChatModel 的高阶封装,不替代 ChatModel。

二、ChatModel 底层核心抽象

2.1 核心接口定义

org.springframework.ai.chat.model.ChatModel
 
public interface ChatModel {
    // 单次同步对话,返回完整响应
    ChatResponse call(ChatPrompt prompt);
    // 流式对话,分段返回结果(打字机效果)
    Flux<ChatResponse> stream(ChatPrompt prompt);
}

  

 
所有厂商模型都实现该接口:
  • OpenAiChatModel
  • OllamaChatModel
  • TongYiChatModel(阿里通义)
  • BaiduErnieChatModel(文心一言)
  • AnthropicChatModel(Claude)

2.2 配套核心数据模型

  1. ChatPrompt:对话提示词载体,承载多条消息
    ChatPrompt prompt = new ChatPrompt(
        new SystemMessage("你是专业Java工程师"),
        new UserMessage("解释Spring AI ChatModel")
    );
    

      

  2. Message 消息体系
    • SystemMessage:系统角色设定,定义 AI 身份、规则
    • UserMessage:用户输入提问
    • AssistantMessage:AI 返回回答
    • ToolMessage:工具调用返回结果(Function Calling)
  3. ChatResponse:大模型统一返回体
    • List<Generation> generations:AI 生成内容
    • ChatMetadata metadata:token 消耗、模型名称、请求 ID 等元数据
  4. ChatOptions:模型参数统一配置(温度、topP、最大 token、流式开关、工具列表等)
     
    各厂商提供对应实现:OpenAiChatOptionsOllamaOptions

2.3 ChatModel 原生使用示例(底层原生写法)

适合底层自定义扩展、精细控制场景:
@Bean
public ChatModel ollamaChatModel(OllamaProperties properties) {
    return new OllamaChatModel(OllamaApi.builder()
            .baseUrl(properties.getBaseUrl())
            .build(),
            OllamaOptions.builder()
                    .model("qwen:7b")
                    .temperature(0.7)
                    .build()
    );
}

// 业务调用
@Autowired
private ChatModel chatModel;

public String rawChat() {
    // 构建提示词
    ChatPrompt prompt = new ChatPrompt(
            new SystemMessage("简洁回答问题"),
            new UserMessage("什么是ChatModel")
    );
    // 同步调用
    ChatResponse response = chatModel.call(prompt);
    return response.getResult().getOutput().getText();
}

// 流式输出
public Flux<String> streamChat() {
    return chatModel.stream(prompt)
            .map(resp -> resp.getResult().getOutput().getText());
}
 

  

2.4 ChatModel 优缺点

优势
  1. 极致底层可控,可手动组装所有消息、参数、工具;
  2. 无额外封装损耗,适合框架二次开发、自定义拦截逻辑;
  3. 完全统一 API,切换模型仅替换实现类,业务代码无需大幅改动。
劣势
  1. 模板代码冗余,每次调用都要手动构建 ChatPromptMessage
  2. 提示词模板、变量替换、记忆管理、工具注册需要自己封装;
  3. 链式调用可读性差,复杂对话逻辑代码臃肿。

三、ChatClient 上层门面工具

3.1 定位与设计目的

ChatClient 是 Spring AI 为业务开发提供的流畅构建器 API,基于 ChatModel 封装,解决原生 ChatModel 代码繁琐问题,内置能力:
  • 流式链式构建语法;
  • 内置提示词模板、变量渲染;
  • 一键配置系统提示词、模型参数;
  • 统一对话记忆(ChatMemory)集成;
  • 工具函数(Function Calling)快速注册;
  • 拦截器(Advisor)全局切面管理;
  • 同步 / 流式 / 实体类型返回一键切换。

3.2 ChatClient 创建方式

方式 1:自动注入(推荐,自动装配)

@Autowired
private ChatClient chatClient;

  

 
自动装配条件:容器中存在 ChatModel Bean,Spring AI 自动生成 ChatClient

方式 2:手动构建自定义 ChatClient

@Bean
public ChatClient customChatClient(ChatModel chatModel) {
    return ChatClient.builder(chatModel)
            // 全局默认系统提示词
            .defaultSystem("你是资深后端开发,回答简洁")
            // 全局默认参数
            .defaultOptions(OllamaOptions.builder().temperature(0.5).build())
            // 全局拦截器
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();
}

  

3.3 ChatClient 完整核心用法示例

3.3.1 基础同步问答

String res = chatClient.prompt()
        .system("你是Java技术博主")
        .user("讲解Spring AI ChatClient")
        .call()
        .content();

  

3.3.2 提示词模板 + 变量占位

String res = chatClient.prompt()
        .system("根据{language}讲解{topic},简短输出")
        .user(u -> u.param("language", "Java").param("topic", "ChatModel"))
        .call()
        .content();

  

3.3.3 流式打字机输出(Web 实时对话)

public Flux<String> streamReply(String question) {
    return chatClient.prompt()
            .user(question)
            .stream()
            .content();
}

  

3.3.4 强类型实体返回(结构化输出,无需手动解析 JSON)

// 定义接收实体
record CodeResp(String title, String code, String explain) {}

CodeResp resp = chatClient.prompt()
        .user("写一段Spring AI调用代码")
        .call()
        .entity(CodeResp.class);

  

3.3.5 集成对话记忆(多轮上下文)

// 内存记忆,支持会话隔离
ChatMemory memory = new InMemoryChatMemory();
String reply1 = chatClient.prompt()
        .advisors(new MessageChatMemoryAdvisor(memory))
        .user("什么是ChatModel")
        .call()
        .content();

String reply2 = chatClient.prompt()
        .advisors(new MessageChatMemoryAdvisor(memory))
        .user("它和ChatClient区别")
        .call()
        .content();

  

3.3.6 Function Calling 工具调用

// 自定义工具
@Tool
public String getWeather(String city) {
    return city + "今日25℃,晴天";
}

// 注册工具调用
String res = chatClient.prompt()
        .tools(this)
        .user("北京今天天气")
        .call()
        .content();

  

 

3.4 ChatClient 核心内置能力:Advisor 拦截器

Advisor 是 ChatClient 的切面扩展点,执行链路:
 
请求前置处理 → 调用ChatModel → 响应后置处理
 
官方内置常用 Advisor:
  1. MessageChatMemoryAdvisor:对话上下文记忆;
  2. SimpleLoggerAdvisor:打印请求 / 响应日志;
  3. PromptTemplateAdvisor:统一处理提示词模板;
  4. RetrievalAugmentationAdvisor:RAG 检索增强接入。
支持自定义 Advisor 实现鉴权、限流、敏感词过滤、日志埋点。

3.5 ChatClient 优缺点

优势
  1. 流畅链式 API,业务代码极简,可读性极强;
  2. 内置模板、记忆、工具、结构化输出,开箱即用;
  3. 全局默认配置统一管理,不用每个请求重复设置参数;
  4. Advisor 切面统一拦截,集中处理日志、RAG、上下文;
  5. 支持强类型返回,省去 JSON 手动解析。
劣势
  1. 重度封装,底层细节隐藏,极端自定义场景不如原生 ChatModel 灵活;
  2. 多层封装轻微增加调用链路,极致性能场景可选用原生 ChatModel。

四、ChatModel vs ChatClient 核心对比表

表格
 
对比维度ChatModelChatClient
定位 底层标准接口,统一大模型抽象 上层业务门面,简化开发工具
依赖关系 无依赖,最底层 持有 ChatModel,封装其能力
编码风格 命令式,手动组装 ChatPrompt、Message 流式链式 Builder,极简代码
提示词模板 需手动实现 原生内置变量渲染
多轮记忆 手动拼接历史消息 内置 ChatMemory Advisor 一键接入
结构化输出 手动解析 ChatResponse .entity(Class) 自动映射实体
工具调用 手动组装 ToolDefinition tools() 快速注册 @Tool 方法
扩展方式 自行封装工具类 Advisor 切面统一拦截处理
适用场景 框架封装、底层中间件、精细控制 业务接口、Web 对话、快速开发

五、两者配合最佳实践方案

企业级项目标准分层使用规范:
  1. 配置层:注入对应厂商 ChatModel Bean,统一管理模型地址、密钥、基础参数;
  2. 全局门面层:基于 ChatModel 构建全局 ChatClient,统一配置系统提示词、日志 Advisor、全局工具;
  3. 业务层(90% 场景):直接使用自动注入的 ChatClient 完成问答、流式、RAG、多轮对话;
  4. 底层扩展场景(10%):自定义拦截、特殊模型参数、自研记忆逻辑时,直接操作原生 ChatModel。

标准完整配置示例

 
@Configuration
public class SpringAiConfig {

    // 1. 底层ChatModel
    @Bean
    public ChatModel ollamaChatModel(OllamaProperties props) {
        OllamaApi api = OllamaApi.builder()
                .baseUrl(props.getBaseUrl())
                .build();
        OllamaOptions options = OllamaOptions.builder()
                .model("qwen:7b")
                .temperature(0.6)
                .build();
        return new OllamaChatModel(api, options);
    }

    // 2. 全局ChatClient,基于ChatModel封装
    @Bean
    public ChatClient chatClient(ChatModel chatModel) {
        return ChatClient.builder(chatModel)
                .defaultSystem("你是专业后端开发,回答精简专业")
                .defaultAdvisors(new SimpleLoggerAdvisor())
                .build();
    }

    // 3. 对话记忆Bean,供业务注入
    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }
}

  

六、常见开发误区总结

  1. 只使用 ChatModel 写业务:大量重复构建消息、模板代码,维护成本高;
  2. 误以为 ChatClient 可以脱离 ChatModel:ChatClient 只是封装,底层必须依赖 ChatModel;
  3. 全局配置重复定义:不要每次 prompt 都重复设置 system、temperature,统一在 ChatClient builder 全局配置;
  4. 多轮对话手动拼接历史消息:优先使用 MessageChatMemoryAdvisor,避免手动维护上下文;
  5. 流式输出自行拼接字符串:ChatClient .stream().content() 已分段返回,直接返回给前端 SSE 即可。

七、全文总结

  1. ChatModel 是标准底座:Spring AI 所有对话模型的统一抽象,抹平各大厂商 API 差异,提供同步 / 流式基础调用能力,面向底层扩展开发;
  2. ChatClient 是业务工具:基于 ChatModel 的高层封装,流畅 Builder API,内置模板、记忆、工具、结构化返回、切面拦截,日常业务开发首选;
  3. 二者互补而非替代:底层能力靠 ChatModel,业务简化靠 ChatClient;企业项目标准架构为「ChatModel 配置 + ChatClient 全局门面 + 业务层调用 ChatClient」;
  4. 开发选型建议:普通问答、流式对话、RAG、多轮聊天全部使用 ChatClient;自研中间件、深度自定义模型请求逻辑、极致性能优化场景直接操作 ChatModel。

 

微信图片_20260323111723_42_204

 

posted @ 2026-07-06 15:35  程序员食堂  阅读(15)  评论(0)    收藏  举报