在这里插入图片描述

Pre

大模型开发 - 01 Spring AI 核心特性一览

大模型开发 - 02 Spring AI Concepts

大模型开发 - 03 QuickStart_借助DeepSeekChatModel实现Spring AI 集成 DeepSeek

大模型开发 - 04 QuickStart_DeepSeek 模型调用流程源码解析:从 Prompt 到远程请求

大模型开发 - 06 QuickStart_本地大模型私有化部署实战:Ollama + Spring AI 全栈指南


概述

在当今大模型(LLM)百花齐放的时代,开发者面临着一个现实挑战:不同厂商提供的模型(如 OpenAI、DeepSeek、Anthropic、Google Gemini、阿里通义千问等)往往拥有各自独立的 SDK 和 API 接口。这不仅增加了学习成本,也使得代码难以复用和迁移。

为了解决这一问题,Spring AI 提出了一个统一的抽象层 —— ChatClient。它基于底层的 ChatModel 进行封装,提供了一套通用、灵活且面向未来的 API,让开发者可以“一次编写,多模型运行”。

本文将深入剖析 ChatClient 的设计理念、核心特性、使用方式,并通过实战示例展示其强大之处。


一、为什么需要 ChatClient?

1.1 问题背景:模型碎片化

假设你正在开发一个智能客服系统,初期使用 OpenAI 的 GPT-4,后期想切换为国产的 DeepSeek 或通义千问。如果你直接调用各厂商 SDK:

// OpenAI
OpenAiService service = new OpenAiService(apiKey);
service.createChatCompletion(...);

// DeepSeek
DeepSeekClient client = new DeepSeekClient(apiKey);
client.chat(...);

你会发现:业务逻辑与具体模型强耦合,切换模型意味着大量代码重构。

1.2 Spring AI 的解决方案

Spring AI 引入了两层抽象:

  • ChatModel:底层接口,定义了与大模型交互的基本契约(如 call(Prompt prompt)),每个模型厂商提供自己的实现(如 OpenAiChatModel, DeepSeekChatModel)。
  • ChatClient高层封装,基于 ChatModel 构建,提供更易用、功能更丰富的 Fluent API,支持系统提示、工具调用、流式响应、记忆管理等。

核心理念面向接口编程,而非具体实现ChatClient 是你日常开发的首选,ChatModel 仅在需要深度定制时使用。


二、ChatClient 的核心优势

特性 说明
统一 API 无论底层是 GPT、DeepSeek 还是 Qwen,代码写法一致
Fluent 链式调用 .prompt().user("...").system("...").call() 语法简洁直观
内置系统提示(System Prompt) 轻松设置角色、行为约束
结构化响应支持 可配合 @JsonFormat 返回 POJO
聊天记忆(Memory) 自动维护对话上下文(需配合 ChatMemory
工具调用(Function Calling / Tools) 声明式注册工具,模型自动调用
流式响应(Streaming) 支持 Flux<String> 实现实时输出
灵活构建 通过 ChatClient.Builder 动态配置模型、选项等

三、ChatClient 基本使用

3.1 自动注入默认模型(单模型场景)

当项目中只引入了一个模型依赖(如 spring-ai-openai-spring-boot-starter),Spring Boot 会自动创建一个 ChatModel Bean。

@SpringBootTest
public class ChatClientTest {

    @Test
    public void testChatClient(ChatClient.Builder builder) {
        ChatClient chatClient = builder.build();
        
        String response = chatClient.prompt()
                .user("Hello, what is Spring AI?")
                .call()
                .content();
                
        System.out.println(response);
    }
}

⚠️ 注意:必须通过 ChatClient.Builder 构建,不能直接 new ChatClient()

Stream输出

      /**
     * 测试聊天客户端流式响应功能
     * 
     * @param chatClientBuilder 聊天客户端构建器,用于创建ChatClient实例
     */
    @Test
    public void testChatClientStream(@Autowired ChatClient.Builder chatClientBuilder){
        // 构建聊天客户端实例
        ChatClient chatClient = chatClientBuilder.build();
        
        // 发送用户消息并以流式方式接收响应内容
        chatClient.prompt().user("你好,请介绍你自己")
                .stream()
                .content()
                .toIterable()
                .forEach(System.out::println);
    }

在这里插入图片描述


3.2 显式指定模型(多模型场景)

若项目中存在多个 ChatModel(如同时引入 OpenAI 和 DeepSeek),Spring 无法自动注入,此时需手动指定:

@SpringBootTest
public class ChatClientTest {

    @Test
    public void testWithDeepSeek(@Autowired DeepSeekChatModel deepSeekModel) {
        ChatClient chatClient = ChatClient.builder(deepSeekModel).build();
        
        String response = chatClient.prompt()
                .user("Explain quantum computing in simple terms.")
                .call()
                .content();
                
        System.out.println(response);
    }
}

这种方式让你在运行时动态选择模型,非常适合 A/B 测试或多租户场景。


四、高级功能实战

4.1 添加系统提示(System Prompt)

系统提示用于设定 AI 的角色或行为准则:

String response = chatClient.prompt()
    .system("You are a helpful assistant specialized in Java programming.")
    .user("How to create a thread in Java?")
    .call()
    .content();

💡 系统提示会自动插入到对话历史的最前面,对模型行为有强引导作用。

4.2 流式响应(Streaming)

对于长文本生成或实时聊天场景,流式输出能显著提升用户体验:

@Test
public void testChatStream() {
    Flux<String> stream = chatClient.prompt()
        .user("Write a short poem about spring.")
        .stream()
        .content();

    // 阻塞式消费(测试用)
    stream.toIterable().forEach(System.out::print);
    
    // 实际 Web 场景中可返回 Flux 给前端(如 SSE)
}

输出效果(逐字/逐词返回):

The breeze whispers through the trees,
New leaves dancing in the breeze...

4.3 结构化输出(返回 Java 对象)

结合 Spring AI 的 @JsonFormat,可让模型返回结构化数据:

public record Weather(String location, String temperature, String condition) {}

Weather weather = chatClient.prompt()
    .user("What's the weather in Beijing today?")
    .call()
    .entity(Weather.class); // 自动解析 JSON

要求模型支持 JSON 模式(如 GPT-4o、DeepSeek-Coder 等),并在提示中明确要求返回 JSON。


五、ChatClient vs ChatModel:如何选择?

维度 ChatClient ChatModel
抽象层级 高层、面向应用 底层、面向模型
使用复杂度 低(Fluent API) 高(需手动构造 Prompt)
功能丰富度 支持记忆、工具、流式等 仅基础 call()
适用场景 90% 以上业务开发 深度定制、性能调优、源码学习
迁移成本 几乎为零

官方建议优先使用 ChatClient,除非它无法满足需求


六、源码学习建议

虽然日常开发用 ChatClient,但理解其底层原理有助于排查问题和扩展功能:

  1. 查看 ChatClientbuild() 方法,了解如何包装 ChatModel
  2. 分析 Prompt 对象的构建过程(user(), system() 如何组装消息)
  3. 研究 call()stream() 的实现差异
  4. 探索 DefaultChatClient 中如何处理工具调用和记忆

🔍 提示:ChatClient 本质是一个 装饰器(Decorator),它在 ChatModel 之上添加了便利层。


七、总结

ChatClient 是 Spring AI 为开发者提供的最佳实践入口。它通过统一的 API 屏蔽了底层模型的差异,同时提供了系统提示、流式响应、工具调用等现代 LLM 应用所需的核心能力。

记住这个开发原则

面向 ChatClient 编程,而非具体模型

这样,无论未来模型如何演进,你的业务代码都能从容应对,真正做到“模型无关,业务先行”。


延伸阅读

在这里插入图片描述

Logo

更多推荐