很多刚上手 Spring AI Alibaba 的同学,都会被一堆架构名词和组件层级搞懵:做 AI 应用到底选 Workflow 还是 Agent?ChatModel 和 ChatClient 都能调大模型,差别在哪?ReactAgent 是不是做智能应用必须要用?
本文从顶层架构模式 和核心组件层级两个维度梳理入门核心概念,附带三套对齐的可运行 Demo,帮你建立清晰认知,为后续多 Agent 协作、复杂编排打下基础。
一、三大顶层架构:Workflow、Agent、混合架构
我们可以按照业务流程的确定性程度,把大模型应用顶层架构分为三类。三者在可控性、灵活性上各有取舍,适配完全不同的业务场景。
1. Workflow:固定工作流
Workflow 属于确定性流程 ,节点执行顺序提前硬编码定义。大模型只负责在单个节点内部做内容生成,没有自主规划、自主选择工具的能力,流程走向不会根据大模型输出动态跳转。
✅ 典型场景:串行固定任务
例如:产品生成 PRD → 开发根据 PRD 生成代码 → 测试依据 PRD + 代码产出测试报告。
✅ 优点:流程稳定可控、可预测,调试简单
❌ 缺点:无法自适应需求变化,不能自主迭代,面对开放性问题能力弱
2. Agent:智能体
Agent 的核心能力是自主思考、工具调用、循环迭代 ,底层思想就是经典的 ReAct:Reason(思考)→ Act(行动) 循环。大模型可以自己判断要不要调用工具、调用哪个工具、什么时候停止。
在 Spring AI Alibaba 里最典型的实现就是 ReactAgent,内部自带思考-工具调用循环,支持多轮迭代,拥有自主决策能力。
✅ 优点:擅长开放、未知问题,灵活性极强
❌ 缺点:流程不可控,容易跑出预期之外的分支;生产环境必须额外增加约束、限流、校验机制
3. 混合架构:企业落地首选
混合架构 = Workflow 固定主流程 + Agent 局部自主能力,也是工业界 AI 项目落地最主流的方案:
- 主链路采用 Workflow 固定编排,保证整体业务链路可控,满足企业合规、管控要求;
- 局部复杂子节点交给 Agent 处理,借助 Agent 的推理和工具调用能力攻克不确定的复杂任务。
一句话通俗总结:
Workflow 是固定剧本 ,Agent 是会自主思考的演员;混合架构就是:主剧本不变,部分复杂桥段交给演员自由发挥。
二、Spring AI 核心组件:三层封装关系 ChatModel → ChatClient → ReactAgent
很多人混淆这几个 API,本质是它们是逐层封装的关系:底层提供原始能力,上层做封装简化,上层组件依赖底层能力。
重要前置说明:下面三套 Demo 使用同一个
searchWeb工具,方便横向对比差异。
- ChatModel:全部自己手动管理消息、循环、工具入参
- ChatClient:简化样板代码,支持注册工具,但不会自动 ReAct 循环
- ReactAgent:内置完整 ReAct 循环,自动处理工具调用、上下文回写
1. ChatModel:最底层原始通信客户端
ChatModel 是对接大模型的原始客户端,职责非常单一:组装消息、发起 LLM 请求、返回模型结果。
它本身没有任何 Agent 循环,不会自动做多轮思考,不会自动处理工具调用 。
如果想用它实现 ReAct 工具调用,需要开发者自己手写 while 循环:每一轮把上下文消息 + 工具定义传给模型,判断返回是否包含工具调用,本地执行工具后,再把工具结果塞回对话消息,继续下一轮请求。
⚠️ 重点提醒:工具 schema(toolList)每一轮请求都要传给模型;对话 messages 只保存 user/assistant/tool 消息,不会持久化保存工具定义。
手写 ChatModel 实现 ReAct 示例代码:
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.ToolMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.tool.ToolDefinition;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class RawChatModelReActDemo {
private final ChatModel chatModel;
public RawChatModelReActDemo(ChatModel chatModel) {
this.chatModel = chatModel;
}
public String run(String query) {
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage(query));
// 定义工具schema
List<ToolDefinition> toolList = List.of(
ToolDefinition.builder()
.name("searchWeb")
.description("联网搜索资料")
.inputSchema("""
{
"type":"object",
"properties":{"keyword":{"type":"string"}}
}
""")
.build()
);
while (true) {
// 每一轮都带上toolList工具定义
Prompt prompt = new Prompt(messages, toolList);
ChatResponse resp = chatModel.call(prompt);
AssistantMessage assistantMsg = resp.getResult().getOutput();
messages.add(assistantMsg);
// 判断是否存在工具调用
if (!assistantMsg.hasToolCalls()) {
return assistantMsg.getContent();
}
// 执行本地工具
assistantMsg.getToolCalls().forEach(call -> {
String toolResult = executeTool(call.getName(), call.getArguments());
messages.add(new ToolMessage(toolResult, call.getId()));
});
}
}
private String executeTool(String toolName, String args) {
if ("searchWeb".equals(toolName)) {
return "搜索结果:AI客服主流厂商:阿里云、字节、百度";
}
return "工具不存在";
}
}
2. ChatClient:轻量对话封装
ChatClient 是在 ChatModel 之上做的轻量封装,简化了 Prompt 组装、消息管理、工具注册的样板代码,调用方式更流畅。
高频踩坑重点:ChatClient 支持注册工具 ,但是没有内置 ReAct 循环 !
如果模型返回工具调用,ChatClient 只会把工具调用信息返回给业务代码,不会自动执行工具、不会自动把结果放回上下文继续下一轮请求。想要多轮迭代,依然需要自己写循环。
2.1 ChatClient 基础单次对话(无工具)
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Component;
@Component
public class ChatClientDemo {
private final ChatClient chatClient;
public ChatClientDemo(ChatClient.Builder builder) {
this.chatClient = builder
.defaultSystemPrompt("你是一个简洁的助手,回答尽量简短")
.build();
}
public String simpleChat(String input) {
return chatClient.prompt()
.user(input)
.call()
.content();
}
}
2.2 ChatClient 注册工具版本(无自动循环)
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ChatClientWithToolDemo {
private final ChatClient chatClient;
public ChatClientWithToolDemo(ChatClient.Builder builder) {
ToolCallback searchWebTool = FunctionToolCallback.builder("searchWeb", this::searchWeb)
.description("联网搜索资料,查询AI厂商信息")
.inputSchema("""
{
"type":"object",
"properties":{"keyword":{"type":"string"}}
}
""")
.build();
this.chatClient = builder
.defaultTools(List.of(searchWebTool))
.defaultSystemPrompt("你是信息查询助手,可以调用searchWeb")
.build();
}
private String searchWeb(String keyword) {
return "搜索结果:AI客服主流厂商:阿里云、字节、百度";
}
public ChatResponse chatWithTool(String userMsg) {
return chatClient.prompt()
.user(userMsg)
.call()
.chatResponse();
}
}
3. ReactAgent:高层智能体封装
ReactAgent 属于 Spring AI Alibaba Graph 提供的高层封装 ReAct 智能体,内部依赖 ChatModel/ChatClient,内置思考+工具调用循环 ,自带 maxIterations 最大迭代次数限制,防止无限循环。
开发者只需要编写系统提示词、注册自定义工具即可开箱使用,不用自己手写 while 循环,是搭建多 Agent 系统的基础单元。
依赖提示:ReactAgent 在
spring-ai-alibaba-graph包,不是原生 Spring AI 自带组件。
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ReactAgentDemo {
private final ReactAgent reactAgent;
public ReactAgentDemo(ChatModel chatModel) {
ToolCallback searchWebTool = FunctionToolCallback.builder("searchWeb", this::searchWeb)
.description("联网搜索资料,查询AI厂商信息")
.inputSchema("""
{
"type":"object",
"properties":{"keyword":{"type":"string"}}
}
""")
.build();
this.reactAgent = ReactAgent.builder()
.name("search_agent")
.model(chatModel)
.systemPrompt("你是信息查询助手,有需要就调用searchWeb工具,整理结果后回答用户")
.tools(List.of(searchWebTool))
.maxIterations(5) // 最大迭代次数,生产环境必须配置
.saver(new MemorySaver()) // 内存会话记忆,threadId隔离对话
.build();
}
private String searchWeb(String keyword) {
return "搜索结果:AI客服主流厂商:阿里云、字节、百度";
}
public String chat(String userQuery) {
RunnableConfig runnableConfig = RunnableConfig.builder()
.threadId("session_001")
.build();
// 内部自动执行ReAct循环:思考→调用工具→回填结果→继续思考/输出答案
return reactAgent.call(userQuery, runnableConfig).getContent();
}
}
三、统一测试 Controller(全部接口放一起)
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AiTestController {
private final RawChatModelReActDemo rawChatModelReActDemo;
private final ChatClientDemo chatClientDemo;
private final ChatClientWithToolDemo chatClientWithToolDemo;
private final ReactAgentDemo reactAgentDemo;
public AiTestController(RawChatModelReActDemo rawChatModelReActDemo,
ChatClientDemo chatClientDemo,
ChatClientWithToolDemo chatClientWithToolDemo,
ReactAgentDemo reactAgentDemo) {
this.rawChatModelReActDemo = rawChatModelReActDemo;
this.chatClientDemo = chatClientDemo;
this.chatClientWithToolDemo = chatClientWithToolDemo;
this.reactAgentDemo = reactAgentDemo;
}
@GetMapping("/raw/chatmodel")
public String rawChatModel(@RequestParam String query) {
return rawChatModelReActDemo.run(query);
}
@GetMapping("/chatclient/simple")
public String chatClientSimple(@RequestParam String query) {
return chatClientDemo.simpleChat(query);
}
@GetMapping("/chatclient/tool")
public ChatResponse chatClientTool(@RequestParam String query) {
return chatClientWithToolDemo.chatWithTool(query);
}
@GetMapping("/agent/react")
public String reactAgent(@RequestParam String query) {
return reactAgentDemo.chat(query);
}
}
四、组件层级 & 核心差异汇总
ChatModel(底层原始模型调用) ← ChatClient(轻量对话封装) ← ReactAgent(具备自主迭代的智能体)
| 组件 | 是否支持工具 | 是否内置ReAct循环 | 适用场景 |
|---|---|---|---|
| ChatModel | ✅ 需要手动传toolList | ❌ 需要自己写while循环 | 深度定制交互逻辑,精细控制每一轮请求 |
| ChatClient | ✅ 支持默认注册tools | ❌ 不会自动迭代 | 简单问答、一次性内容生成,想要工具循环需自己编码 |
| ReactAgent | ✅ 注册工具回调 | ✅ 内置循环、迭代次数控制 | 开放问题、自主工具探索,快速搭建智能体 |
越底层,自由度越高、样板代码越多;越上层,封装越完善、开发越简单。我们可以根据业务复杂度灵活选择对应层级组件。
五、总结与选型建议
- 流程固定、步骤明确、追求稳定可控:优先 Workflow;
- 问题开放、需要模型自主检索、推理、多轮工具探索:优先 Agent;
- 企业业务系统:优先混合架构,主流程 Workflow 兜底,复杂子任务交给 Agent;
- 简单问答、一次性生成文案:用 ChatClient;
- 需要深度定制 ReAct 循环逻辑、自己掌控每一轮交互:直接基于 ChatModel 开发;
- 快速搭建具备工具调用能力的智能体:直接使用 ReactAgent。