Java 构建 AI 应用:Spring AI Alibaba Workflow 与 Agent 架构抉择

很多刚上手 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 ✅ 注册工具回调 ✅ 内置循环、迭代次数控制 开放问题、自主工具探索,快速搭建智能体

越底层,自由度越高、样板代码越多;越上层,封装越完善、开发越简单。我们可以根据业务复杂度灵活选择对应层级组件。

五、总结与选型建议

  1. 流程固定、步骤明确、追求稳定可控:优先 Workflow;
  2. 问题开放、需要模型自主检索、推理、多轮工具探索:优先 Agent;
  3. 企业业务系统:优先混合架构,主流程 Workflow 兜底,复杂子任务交给 Agent;
  4. 简单问答、一次性生成文案:用 ChatClient;
  5. 需要深度定制 ReAct 循环逻辑、自己掌控每一轮交互:直接基于 ChatModel 开发;
  6. 快速搭建具备工具调用能力的智能体:直接使用 ReactAgent。
相关推荐
一枕槐安4876 天前
多模态RAG实战:PDF图文混合文档检索问答本地跑通
langchain·pdf·milvus·ai应用开发·多模态rag
Java成神之路-7 天前
Jev 和 LLM 到底有什么区别?
ai应用开发
Java成神之路-11 天前
多 Agent 协作别过度设计:A2A(Agent2Agent)协议
ai应用开发
FRing0311 天前
什么是AI、模型和token、vibecoding介绍、ClaudeCode环境搭建
人工智能·ai应用开发·智能体开发
Java成神之路-18 天前
大模型API输出莫名截断?
ai应用开发
Java成神之路-20 天前
大模型输出工程契约设计:从Prompt软约束到Schema硬约束
prompt·ai应用开发
Jing_jing_X22 天前
大模型只会输出token,是怎么“调用工具“的?
ai·agent·个人开发·ai应用开发
孙启超2 个月前
【AI开发之Rust】第 5 课:引用与生命周期 —— 借用能活多久?
人工智能·后端·rust·llm·ai应用开发
Java成神之路-2 个月前
RAG 工程最优解:意图路由分流架构
人工智能·ai应用开发·springaialibaba