Spring AI 源码解读 - 第 2 篇:ChatClient 调用链路
从
prompt().user().call()到content()的完整执行路径
📖 开篇引言
上一篇文章我们分析了 ChatModel 接口,它定义了发送 Prompt 并返回 ChatResponse 的核心契约。
但日常开发中,我们更多使用的是 ChatClient:
// 这种方式
String answer = chatClient.prompt()
.user("你好")
.call()
.content();
// 而不是这种方式
Prompt prompt = new Prompt(new UserMessage("你好"));
ChatResponse response = chatModel.call(prompt);
String answer = response.getResult().getOutput().getContent();
ChatClient 相比 ChatModel 封装了更多能力:
- 链式 Builder API:更友好的编程体验
- Advisor 拦截器链:自动注入记忆、日志增强等
- Prompt 模板处理:支持 System Prompt 的灵活配置
- 流式/非流式统一:
call()和stream()两种调用方式
本篇将深入 ChatClient 的内部实现,理解这条优雅链式调用的背后机制。
一、ChatClient 体系结构
1.1 接口定义
// org.springframework.ai.chat.client.ChatClient
public interface ChatClient {
// 默认 PromptBuilder
PromptBuilder prompt();
// 通用的 prompt() 重载
PromptBuilder prompt(Prompt prompt);
// ========== 非流式调用 ==========
// 返回完整响应
ResponseEntity<ChatResponse> call(Prompt prompt);
// 返回单个文本(便捷方法)
ResponseEntity<String> call(String message);
// 返回自定义类型(通过 ChatResponseMapper 转换)
<T> ResponseEntity<T> call(Prompt prompt, Class<T> responseClass);
// ========== 流式调用 ==========
// 返回流式响应
Flux<ChatResponse> stream(Prompt prompt);
// 返回流式文本
Flux<String> stream(String message);
}
1.2 PromptBuilder 子接口
// Prompt 构建器接口
public interface PromptBuilder
extends Builder<PromptBuilder>,
RequestBuilder<PromptBuilder, Prompt> {
// 继承自 RequestBuilder:消息构建
PromptBuilder user(String userMessage);
PromptBuilder user(Object userMessage); // 支持复杂对象
PromptBuilder system(String systemMessage);
PromptBuilder system(SystemPromptTemplate systemPromptTemplate);
// 继承自 Builder:选项配置
PromptBuilder options(ChatOptions options);
PromptBuilder defaultOptions(ChatOptions options);
// 构建并触发调用
ResponseEntity<ChatResponse> call();
<T> ResponseEntity<T> call(Class<T> responseClass);
Flux<ChatResponse> stream();
Flux<String> stream();
}
继承关系:
PromptBuilder
│
├─── user(String) 添加用户消息
├─── system(String) 添加系统消息
├─── options(ChatOptions) 设置本次请求参数
├─── defaultOptions(ChatOptions) 设置默认参数
├─── call() 同步调用
└─── stream() 流式调用
1.3 ResponseEntity 与 ChatResponse
ChatClient 返回 ResponseEntity<ChatResponse> 而不是直接返回 ChatResponse:
// ResponseEntity 包装了 ChatResponse,额外提供 HTTP 状态码等信息
public class ResponseEntity<T> {
private final T body;
private final HttpStatusCode statusCode;
public static <T> ResponseEntity<T> of(T body) {
return new ResponseEntity<>(body, HttpStatusCode.OK);
}
public T body() { return body; }
public HttpStatusCode statusCode() { return statusCode; }
}
// 便捷方法:直接提取 body
public class ResponseEntity<T> {
public T getBody() {
return this.body;
}
}
为什么用 ResponseEntity?
与 Spring MVC 风格保持一致,方便在异常情况下返回不同的 HTTP 状态码(如 429 限流、500 服务错误等)。
二、ChatClient 默认实现:DefaultChatClient
2.1 类结构
// org.springframework.ai.chat.client.DefaultChatClient
public class DefaultChatClient implements ChatClient {
private final ChatModel chatModel; // 核心模型
private final ChatClientOptions defaultOptions; // 默认选项
private final List<ChatModelOptionsTransformer> optionTransformers; // 选项转换器
private final ChatModelChatMemoryManager chatMemoryManager; // 记忆管理器
private final Map<String, ChatModel> toolTimeReturnChatModelCache; // 工具模型缓存
private final Set<CallAroundAdvisor> aroundAdvisors; // 拦截器链
private final RequestResponseAdvisorManager advisorManager; // 拦截器管理器
}
DefaultChatClient 的核心职责:
- 管理
ChatModel实例 - 维护
Advisor拦截器链 - 管理
ChatMemory记忆 - 提供
PromptBuilder实现
2.2 Builder 模式:ChatClient.builder()
// DefaultChatClient 的 Builder
public class DefaultChatClientBuilder implements ChatClientBuilder {
private ChatModel chatModel; // 必填
private ChatClientOptions defaultOptions; // 可选
private List<CallAroundAdvisor> aroundAdvisors; // 拦截器
private ChatMemory chatMemory; // 记忆
private MessageWindowChatMemory defaultChatMemory; // 默认记忆
// 基础构建
public ChatClientBuilder chatModel(ChatModel chatModel) {
this.chatModel = chatModel;
return this;
}
// 添加 Advisor(拦截器)
public ChatClientBuilder defaultAdvisors(CallAroundAdvisor... advisors) {
this.aroundAdvisors = Arrays.asList(advisors);
return this;
}
// 添加记忆
public ChatClientBuilder chatMemory(ChatMemory chatMemory) {
this.chatMemory = chatMemory;
return this;
}
// 构建最终对象
public ChatClient build() {
// 1. 如果没有显式设置 ChatMemory,使用默认的 MessageWindowChatMemory
if (this.chatMemory == null) {
this.chatMemory = MessageWindowChatMemory.create();
}
// 2. 构建 ChatModelChatMemoryManager(管理记忆注入)
ChatModelChatMemoryManager chatMemoryManager =
new ChatModelChatMemoryManager(this.chatMemory);
// 3. 构建 Advisor 管理器
RequestResponseAdvisorManager advisorManager =
new RequestResponseAdvisorManager(this.aroundAdvisors);
// 4. 创建 DefaultChatClient 实例
return new DefaultChatClient(
this.chatModel,
this.defaultOptions,
this.optionTransformers,
chatMemoryManager,
this.toolTimeReturnChatModelCache,
advisorManager
);
}
}
典型的构建方式:
ChatClient chatClient = ChatClient.builder(chatModel)
// 设置默认系统提示词
.defaultSystem("你是一个专业的 Java 工程师")
// 添加记忆管理(自动注入历史消息)
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
// 添加工具拦截器
.defaultAdvisors(myToolAdvisor)
.build();
三、PromptBuilder 实现:prompt() 方法
3.1 prompt() 方法源码
// DefaultChatClient.prompt()
@Override
public PromptBuilder prompt() {
return new PromptUserMessageBuilder(this); // 每次创建新的 Builder
}
// 内部 Builder 实现
class PromptUserMessageBuilder implements PromptBuilder {
private final DefaultChatClient client; // 持有 client 引用
private final List<Message> messages; // 消息列表
private ChatOptions options; // 请求选项
private SystemPromptTemplate systemPromptTemplate; // 系统提示模板
PromptUserMessageBuilder(DefaultChatClient client) {
this.client = client;
this.messages = new ArrayList<>();
}
@Override
public PromptBuilder user(String userMessage) {
this.messages.add(new UserMessage(userMessage));
return this;
}
@Override
public PromptBuilder system(String systemMessage) {
this.systemPromptTemplate = new SystemPromptTemplate(systemMessage);
return this;
}
@Override
public PromptBuilder system(SystemPromptTemplate systemPromptTemplate) {
this.systemPromptTemplate = systemPromptTemplate;
return this;
}
@Override
public PromptBuilder options(ChatOptions options) {
this.options = options;
return this;
}
// ... 其他方法
}
3.2 链式调用示例
chatClient.prompt() // → PromptUserMessageBuilder
.system("你是一个助手") // 设置系统提示词
.user("你好") // 添加用户消息
.user("今天天气如何?") // 再次添加用户消息
.options(options) // 设置请求选项
.call() // 触发调用
.content(); // 提取文本
Builder 内部状态变化:
初始状态
↓ prompt()
messages: []
systemPrompt: null
options: null
↓ system("你是一个助手")
messages: []
systemPrompt: SystemPromptTemplate("你是一个助手")
options: null
↓ user("你好")
messages: [UserMessage("你好")]
systemPrompt: SystemPromptTemplate("你是一个助手")
options: null
↓ user("今天天气如何?")
messages: [UserMessage("你好"), UserMessage("今天天气如何?")]
systemPrompt: SystemPromptTemplate("你是一个助手")
options: null
↓ options(options)
messages: [UserMessage("你好"), UserMessage("今天天气如何?")]
systemPrompt: SystemPromptTemplate("你是一个助手")
options: ChatOptions{...}
四、call() 方法执行链路
4.1 call() 的完整流程
当调用 call() 时,背后经历了以下步骤:
// 用户代码
chatClient.prompt().user("你好").call().content()
// 步骤分解
PromptUserMessageBuilder builder = chatClient.prompt(); // 1. 获取 Builder
builder.user("你好"); // 2. 添加消息
ResponseEntity<ChatResponse> response = builder.call(); // 3. 执行调用
String content = response.getBody().getResult()...; // 4. 提取结果
4.2 PromptBuilder.call() 源码
// PromptUserMessageBuilder.call()
public ResponseEntity<ChatResponse> call() {
// 1. 构建完整的 Prompt(包含系统消息和用户消息)
Prompt prompt = buildPrompt();
// 2. 触发实际调用
return this.doCall(prompt);
}
// 内部方法
private ResponseEntity<ChatResponse> doCall(Prompt prompt) {
// 3. 获取 DefaultChatClient 实例
DefaultChatClient client = getClient();
// 4. 调用 client 的 doChatMethod
// 这里会触发 Advisor 链的执行
return client.doChatMethod(
Prompt.toUserMessages(prompt), // 只传用户消息
Prompt.toSystemMessage(prompt), // 单独传系统消息
prompt.getOptions() // 请求选项
);
}
4.3 DefaultChatClient.doChatMethod() 源码
这是真正触发 Advisor 链的方法:
// DefaultChatClient.doChatMethod()
ResponseEntity<ChatResponse> doChatMethod(
List<UserMessage> userMessages, // 用户消息列表
String systemPromptText, // 系统提示词文本
ChatOptions requestOptions // 请求级选项
) {
// 1. 构建 AdvisedRequest(携带完整上下文)
AdvisedRequest advisedRequest = AdvisedRequest.builder()
.userMessage(userMessages) // 用户消息
.systemText(systemPromptText) // 系统提示词
.options(mergeOptions(requestOptions)) // 合并后的选项
.chatMemoryContext(this.chatMemoryManager.getChatMemoryContext(
Thread.currentThread().threadId() // 获取当前线程的会话 ID
))
.build();
// 2. 通过 AdvisorManager 执行拦截器链
// before(): 前置处理(注入记忆等)
// doChat(): 实际调用 ChatModel
// after(): 后置处理(日志等)
AdvisedResponse<ChatResponse> advisedResponse =
this.advisorManager.execute(advisedRequest,
advisedRequest1 -> {
// 实际的 ChatModel 调用
return doChat(advisedRequest1);
});
// 3. 返回响应
return ResponseEntity.of(advisedResponse.getChatResponse());
}
4.4 doChat() 方法:实际调用 ChatModel
// 执行实际的 ChatModel 调用
ChatResponse doChat(AdvisedRequest request) {
// 1. 注入 ChatMemory 记忆到用户消息
// 这一步会把历史消息插入到当前消息之前
UserMessage userMessageWithMemory =
this.chatMemoryManager.appendHistoryContext(request);
// 2. 构建完整的 Prompt(系统消息 + 记忆消息 + 当前消息)
Prompt prompt = new Prompt(
userMessageWithMemory,
request.getOptions()
);
// 3. 调用底层的 ChatModel
return this.chatModel.call(prompt);
}
4.5 完整调用链路图
┌─────────────────────────────────────────────────────────────────┐
│ chatClient.prompt().user("你好").call().content() │
└─────────────────────────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────────┐
│ 1. PromptUserMessageBuilder 实例化 │
│ messages = [] │
└─────────────────────────────────────────────────────────────────┘
│
↓ .user("你好")
┌─────────────────────────────────────────────────────────────────┐
│ 2. 添加用户消息 │
│ messages = [UserMessage("你好")] │
└─────────────────────────────────────────────────────────────────┘
│
↓ .call()
┌─────────────────────────────────────────────────────────────────┐
│ 3. buildPrompt() - 构建完整 Prompt │
│ - systemPromptTemplate → SystemMessage │
│ - userMessages → UserMessage │
│ Prompt{messages: [SystemMessage, UserMessage]} │
└─────────────────────────────────────────────────────────────────┘
│
↓ doChatMethod()
┌─────────────────────────────────────────────────────────────────┐
│ 4. 构建 AdvisedRequest(携带上下文) │
│ - userMessage │
│ - systemText │
│ - options (合并后的) │
│ - chatMemoryContext │
└─────────────────────────────────────────────────────────────────┘
│
↓ advisorManager.execute()
┌─────────────────────────────────────────────────────────────────┐
│ 5. Advisor 链执行 │
│ before() → doChat() → after() │
│ ├── LoggerAdvisor.before() 记录请求日志 │
│ ├── MemoryAdvisor.before() 注入历史消息 ← 关键! │
│ ├── doChat() 调用 ChatModel │
│ │ ├── 注入记忆消息 │
│ │ └── chatModel.call(prompt) │
│ ├── MemoryAdvisor.after() 更新记忆 │
│ └── LoggerAdvisor.after() 记录响应日志 │
└─────────────────────────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────────┐
│ 6. 返回 ChatResponse │
│ ResponseEntity.of(chatResponse) │
└─────────────────────────────────────────────────────────────────┘
│
↓ .content()
┌─────────────────────────────────────────────────────────────────┐
│ 7. 提取文本内容 │
│ chatResponse.getResult().getOutput().getContent() │
└─────────────────────────────────────────────────────────────────┘
五、ChatMemory 记忆注入机制
5.1 为什么要注入记忆?
多轮对话时,AI 需要知道之前的上下文:
# 第 1 轮
用户:我想学 Java
AI:Java 是一门面向对象的编程语言...
# 第 2 轮(AI 需要知道用户在讨论 Java)
用户:它和 Python 有什么区别?
AI:Java 和 Python 的主要区别是...
MessageChatMemoryAdvisor 负责在两次调用之间保存和注入记忆。
5.2 MessageChatMemoryAdvisor 源码
// org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor
public class MessageChatMemoryAdvisor
implements CallAroundAdvisor,
StreamAroundAdvisor {
private final ChatMemory chatMemory; // 记忆存储
// 1. before() - 在调用前注入记忆
@Override
public AdvisedRequest before(AdvisedRequest advisedRequest) {
// 获取会话 ID(如果没有则生成新 ID)
String sessionId = getOrCreateSessionId(advisedRequest);
// 从 ChatMemory 中获取该会话的历史消息
List<Message> historyMessages = this.chatMemory.get(
new ConversationId(sessionId)
);
// 将历史消息注入到请求中
// 会插入到 SystemMessage 之后、当前 UserMessage 之前
advisedRequest = AdvisedRequest.from(advisedRequest)
.userMessage(
insertHistoryMessages(
advisedRequest.getUserMessage(), // 当前消息
historyMessages // 历史消息
)
)
.build();
return advisedRequest;
}
// 2. after() - 在调用后保存消息到记忆
@Override
public ChatResponse after(AdvisedRequest advisedRequest,
AdvisedResponse<ChatResponse> advisedResponse) {
String sessionId = getOrCreateSessionId(advisedRequest);
// 保存用户消息和 AI 回复到记忆
this.chatMemory.add(
new ConversationId(sessionId),
advisedRequest.getUserMessage() // 用户消息
);
this.chatMemory.add(
new ConversationId(sessionId),
advisedResponse.getChatResponse() // AI 回复
);
return advisedResponse;
}
}
5.3 记忆注入时机
调用前 (before)
┌──────────────────────────────────────────────────────────┐
│ ChatMemory.get(sessionId) │
│ ↓ 获取历史消息 │
│ [UserMessage("我想学 Java"), AssistantMessage("Java 是...")] │
│ ↓ 插入到当前请求 │
│ Prompt.messages = [ ││ SystemMessage("你是一个助手"), ││ UserMessage("我想学 Java"), ← 历史消息 ││ AssistantMessage("Java 是..."), ← 历史消息 ││ UserMessage("它和 Python 的区别?") ← 当前消息 ││ ] │
└──────────────────────────────────────────────────────────┘
调用后 (after)
┌──────────────────────────────────────────────────────────┐
│ ChatMemory.add(sessionId, [UserMessage, AssistantMessage])│
│ ↓ 保存到记忆 │
│ 下次调用时,ChatMemory.get() 会返回这些消息 │
└──────────────────────────────────────────────────────────┘
六、stream() 流式调用链路
6.1 stream() 方法签名
// ChatClient.stream()
Flux<String> stream(String userMessage);
// PromptBuilder.stream()
Flux<ChatResponse> stream();
Flux<String> stream();
6.2 流式调用的实现
// DefaultChatClient.PromptUserMessageBuilder.stream()
public Flux<ChatResponse> stream() {
// 1. 构建 Prompt
Prompt prompt = buildPrompt();
// 2. 获取 Client
DefaultChatClient client = getClient();
// 3. 调用流式方法
return client.streamChat(prompt);
}
// DefaultChatClient.streamChat()
Flux<ChatResponse> streamChat(Prompt prompt) {
// 构建 AdvisedRequest
AdvisedRequest advisedRequest = buildAdvisedRequest(prompt);
// 通过 AdvisorManager 执行流式拦截器链
return this.advisorManager.streamExecute(
advisedRequest,
advisedRequest1 -> {
// 流式调用 ChatModel
return doStreamChat(advisedRequest1);
}
);
}
// 流式调用 ChatModel
Flux<ChatResponse> doStreamChat(AdvisedRequest request) {
// 1. 注入记忆
UserMessage userMessageWithMemory =
this.chatMemoryManager.appendHistoryContext(request);
// 2. 构建 Prompt
Prompt prompt = new Prompt(userMessageWithMemory, request.getOptions());
// 3. 调用流式 ChatModel(返回 Flux)
return this.chatModel.stream(prompt);
}
6.3 call() vs stream() 对比
| 维度 | call() | stream() |
|---|---|---|
| 返回类型 | ResponseEntity<ChatResponse> | Flux<ChatResponse> |
| 响应时机 | 完整响应后返回 | 流式返回(边生成边返回) |
| 使用场景 | 简单对话、工具调用 | 长文本生成、实时展示 |
| 性能 | 需要等待完整生成 | 首字符更快 |
| 内存 | 一次性加载完整响应 | 流式处理,内存占用小 |
6.4 流式响应的使用示例
// 非流式:等待完整响应
String answer = chatClient.prompt()
.user("写一篇 5000 字的文章")
.call()
.content();
// 流式:边生成边打印
chatClient.prompt()
.user("写一篇 5000 字的文章")
.stream()
.subscribe(
chunk -> System.out.print(chunk), // 每个 token 到达时打印
error -> error.printStackTrace(),
() -> System.out.println("\n[完成]")
);
七、ChatModelChatMemoryManager 记忆上下文管理
7.1 为什么需要上下文管理器?
每个用户会话需要独立的记忆空间:
// 用户 A 的会话
session-A: [A的历史消息...]
// 用户 B 的会话
session-B: [B的历史消息...]
7.2 上下文管理机制
// DefaultChatClient 中的 ChatModelChatMemoryManager
class ChatModelChatMemoryManager {
private final ChatMemory chatMemory; // 统一存储
private final Map<String, String> conversationIdIndex; // 线程→会话ID 映射
// 获取当前线程对应的会话 ID
String getOrCreateSessionId(AdvisedRequest request) {
long threadId = Thread.currentThread().getId();
return conversationIdIndex.computeIfAbsent(
String.valueOf(threadId),
k -> UUID.randomUUID().toString() // 新线程 = 新会话
);
}
// 获取指定会话的历史消息
List<Message> getHistoryMessages(String sessionId) {
return this.chatMemory.get(new ConversationId(sessionId));
}
// 添加消息到指定会话
void addMessage(String sessionId, Message message) {
this.chatMemory.add(new ConversationId(sessionId), message);
}
}
多会话管理:
ChatMemory (统一存储)
│
├── session-A: [msg1, msg2, msg3, ...] ← 用户 A
├── session-B: [msg1, msg2, ...] ← 用户 B
└── session-C: [msg1, ...] ← 用户 C
ConversationIdIndex (线程→会话映射)
│
├── thread-1 → session-A
├── thread-2 → session-B
└── thread-3 → session-C
八、Options 合并策略
8.1 三级 Options 优先级
优先级 1:请求级 Options(PromptBuilder.options() 设置)
↓ 覆盖
优先级 2:Client 默认级 Options(builder.defaultOptions() 设置)
↓ 覆盖
优先级 3:模型级 Options(application.properties 配置)
8.2 合并源码
// DefaultChatClient.mergeOptions()
ChatOptions mergeOptions(ChatOptions requestOptions) {
// 1. 从 Client 构建时传入的默认选项
ChatOptions defaultOptions = this.defaultOptions;
// 2. 如果请求指定了选项,合并到默认选项
if (requestOptions != null) {
return ChatModelOptionsUtils.merge(
requestOptions, // 请求级(高优先级)
defaultOptions // 默认级(低优先级)
);
}
// 3. 如果没有请求选项,返回默认选项
return defaultOptions;
}
合并示例:
// application.properties
spring.ai.ollama.chat.options.temperature=0.8
// 代码中
chatClient.builder(chatModel)
.defaultOptions(OllamaOptions.builder()
.temperature(0.5) // Client 默认:0.5
.maxTokens(1000) // Client 默认:1000
.build())
.build();
// 请求时
.prompt()
.options(OllamaOptions.builder()
.temperature(0.3) // 请求指定:0.3
// maxTokens 未指定,沿用 Client 默认:1000
.build())
.call();
// 最终合并结果
// temperature = 0.3(请求覆盖了默认)
// maxTokens = 1000(沿用默认)
九、小结
9.1 本篇要点
| 主题 | 核心要点 |
|---|---|
| ChatClient vs ChatModel | ChatClient 是更高层的封装,提供 Builder API 和 Advisor 链支持 |
| Builder 模式 | prompt().user().system().call() 链式调用的实现原理 |
| Advisor 拦截链 | before() → doChat() → after() 的执行顺序 |
| 记忆注入 | MessageChatMemoryAdvisor 在调用前注入历史消息、调用后保存新消息 |
| call() vs stream() | 完整响应 vs 流式响应,返回类型和执行流程的差异 |
| Options 合并 | 三级优先级:请求 > Client 默认 > 配置文件 |
9.2 关键类清单
| 类 / 接口 | 职责 |
|---|---|
ChatClient | 顶层接口,定义 prompt()、call()、stream() |
DefaultChatClient | 默认实现,管理 Advisor 链和记忆 |
PromptBuilder | Prompt 构建器,提供链式 API |
PromptUserMessageBuilder | PromptBuilder 实现,持有消息列表 |
AdvisedRequest | 携带完整上下文的请求对象 |
AdvisedResponse | Advisor 链处理后的响应对象 |
RequestResponseAdvisorManager | Advisor 链的执行管理器 |
MessageChatMemoryAdvisor | 记忆注入拦截器 |
ChatModelChatMemoryManager | 会话 ID 到记忆的映射管理 |
9.3 完整调用链路总结
用户代码
chatClient.prompt().user("你好").call().content()
│
↓
┌───────────────┐
│ ChatClient │ 提供 prompt() 方法
│ .prompt() │
└───────┬───────┘
↓
┌───────────────┐
│ PromptBuilder │ 构建 Prompt
│ .user("...") │ 添加用户消息
│ .call() │ 触发调用
└───────┬───────┘
↓
┌───────────────┐
│ AdvisorManager│ 执行拦截器链
│ .execute() │
└───────┬───────┘
│
├──→ LoggerAdvisor.before() 记录请求
│
├──→ MemoryAdvisor.before() 注入历史消息
│
├──→ doChat() 调用 ChatModel
│ │
│ ├──→ 注入记忆消息
│ ├──→ chatModel.call(prompt)
│ └──→ 返回 ChatResponse
│
├──→ MemoryAdvisor.after() 保存新消息到记忆
│
└──→ LoggerAdvisor.after() 记录响应
│
↓
┌───────────────┐
│ ChatResponse │ 返回完整响应
│ .content() │ 提取文本
└───────────────┘
9.4 下一篇预告
第 3 篇:Prompt 与 Message 体系
PromptTemplate模板引擎的实现- 变量替换机制
${name}→ 实际值 SystemPromptTemplate的高级用法- 不同模型的消息格式映射(Role Mapping)
系列目录:
- 第 1 篇:整体架构与核心抽象
- 第 2 篇:ChatClient 调用链路(本篇)
需要Spring AI系列学习代码的同学 欢迎关注公众号「AI日撰」,点击菜单「获取源码」获取完整代码(Gitee 仓库)。