
Spring AI 核心架构拆解:ChatClient、ChatModel、Prompt、Advisor 到底是什么?
很多 Java 开发者学 Spring AI,都会卡在同一个地方:
代码能跑,但不知道为什么能跑。
chatClient.prompt().user(...).call().content() 这一行能拿到模型回复。可再往下看,ChatClient、ChatModel、Prompt、Advisor 这些类名全冒出来了。
每个词好像都认识。
但串不起来。
这篇不继续堆 Demo。我们把 Spring AI 的主调用链路拆开,看一次请求是怎么从 Controller 走到模型,再把结果返回来的。
一、先看完整链路
你在 Controller 里可能写过这样的代码:
java
String response = chatClient.prompt()
.user("什么是 Spring AI?")
.call()
.content();
表面看,就是发个问题,拿个回答。
实际背后大概是这条链:
text
Controller -> ChatClient -> Prompt -> Advisor Chain -> ChatModel -> ChatResponse
这里的代码里看不到 Advisor,因为它通常是在构建 ChatClient 时配置好的。真正调用 .call() 时,请求才会经过这些 Advisor。
先用一句话记住:
ChatClient是业务入口,Prompt描述这次请求,Advisor在调用前后做增强,ChatModel对接具体模型,最后返回ChatResponse。
接下来按这条链路拆。
二、ChatClient:业务入口
ChatClient 是业务代码里最常见的入口。
它的价值很简单:让你用链式 API 顺手地调用模型。
比如:
java
chatClient.prompt()
.system("你是一个技术文档助手")
.user("解释下 Spring Bean 生命周期")
.call()
.content();
这里的 .prompt()、.system()、.user()、.call(),都是 ChatClient 给你的调用方式。
刚开始写业务时,你暂时不用管 Prompt 怎么构造、Advisor 怎么执行、ChatModel 怎么调用。
你只要按顺序写:
.user():用户问题;.system():可选,系统提示;.call():发起调用;.content():拿文本结果。
一个最小接口大概这样:
java
@RestController
public class AiController {
private final ChatClient chatClient;
public AiController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
这就是 ChatClient 的定位:把复杂链路藏起来,让你先把业务接口写出来。
三、Prompt:这次请求长什么样
Prompt 不是"万能容器"。
更准确地说,它是一次模型调用的请求描述。
你可以先把它拆成两块。
1. Messages
一次调用不一定只有用户问题,还可能有系统提示和历史回复。
java
Prompt prompt = new Prompt(List.of(
new SystemMessage("你是一个 Java 专家"),
new UserMessage("什么是 Spring Bean?")
));
常见消息有这几类:
SystemMessage:告诉模型应该怎么回答;UserMessage:用户输入;AssistantMessage:模型历史回复,多轮对话会用到。
2. Options
也就是这次调用的参数,比如模型名、温度、最大输出长度。
java
ChatOptions options = ChatOptions.builder()
.model("deepseek-v4-flash")
.temperature(0.7)
.build();
Prompt prompt = new Prompt("解释下 JVM", options);
那历史对话、RAG 文档、工具相关信息在哪?
不一定一开始就在 Prompt 里。
实际运行时,Advisor 可能会在调用前补充这次请求。比如把历史消息补进去,或者把检索到的文档作为上下文交给模型。
所以你可以把 Prompt 理解成一个请求快照:
在某个时刻,它描述了这次要发给模型的内容。
但到达 ChatModel 之前,它可能已经被 Advisor Chain 改过了。
四、Advisor Chain:增强链
Advisor 是这条链路里最灵活的部分。
它有点像拦截器,但不是 Spring MVC 的 HandlerInterceptor。
它做的是模型调用前后的增强。
比如:
- 调用前:补历史、查知识库、记录请求;
- 调用后:记录响应、补 metadata、做轻量处理。
链路可以这样理解:
text
ChatClient
-> Advisor 1
-> Advisor 2
-> ChatModel
-> Advisor 2
-> Advisor 1
-> 返回结果
SimpleLoggerAdvisor
最容易理解的是日志。
java
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
调试 Spring AI 调用链路时,它很有用。
MessageChatMemoryAdvisor
如果你想让模型记住前面聊过什么,可以加记忆 Advisor。
java
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build()
)
.build();
它会在调用前,把需要的历史消息补进这次请求里。
真实项目里还要注意一件事:多用户场景要区分 conversationId,不然不同用户的上下文可能串在一起。
QuestionAnswerAdvisor
RAG 也可以通过 Advisor 接进来。
java
QuestionAnswerAdvisor advisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().topK(5).build())
.build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(advisor)
.build();
这类 Advisor 会先去向量库检索相关文档,再把上下文补进请求里,让模型带着资料回答。
注意,QuestionAnswerAdvisor 需要对应的 vector store / advisor 依赖。不是只引入一个聊天模型 starter 就一定有。
Advisor 不要乱塞
Advisor 很强,但不是所有逻辑都往里放。
适合放进去的:
- 日志和监控;
- 对话记忆;
- RAG 上下文增强;
- 请求改写;
- 轻量响应处理。
不太适合放进去的:
- 复杂业务逻辑;
- 重量级数据处理;
- 跟模型调用无关的副作用,比如发邮件、写业务库。
记住一句话:
Advisor 是增强这次模型调用,不是替代 Service 层。
顺序也要注意。
多个 Advisor 会按配置顺序处理请求,响应回来时再反向经过。日志放前面,看到的更接近原始请求;日志放后面,看到的更接近最终发给模型的请求。
没有绝对对错,关键是你要知道自己想看哪一层。
五、ChatModel:模型抽象层
很多人会把 ChatModel 理解成"大模型"。
其实不是。
ChatModel 是 Spring AI 对聊天模型的统一抽象。
它不是 OpenAI、DeepSeek、Ollama 这些模型本身,而是 Spring AI 和具体模型实现之间的一层接口。
Spring Boot 会根据你引入的 starter 和配置,创建对应的 ChatModel Bean。
比如从 OpenAI 换到 DeepSeek,业务代码通常不用动。
OpenAI 配置可能是:
yaml
spring:
ai:
openai:
api-key: sk-xxx
chat:
options:
model: your-openai-model
DeepSeek 配置可能是:
yaml
spring:
ai:
deepseek:
api-key: sk-xxx
chat:
options:
model: deepseek-v4-flash
业务代码还是这一段:
java
String response = chatClient.prompt()
.user("什么是 Spring AI?")
.call()
.content();
这就是抽象层的价值:业务代码尽量不绑死具体供应商。
平时写业务,优先用 ChatClient。
什么时候看 ChatModel?
- 想理解底层怎么对接模型;
- 要做自定义模型实现;
- 调试时想绕过
ChatClient和Advisor。
比如直接调底层模型:
java
Prompt prompt = new Prompt("测试请求");
ChatResponse response = chatModel.call(prompt);
这种场景不多。
大部分时候,你只要记住:
ChatClient是主要入口,ChatModel是底层抽象。
六、ChatResponse:返回结果
如果 .content() 是快捷拿文本,那么 ChatResponse 就是完整返回包。
它可能包含:
- 模型返回的文本;
- 模型信息;
- finish reason;
- token 使用量。
拿文本:
java
ChatResponse response = chatClient.prompt()
.user("什么是 Spring AI?")
.call()
.chatResponse();
String content = response.getResult()
.getOutput()
.getText();
只要文本时,直接这样就行:
java
String content = chatClient.prompt()
.user("什么是 Spring AI?")
.call()
.content();
看元信息:
java
ChatResponseMetadata metadata = response.getMetadata();
System.out.println("模型: " + metadata.getModel());
System.out.println("响应 ID: " + metadata.getId());
看 finish reason:
java
String finishReason = response.getResult()
.getMetadata()
.getFinishReason();
看 token:
java
Usage usage = response.getMetadata().getUsage();
if (usage != null) {
System.out.println("输入 token: " + usage.getPromptTokens());
System.out.println("输出 token: " + usage.getCompletionTokens());
System.out.println("总计: " + usage.getTotalTokens());
}
注意,不是所有模型、所有调用方式都会返回完整 usage。做日志和成本统计时,先判空。
大部分业务接口只用 .content() 就够了。
但如果你要做成本统计、监控埋点、调用分析,就要看 ChatResponse。
七、什么时候用谁?
简单整理一下:
| 场景 | 优先看什么 | 原因 |
|---|---|---|
| 写业务代码 | ChatClient |
链式 API 顺手,封装了底层细节 |
| 只要文本结果 | .call().content() |
最简单,业务代码最常用 |
| 需要对话记忆 | MessageChatMemoryAdvisor |
自动补历史消息 |
| 需要 RAG 增强 | QuestionAnswerAdvisor |
检索文档,补上下文 |
| 需要记录日志 | SimpleLoggerAdvisor |
调试请求和响应 |
| 需要 token 统计 | ChatResponse / metadata |
看模型是否返回 usage |
| 理解底层机制 | ChatModel |
看 Spring AI 怎么对接模型 |
| 自定义模型实现 | ChatModel 接口 |
对接 Spring AI 还不支持的模型 |
一句话:
写业务,优先用
ChatClient。需要增强,配置
Advisor。想理解底层,再看
ChatModel和ChatResponse。
写在最后
这篇把 Spring AI 的主链路拆了一遍:
text
Controller -> ChatClient -> Prompt -> Advisor Chain -> ChatModel -> ChatResponse
你只要先记住这几个角色:
ChatClient:发起调用;Prompt:描述请求;Advisor:前后增强;ChatModel:对接模型;ChatResponse:承接结果。
以后再看 .call().content(),就不会只看到一行代码了。
你会知道它背后经过了哪些层,每一层大概在干什么。
如果你已经跑通了 Spring AI 的 Hello World,建议回头再看一遍这篇,会更清楚。
因为对话记忆、RAG、日志增强这些能力,基本都会绕到它。
后续会继续更新 Spring AI、RAG、Memory、Tool Calling、MCP 等实战内容。完整系列也会同步整理在公众号「AI Agent 实战有术」。