Spring AI 中 ChatClient常用方法_springai chatclient
1、ChatClient是什么?
ChatClient 是 Spring AI 中一个简洁高效的组件,它能让你仅用几行代码就轻松对接 Deepseek、Qwen等主流 AI 大模型。其核心定位是一个流畅的 API 客户端,专为解决复杂AI交互场景而生,尤其擅长应对诸如提示词模板拼接、聊天记忆管理、输出解析等常见痛点。
ChatClient 通过链式调用将用户输入、系统提示及模型参数(如温度、最大 Token 数)组装成 Prompt 对象,完成请求的构建与参数传递。随后,ChatModel 调用底层 AI 服务接口(如火山引擎的流式 API),获取分块返回的原始响应数据流。最终,ChatClient 将这些流式响应统一封装为 ChatResponse 对象,或映射为自定义实体类(如 POJO),实现结构化输出,从而完成从请求构建、模型推理到结果解析的完整闭环。
举个🌰:
当你想与 AI 进行对话时,通常需要经历以下步骤:
-
拼接提示词模板;
-
维护和管理历史对话记录;
-
解析返回的 JSON 数据;
-
支持流式响应处理
而有了 ChatClient,这些繁琐操作将被封装成一条简洁的链式调用,一气呵成!从内部机制来看,ChatClient 就像是一位经验丰富的导演,协调多个“演员”协同演出:
- 提示词模板引擎:自动拼接系统指令与用户输入;
- HTTP通信模块:负责向 OpenAI 等模型接口发起请求;
- 响应解析器:将返回的 JSON 转化为字符串、对象或流式数据;
- 组件集成中心:整合聊天记忆(ChatMemory)、函数调用(Function Calling)等高级功能。
ChatClient 的链式调用基于 Fluent API 设计模式,通过方法链简化与 AI 模型的交互流程。以下是其核心方法及作用详解:
2、背景知识:系统提示词(System Prompt)
(1)在与大语言模型(LLM)交互时,通常有三种类型的输入内容:
System Prompt(系统提示):
定义了模型的行为方式、角色设定或全局规则。
比如:“你是一个乐于助人的助手。” 或 “你是一名精通Java的软件工程师。”
在对话中一般只发送一次,用于初始化模型的角色认知。
User Prompt(用户提示):
用户发出的具体请求或问题。
Assistant Response(助手回复):
模型对用户请求的回答。
(2)defaultSystem(...)
的作用
此方法用于指定一个默认的 system prompt。这个 system prompt 将会在每次会话开始时自动应用,无需手动重复设置。如果你不调用这个方法,可能会使用空值或模型默认的 system prompt(通常是通用助手行为)。
ChatClient chatClient = ChatClient .builder(model) .defaultSystem(\"你是一个专业的法律顾问。\") .build();
在这个例子中,所有通过此 chatClient
发起的对话都会以“你是一个专业的法律顾问”作为系统指令开始。
(3) 使用场景
-
你想让模型始终扮演某个特定角色(客服、教师、医生等)。
-
需要统一模型输出风格或遵循某些规范。
-
多次对话中避免重复设置 system prompt。
3、ChatClient链式调用—基础配置方法
(1)prompt()
方法
prompt()
是ChatClient
中 链式调用的核心入口方法,用于启动 Fluent API 构建 AI 模型请求。作为方法链的起点,后续可串联.user()
、.system()
等方法设置用户输入、系统提示等内容。
prompt()
方法通过 Fluent API 设计简化了请求构建流程,并支持动态参数、多模态输入、异步处理等高级功能。开发者可通过链式调用灵活控制模型行为,适用于从简单问答到复杂多模态交互的多样化场景
prompt()
这个无参数方法让您开始使用流畅 API,允许您构建用户、系统和其他提示部分。
prompt(Prompt prompt)
这个方法接受 Prompt
参数,让您传入使用 Prompt 的非流畅 API 创建的 Prompt
实例。
prompt(String content)
这是一个类似于前一个重载的便捷方法。它接受用户的文本内容。
(2)defaultSystem(String prompt)
-
作用:设置默认系统提示语,用于引导模型行为(如角色定义、回复风格)。
-
示例:
ChatClient.builder().defaultSystem(\" 你是一个幽默的助手\").build();
-
特性:支持动态变量替换(如
{{变量名}}
)
(3)model(String modelName)
-
作用:指定调用的 AI 模型(如
\"gpt-4\"
、\"chatglm3-6b\"
)。
4、ChatClient链式调用—请求配置方法
(1)user(String message)
- 作用:添加用户输入消息,标识为
USER
角色。
示例:
client.prompt().user(\" 如何学习编程?\");
(2)system(String message)
- 作用:添加系统级提示,覆盖默认配置(如临时调整回复规则)。
示例:
client.prompt().system(\" 用简短的句子回答\");
(3)param(String key, Object value)
- 作用:动态注入参数至提示语变量,用于模板化提示。
- 示例:
client.prompt().user(\" 写一个{{style}}的笑话\").param(\"style\", \"冷笑话\");
5、ChatClient链式调用—执行与响应方法
(1)call()
作用:发起同步请求,返回 ChatResponse
对象(包含完整响应内容)。
示例:
ChatResponse response = client.prompt().user(\" 你好\").call();
(2)stream()
作用:发起流式请求,返回 Flux
对象(适用于实时逐块输出)。
示例:
Flux stream = client.prompt().user(\" 讲一个故事\").stream();
(3)entity(Class type)
作用:将模型输出解析为结构化对象(需响应内容符合目标类格式)。
示例:
MovieInfo info = client.prompt().user(\" 推荐一部科幻电影\").call().entity(MovieInfo.class);
(4) ChatResponse
在 Spring AI 框架中,
ChatResponse
是一个非常核心的类,用于封装从大语言模型(LLM)返回的聊天响应结果。它不仅仅是一个简单的文本回复容器,还包含了丰富的元数据信息
-
实际的模型输出内容
-
使用的模型名称
-
生成过程中的 token 统计(输入、输出、总消耗)
-
响应状态和错误信息(如果有)
①ChatResponse
的作用总结
Generation
列表形式存在MessageHistory
等对象实现复杂对话逻辑②ChatResponse
的典型结构(简化版)
public class ChatResponse { private String model; // 使用的模型名称,如 \"qwen-max\" private List generations; // 生成的内容列表 private Map metadata; // 元数据,如 token 使用情况、调用耗时等}
其中,Generation
是实际的生成内容,结构如下:
public class Generation { private String content; // 模型生成的内容 private String role; // 角色,如 \"assistant\"}
③使用 Spring AI 调用模型并处理 ChatResponse
假设你已经配置好了 ChatClient
(例如基于 OpenAI 或 Qwen),你可以这样调用并解析响应:
import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.model.ChatResponse;import org.springframework.ai.chat.prompt.Prompt;import org.springframework.stereotype.Service;@Servicepublic class ChatService { private final ChatClient chatClient; public ChatService(ChatClient chatClient) { this.chatClient = chatClient; } public void askQuestion(String userMessage) { Prompt prompt = new Prompt(userMessage); ChatResponse response = chatClient.call(prompt); // 输出模型名称 System.out.println(\"Model used: \" + response.getMetadata().get(\"model\")); // 输出生成内容 response.getGenerations().forEach(gen -> { System.out.println(\"Assistant: \" + gen.getContent()); }); // 输出 token 统计(如果支持) if (response.getMetadata().containsKey(\"usage\")) { System.out.println(\"Usage: \" + response.getMetadata().get(\"usage\")); } }}
④ChatResponse
的关键应用场景
response.getGenerations().get(0).getContent()
response.getMetadata().get(\"model\")
response.getMetadata().get(\"usage\")
content
和 role
添加到下一次请求中model
, prompt
, content
, usage
等用于审计或计费⑤Spring AI 支持的 LLM 类型
Spring AI 目前支持多种 LLM 后端,包括:
-
OpenAI / Azure OpenAI
-
Amazon Bedrock
-
Google Vertex AI
-
Alibaba Cloud Qwen
-
Ollama(本地模型)
-
HuggingFace Inference API
-
自定义模型(通过 SPI 接口)
下面通过调用 call() 方法后的 chatResponse() 方法展示了返回包含元数据的 ChatResponse 对象的示例:
ChatResponse chatResponse = chatClient.prompt() .user(\"给我讲个笑话\") .call() .chatResponse();
无论你使用哪种模型,它们都会返回统一格式的 ChatResponse
,极大提升了代码的可移植性和可维护性。
{ \"result\": { \"metadata\": { \"finishReason\": \"STOP\", \"contentFilterMetadata\": null }, \"output\": { \"messageType\": \"ASSISTANT\", \"media\": [], \"metadata\": { \"finishReason\": \"STOP\", \"role\": \"ASSISTANT\", \"id\": \"endpoint_common_28\", \"messageType\": \"ASSISTANT\" }, \"content\": \"我是Qwen,由阿里云开发的大型语言模型。我被设计用来协助人们进行各种任务,包括编写文档、创作故事、表达观点等。有什么我可以帮助你的吗?\" } }, \"metadata\": {}, \"results\": [ { \"metadata\": { \"finishReason\": \"STOP\", \"contentFilterMetadata\": null }, \"output\": { \"messageType\": \"ASSISTANT\", \"media\": [], \"metadata\": { \"finishReason\": \"STOP\", \"role\": \"ASSISTANT\", \"id\": \"endpoint_common_28\", \"messageType\": \"ASSISTANT\" }, \"content\": \"我是Qwen,由阿里云开发的大型语言模型。我被设计用来协助人们进行各种任务,包括编写文档、创作故事、表达观点等。有什么我可以帮助你的吗?\" } } ]}
⑥ 总结
generations
, model
, metadata
AI 模型的响应是一个由 ChatResponse 类型定义的丰富结构。 它包括有关如何生成响应的元数据,还可以包含多个响应,称为 Generations,每个都有自己的元数据。 元数据包括用于创建响应的令牌数量(每个令牌大约是一个单词的 3/4)。 这些信息很重要,因为托管 AI 模型根据每个请求使用的令牌数量收费。
6、ChatClient链式调用—控制模型生成行为
通过链式方法设置温度值(
.temperature()
)、最大 Token 数(.maxTokens()
)等,控制输出的随机性及长度。大模型中的Temperature参数主要用于调节生成文本的随机性和多样性,温度系数越大,模型输出越倾向于给出较高的概率值,表现为“热情”;温度系数越小,模型输出越倾向于给出较低的概率值,表现为“冷静”
(1)temperature(double value)
作用:设置模型生成温度值(控制随机性,范围 0.0-1.0
)。
示例:
client.prompt().user(\" 写诗\").temperature(0.7).call();
(2)maxTokens(int value)
作用:限制生成的最大 Token 数,防止过长响应。
示例:
client.prompt().user(\" 总结这篇文章\").maxTokens(500).call();
(3)onError(Consumer handler)
作用:自定义异常处理逻辑(如网络错误、参数校验失败)。
示例:
client.prompt().user(\" 提问\").onError(e -> log.error(\" 请求失败\", e)).call();
7、ChatClient链式调用—控制模型生成行为
(1)media(MediaData data)
作用:添加图像、音频等多媒体输入(需模型支持多模态)。
示例:
client.prompt().user(\" 描述这张图\").media(imageData).call();
(2)withMemory(ChatMemory memory)
作用:绑定对话记忆组件,自动附加历史上下文。
示例:
client.withMemory(redisChatMemory).prompt().user(\" 继续刚才的话题\").call();
8、ChatClient典型链式调用示例
ChatResponse response = ChatClient.builder() . model(\"gpt-4\") . defaultSystem(\"你是一名技术顾问\") . build() .prompt() .user(\"解释区块链原理\") .temperature(0.5) .maxTokens(300) .call();
关键设计优势
-
代码简洁性:通过链式调用替代多层嵌套代码
-
类型安全:编译时检查参数类型,减少运行时错误
-
可扩展性:支持自定义方法扩展(如添加领域特定参数)
9、在单次请求中临时覆盖模型名称
如果未显式设置模型名称,ChatClient会使用默认模型(通常取决于底层ChatModel
的配置)。您可以在运行时覆盖默认设置,例如:
ChatResponse response = chatClient.prompt() .options(OpenAiChatOptions.builder().withModel(\"gpt-3.5-turbo\").build()) .user(\"What\'s the weather today?\") .call();
10、使用ChatOptions
对象设置模型名称(如使用OpenAI的模型)
创建一个包含模型名称的ChatOptions
选项对象,并在创建ChatClient实例时传递给它。这是推荐的方法,因为它支持其他参数(如温度、随机性控制),并确保代码可读性高
import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.openai.OpenAiChatOptions; // 导入选项类 // 创建ChatClient实例并指定模型名称 ChatClient chatClient = ChatClient.builder() .chatModel(chatModel) // 注入ChatModel Bean(如OpenAI的GPT模型) .defaultOptions( // 设置默认选项,包括模型名称 OpenAiChatOptions.builder() .withModel(\"gpt-4-1106-preview\") // 指定模型名称 .withTemperature(0.7f) // 可选:其他参数 .build() ) .build(); // 使用ChatClient发送请求String response = chatClient.prompt() .user(\"Hello, how are you?\") .call() .content();
参考链接:
Spring AI ChatClient API 使用指南:从基础到实战(附完整代码示例)_spring ai client api-CSDN博客
增强器 API - 零基础入门Java AI
Spring AI中的ChatClient:从入门到精通,一篇搞定!
Spring AI 隐藏杀器:参数这样调,效果立竿见影