基于SpringAI实现简易聊天对话
简介
本文旨在记录学习和实践 Spring AI Alibaba 提供的 ChatClient 组件的过程。ChatClient 是 Spring AI 中用于与大语言模型(LLM)进行交互的高级 API,它通过流畅(Fluent)的编程接口,极大地简化了构建聊天应用程序的复杂度。相比直接使用底层的 ChatModel,ChatClient 封装了提示词构建、响应处理、结构化输出、流式响应以及与 RAG、聊天记忆等高级功能的集成。
通过本文的学习,我们将掌握:
ChatClient 的核心概念和优势。
如何创建和配置 ChatClient 实例。
使用 ChatClient 处理不同类型的 AI 响应(文本、完整响应对象、结构化实体、流式响应)。
结合 Spring Boot 快速搭建一个可交互的聊天后端服务。
了解 Server-Sent Events (SSE) 在流式响应中的应用。
我们将从官方文档入手,结合代码实践,逐步深入理解 ChatClient 的使用方法。
ChatClient相关原理
核心知识点:ChatClient in Spring AI Alibaba
ChatClient 是 Spring AI Alibaba 提供的一个更高级别的 API,用于与 AI 模型进行交互。它旨在简化开发流程,特别是当应用程序需要组合多个组件(如提示词模板、聊天记忆、模型本身、输出解析器、RAG 组件等)时。
- ChatClient 简介
目的: 提供一个 Fluent API (流畅 API) 与 AI 模型通信,支持同步和反应式 (Reactive) 编程模型。
优势:
隐藏复杂性: 将与 LLM (Large Language Model) 及其他组件(提示词模板、聊天记忆、RAG 等)交互的复杂性封装起来。
减少样板代码: 相比直接使用 ChatModel、Message 等原子 API,ChatClient 减少了需要编写的重复性代码。
类似服务层: 在应用程序中扮演类似服务层 (Service Layer) 的角色,直接为应用提供 AI 服务。
快速组装交互流程: 使用 Fluent API 可以快速地组装一个完整的 AI 交互流程。
基础功能:
定制和组装模型的输入 (Prompt)。
格式化解析模型的输出 (结构化输出 Structured Output)。
调整模型交互参数 (ChatOptions)。
高级功能:
聊天记忆 (Chat Memory)。
工具/函数调用 (Function Calling)。
检索增强生成 (RAG)。
- 创建 ChatClient
创建 ChatClient 实例需要使用 ChatClient.Builder 对象。有两种主要方式获取 ChatClient:
方式一:使用自动配置的 ChatClient.Builder (推荐)
Spring Boot 会根据你的依赖和配置自动创建一个默认的 ChatClient.Builder Bean。
你只需要在你的类中注入这个 ChatClient.Builder,然后调用 build() 方法即可获得 ChatClient 实例。
示例代码 (带详细注释):
import org.springframework.ai.chat.client.ChatClient; // 导入 ChatClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 注解,用于处理 HTTP GET 请求
import org.springframework.web.bind.annotation.RequestParam; // 导入 RequestParam 注解,用于获取请求参数
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 注解,标识这是一个 RESTful 控制器 // 声明这是一个 Spring MVC 的 REST 控制器,其方法默认返回 JSON 或其他指定格式的数据
public class ChatController {// 声明一个 final 的 ChatClient 成员变量,用于与 AI 模型交互private final ChatClient chatClient;// 控制器的构造函数// Spring Boot 会自动查找并注入一个 ChatClient.Builder 类型的 Beanpublic ChatController(ChatClient.Builder builder) {// 使用注入的 builder 构建 ChatClient 实例,并赋值给成员变量// builder 会使用自动配置好的底层 ChatModel (例如通义千问模型) 和其他默认设置this.chatClient = builder.build();}("/chat") // 将 HTTP GET 请求映射到 /chat 路径// @RequestParam("input") String input 表示从请求参数中获取名为 "input" 的值,并赋给 input 变量public String chat(("input") String input) {// 使用 chatClient 的 Fluent API 开始构建一个请求return this.chatClient.prompt() // 1. 调用 prompt() 方法开始构建一个 Prompt (提示).user(input) // 2. 调用 user() 方法设置用户角色的消息内容,内容为传入的 input 字符串.call() // 3. 调用 call() 方法,执行与 AI 模型的同步调用 (发送请求并等待响应).content(); // 4. 调用 content() 方法,从 AI 模型的响应 (ChatResponse) 中提取文本内容并返回}
}
方式二:以编程方式创建 ChatClient
禁用自动配置: 如果你想完全控制 ChatClient 的创建过程,或者需要使用多个不同的 ChatModel 实例,可以先禁用 ChatClient.Builder 的自动配置。在 application.properties 或 application.yml 中设置:
spring.ai.chat.client.enabled=false
手动创建: 然后,你可以手动创建 ChatClient.Builder,并传入你想要使用的 ChatModel 实例。
示例代码 (带详细注释):
import org.springframework.ai.chat.client.ChatClient; // 导入 ChatClient 类
import org.springframework.ai.chat.model.ChatModel; // 导入 ChatModel 接口// ... 其他 importpublic class MyService {private final ChatClient customChatClient;// 假设 myChatModel 是你通过其他方式配置或注入的特定 ChatModel 实例public MyService(ChatModel myChatModel) {// 方法一:使用 ChatClient.builder() 静态方法,并传入 ChatModel 实例ChatClient.Builder builder = ChatClient.builder(myChatModel);// 这里可以继续使用 builder 配置其他选项,例如 .defaultOptions(), .defaultSystem(), etc.this.customChatClient = builder.build(); // 构建 ChatClient 实例// 方法二:使用 ChatClient.create() 静态方法,这是一个更简洁的方式// 它会使用传入的 ChatModel 和默认的 Builder 设置来创建 ChatClient// this.customChatClient = ChatClient.create(myChatModel);}public String askSomething(String question) {// 使用手动创建的 customChatClient 进行交互return customChatClient.prompt().user(question).call().content();}
}
- 处理 ChatClient 响应
ChatClient API 提供了多种方式来处理和格式化来自 AI 模型的响应:
返回 ChatResponse:
call() 或 stream() 方法默认返回 ChatResponse 对象。
ChatResponse 是一个丰富的结构,包含:
AI 生成的实际结果 (Generation)。
与响应生成相关的元数据 (例如模型名称、token 使用情况等)。
可能包含多个子响应结果 (如果模型支持,例如返回多个候选答案)。
你可以从 ChatResponse 中获取详细信息。
示例: (在上面的 /chat 接口示例中,.call() 返回的就是 ChatResponse,之后 .content() 是从中提取内容)
返回实体类 (Entity) - 结构化输出:
ChatClient 支持将 AI 模型的文本输出自动映射为你定义的 Java POJO (Plain Old Java Object)。这对于需要固定格式输出的场景非常有用。
使用 .entity(YourClass.class) 方法来指定期望的输出类型。
示例代码 (带详细注释):
import org.springframework.ai.chat.client.ChatClient; // 导入 ChatClient 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 注解
import org.springframework.web.bind.annotation.RequestParam; // 导入 RequestParam 注解
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 注解
public class StructuredOutputController {private final ChatClient chatClient;// 定义一个简单的 POJO 类,用于接收结构化输出static class ActorFilms {public String actor; // 演员姓名public List<String> movies; // 电影列表}public StructuredOutputController(ChatClient.Builder builder) {this.chatClient = builder.build();}("/actor-films") // 将 HTTP GET 请求映射到 /actor-films 路径public ActorFilms getActorFilms(("actor") String actorName) {// 使用 chatClient 的 Fluent APIreturn this.chatClient.prompt()// 设置用户消息,要求模型列出指定演员的电影,并明确要求 JSON 格式.user("Generate a list of films for the actor " + actorName + ". Respond in JSON format with keys 'actor' and 'movies'.").call() // 执行与 AI 模型的同步调用// 调用 entity() 方法,并传入 ActorFilms.class// ChatClient 会尝试将 AI 返回的文本内容 (预期是 JSON 字符串)// 解析并映射到 ActorFilms 类的实例中.entity(ActorFilms.class);}
}
流式响应 (Streaming):
对于需要实时显示或处理部分结果的场景 (例如聊天机器人),可以使用流式响应。
调用 .stream() 方法代替 .call()。
.stream() 方法返回一个 Flux (如果使用了 Reactive 库) 或支持类似的流式处理机制。你可以订阅这个流来接收模型逐步生成的内容块。
示例代码 (概念性,具体实现依赖 Reactive 库如 Project Reactor):
import org.springframework.ai.chat.client.ChatClient; // 导入 ChatClient 类
import org.springframework.http.MediaType; // 导入 MediaType 类
import org.springframework.web.bind.annotation.GetMapping; // 导入 GetMapping 注解
import org.springframework.web.bind.annotation.RequestParam; // 导入 RequestParam 注解
import org.springframework.web.bind.annotation.RestController; // 导入 RestController 注解
import reactor.core.publisher.Flux; // 导入 Flux 类 (来自 Project Reactor)
import org.springframework.ai.chat.model.ChatResponse; // 导入 ChatResponse 类
public class StreamingChatController {private final ChatClient chatClient;public StreamingChatController(ChatClient.Builder builder) {this.chatClient = builder.build();}// produces = MediaType.TEXT_EVENT_STREAM_VALUE 指定响应类型为 Server-Sent Events (SSE)(value = "/stream-chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> streamChat(("input") String input) {// 使用 chatClient 的 Fluent APIreturn this.chatClient.prompt().user(input) // 设置用户消息.stream() // 1. 调用 stream() 方法,启动与 AI 模型的流式交互,返回 Flux<ChatResponse>.content(); // 2. 调用 content() 方法 (针对 Flux),将 ChatResponse 流映射为 String 内容流// 每次模型生成一部分内容,就会在这个 Flux 中发布一个 String 片段}// 如果需要更详细的流信息,可以直接处理 Flux<ChatResponse>(value = "/stream-chat-response", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ChatResponse> streamChatResponse(("input") String input) {return this.chatClient.prompt().user(input).stream() // 直接返回 ChatResponse 的流.chatResponse(); // 获取原始的 ChatResponse 流}
}
- 定制 ChatClient 默认值
可以在创建 ChatClient 时设置一些默认行为,这些默认值会应用于该 ChatClient 实例发出的所有请求,除非在单次请求中被覆盖。
设置默认系统消息 (System Message):
系统消息通常用于给 AI 模型设定角色、提供指令或上下文背景。
在 ChatClient.Builder 上调用 .defaultSystem(…) 方法。
ChatClient chatClient = ChatClient.builder(chatModel)// 设置默认的系统消息,告诉 AI 它是一个乐于助人的 AI 助手.defaultSystem("You are a helpful AI assistant.").build();// 后续使用这个 chatClient 发送请求时,会自动带上这个系统消息
chatClient.prompt().user("What is the capital of France?").call().content();
其他默认设置:
默认用户消息: .defaultUser(…)
默认模型选项: .defaultOptions(…),可以设置温度 (temperature)、最大 token 数 (maxTokens) 等模型参数。
默认函数: .defaultFunctions(…) (用于 Function Calling)
默认头信息: .defaultHeaders(…) (可能用于特定模型的 API 调用)
- Advisors (增强器/顾问)
Advisors 是一种强大的机制,用于向 ChatClient 的请求/响应流程中添加额外的功能,类似于中间件 (Middleware) 或 AOP (Aspect-Oriented Programming) 中的切面。
它们可以在请求发送前对其进行修改,或者在收到响应后对其进行处理。
通过 ChatClient.Builder 的 .defaultAdvisors(…) 方法添加。
常见的 Advisors 应用场景:
检索增强生成 (RAG): 在发送用户问题给 LLM 之前,先从知识库 (Vector Store) 中检索相关文档,并将文档内容添加到提示词中。QuestionAnswerAdvisor 是一个常见的 RAG Advisor。
聊天记忆 (Chat Memory): 在发送请求前,从 ChatMemory 组件中加载历史对话记录,并将其添加到提示词中;在收到响应后,将当前的问答对保存到 ChatMemory 中。ChatMemoryAdvisor 用于此目的。
日志记录: 记录请求和响应的详细信息。
示例 (概念性):
// 假设 vectorStore 和 chatMemory 是已经配置好的 Bean
VectorStore vectorStore = ...;
ChatMemory chatMemory = ...;ChatClient chatClient = ChatClient.builder(chatModel)// 添加一个 RAG Advisor,使用指定的 VectorStore 进行检索.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))// 添加一个聊天记忆 Advisor.defaultAdvisors(new ChatMemoryAdvisor(chatMemory)).build();// 现在使用这个 chatClient 时,会自动进行 RAG 检索和聊天记忆管理
chatClient.prompt().user("Tell me about Spring AI based on my previous questions.").call().content();
总结:
ChatClient 是 Spring AI Alibaba 中进行 AI 模型交互的核心组件之一。它通过 Fluent API 极大地简化了与 AI 模型的通信,隐藏了底层实现的复杂性,并提供了强大的功能,如结构化输出、流式响应和通过 Advisors 实现的 RAG、聊天记忆等高级特性。掌握 ChatClient 的使用对于在 Spring 应用中高效地集成 AI 功能至关重要。
资料推荐
💡大模型中转API推荐
✨中转使用教程