单 Agent 的天花板
你写了一个 Agent,注册了 7-8 个工具:查订单、查用户、查产品、生成 Excel、发邮件、生成报告、发送通知……
Prompt 写了几百字描述每个工具的用途。LLM 跑起来。
第一次跑:基本能用。
第三次跑:LLM 选了”知识库搜索”而不是”SQL 查询”,因为”查数据”两个工具都沾边。
第十次跑:你开始写”必须先用 SQL 工具,否则不通过”的硬约束,Prompt 越来越长。
第三十次跑:Prompt 已经 1000+ token 了,LLM 还是偶尔选错。
这就是单 Agent 的天花板:工具一多,准确性断崖式下降。
多 Agent 是解法。Spring AI Alibaba 的 Graph 框架提供了 4 种核心模式:顺序、并行、路由、监督。这篇文章讲清楚每种怎么用、什么时候用。
准备:公共 ChatModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ChatModelFactory { public static ChatModel getChatModel() { DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); return DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .defaultOptions(DashScopeChatOptions.builder() .model("qwen-plus") .temperature(0.5) .maxToken(1000) .build()) .build(); } }
|
模式 1:顺序执行(SequentialAgent)
适用场景:流水线式任务,每一步依赖前一步的结果。
典型用例:
- 先写文章 → 再翻译
- 先查数据 → 再生成图表 → 再发邮件
- 先识别意图 → 再调用具体工具 → 再格式化输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class SequentialAgentTest { public static void main(String[] args) throws GraphRunnerException { ChatModel chatModel = ChatModelFactory.getChatModel(); ReactAgent writerAgent = ReactAgent.builder() .name("writer_agent") .model(chatModel) .description("专业写作 Agent") .instruction("你是一个作家。请根据用户提问写一段话:{input}") .outputKey("article") .build(); ReactAgent translateAgent = ReactAgent.builder() .name("translate_agent") .model(chatModel) .description("专业翻译 Agent") .instruction(""" 你是翻译官。请翻译以下文章: {article} 只返回翻译结果。 """) .outputKey("reviewed_article") .build(); SequentialAgent blogAgent = SequentialAgent.builder() .name("blog_agent") .description("写文章并翻译") .subAgents(List.of(writerAgent, translateAgent)) .build(); Optional<OverAllState> result = blogAgent.invoke("写一个 100 字的散文"); result.ifPresent(state -> { state.value("article").ifPresent(a -> System.out.println("原文: " + ((AssistantMessage) a).getText()) ); state.value("reviewed_article").ifPresent(t -> System.out.println("译文: " + ((AssistantMessage) t).getText()) ); }); } }
|
关键设计:
outputKey("article") 把 Agent 1 的输出存到 state
- Agent 2 的 instruction 用
{article} 占位符引用
- 系统自动做字符串替换
模式 2:并行执行(ParallelAgent)
适用场景:多个独立任务可以同时跑,结果合并。
典型用例:
- 同时让 3 个 Agent 写不同风格的散文,取最好的
- 同时让”优点分析 Agent”和”缺点分析 Agent”评估同一篇产品
- 同时从多个数据源采集数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class ParallelAgentTest { public static void main(String[] args) throws GraphRunnerException { ChatModel chatModel = ChatModelFactory.getChatModel(); ReactAgent proseAgent = ReactAgent.builder() .name("prose_writer") .model(chatModel) .description("散文作家") .instruction("写一段散文:{input}") .outputKey("prose_result") .build(); ReactAgent poetryAgent = ReactAgent.builder() .name("poetry_writer") .model(chatModel) .description("诗歌作家") .instruction("写一首诗:{input}") .outputKey("poetry_result") .build(); ReactAgent novelAgent = ReactAgent.builder() .name("novel_writer") .model(chatModel) .description("小说作家") .instruction("写一段小说:{input}") .outputKey("novel_result") .build(); ParallelAgent parallelAgent = ParallelAgent.builder() .name("multi_style_writer") .description("并行让 3 个作家同时写") .subAgents(List.of(proseAgent, poetryAgent, novelAgent)) .build(); Optional<OverAllState> result = parallelAgent.invoke("秋天"); result.ifPresent(state -> { state.value("prose_result").ifPresent(System.out::println); state.value("poetry_result").ifPresent(System.out::println); state.value("novel_result").ifPresent(System.out::println); }); } }
|
关键设计:
- 三个 Agent 同时启动,节省总时间(如果单 Agent 3 秒,并行后还是 3 秒)
- 每个 Agent 写自己的 outputKey,结果不冲突
- 你需要后续的”汇总 Agent”决定用哪个结果
模式 3:路由(RoutingAgent)
适用场景:根据输入动态选择执行路径。
典型用例:
- 用户问”查订单”→ 路由到 OrderAgent
- 用户问”推荐产品”→ 路由到 RecommendAgent
- 用户问”投诉”→ 路由到 CustomerServiceAgent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class RoutingAgentTest { public static void main(String[] args) throws GraphRunnerException { ChatModel chatModel = ChatModelFactory.getChatModel(); ReactAgent orderAgent = ReactAgent.builder() .name("order_agent") .model(chatModel) .description("处理订单相关问题:查订单、修改订单、取消订单") .instruction("你是订单助手。用户说:{input}") .build(); ReactAgent productAgent = ReactAgent.builder() .name("product_agent") .model(chatModel) .description("处理产品问题:推荐、参数、对比") .instruction("你是产品助手。用户说:{input}") .build(); ReactAgent serviceAgent = ReactAgent.builder() .name("service_agent") .model(chatModel) .description("处理售后问题:投诉、退换货、客服") .instruction("你是售后助手。用户说:{input}") .build(); RoutingAgent routingAgent = RoutingAgent.builder() .name("customer_service_router") .description("根据用户意图路由到对应专家") .subAgents(List.of(orderAgent, productAgent, serviceAgent)) .build(); routingAgent.invoke("我想查一下我的订单 #12345 的状态"); } }
|
关键设计:
- 路由 Agent 内部有个”调度 LLM”,它根据用户输入和每个子 Agent 的 description 决定走哪条路
- 子 Agent 的
description 必须清晰区分,否则路由错误
- 适合”意图分类”清晰的场景(3-10 个明确分支)
坑:
- 如果子 Agent 描述重叠(比如”订单”和”产品”经常一起出现),路由会乱
- 解决:description 写”互斥”的描述,”订单 = 已有订单的查改退”,”产品 = 浏览、推荐、对比”
模式 4:监督者(SupervisorAgent)
适用场景:复杂任务,需要”总指挥”动态协调多个子 Agent。
典型用例:
- 用户一句话里有多步操作:”帮我查上个月销售最高的产品,导出成 Excel,发给老板”
- 任务流程不确定,需要根据上一步结果决定下一步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class SupervisorAgentTest { public static void main(String[] args) throws GraphRunnerException { ChatModel chatModel = ChatModelFactory.getChatModel(); ReactAgent knowledgeAgent = ReactAgent.builder() .name("knowledge_agent") .model(chatModel) .description("知识库查询。处理关于文档、政策、流程的查询") .instruction("基于知识库回答:{input}") .build(); ReactAgent dataQueryAgent = ReactAgent.builder() .name("data_query_agent") .model(chatModel) .description("数据库查询。处理关于销售、用户、订单数据的查询") .instruction("执行 SQL 查询:{input}") .build(); ReactAgent exportAgent = ReactAgent.builder() .name("export_agent") .model(chatModel) .description("数据导出。处理 Excel、PDF、CSV 导出请求") .instruction("导出数据:{input}") .build(); ReactAgent analysisAgent = ReactAgent.builder() .name("analysis_agent") .model(chatModel) .description("数据分析。处理趋势分析、对比、洞察请求") .instruction("分析数据:{input}") .build(); SupervisorAgent supervisor = SupervisorAgent.builder() .name("business_assistant") .description("总指挥。协调 knowledge、data_query、export、analysis 4 个子 Agent") .subAgents(List.of(knowledgeAgent, dataQueryAgent, exportAgent, analysisAgent)) .maxIterations(10) .build(); Optional<OverAllState> result = supervisor.invoke(""" 帮我查上个月销售额最高的 5 个产品, 然后导出成 Excel, 最后发邮件给 boss@company.com """); } }
|
关键设计:
- Supervisor 内部有个”调度 LLM”循环,根据上一步结果决定下一步调用谁
maxIterations(10) 防止陷入死循环
- 适合”任务流程不确定”的复杂场景
Supervisor vs Routing 的区别:
- Routing:入口一次性路由,选定一个 Agent 后任务结束
- Supervisor:持续协调,可以根据中间结果决定后续步骤
实战选型决策
| 场景特征 |
用哪种 |
| 流程固定、每步依赖上一步 |
Sequential |
| 多步独立、可同时跑 |
Parallel |
| 入口分流、单一意图 |
Routing |
| 任务复杂、流程动态 |
Supervisor |
| 流程固定 + 中间有并行 |
Sequential + Parallel 嵌套 |
| 入口分流 + 后续协调 |
Routing → Supervisor 嵌套 |
一个完整的业务系统设计
场景:智能客服系统
架构:
1 2 3 4 5 6 7 8 9 10 11 12 13
| Supervisor(业务总指挥) │ ├─ Routing Agent(意图路由) │ │ │ ├─ 售前 Agent(产品咨询) │ ├─ 售中 Agent(订单相关) │ └─ 售后 Agent(投诉、退换货) │ └─ Parallel Agent(多源信息收集) │ ├─ 知识库查询 Agent ├─ 用户历史订单 Agent └─ 产品库存 Agent
|
执行流程:
- 用户:”我想退掉上周买的手机”
- Supervisor 决定走”售后 Agent”(Routing)
- 售后 Agent 启动后,并行调用 3 个数据源(Parallel)
- 拿到结果后生成回复
- Supervisor 决定是否需要后续(如”是否生成退货工单”)
这套架构在 Spring AI Alibaba Graph 里都能实现。
意味着什么?
多 Agent 不是”花式玩法”,是解决单 Agent 工具过多导致决策不准的标准答案。
- 工具 < 5 个:单 Agent 就够
- 工具 5-20 个:考虑 Routing(按意图分组)
- 工具 20+ 个:必须多 Agent(按领域拆分)
- 任务流程固定:Sequential
- 任务流程动态:Supervisor
Java 后端做 AI Agent 的最大优势:可以直接用 Spring 生态的成熟模式。Spring AI Alibaba 的 4 大模式就是从 Java 企业开发经验里抽象出来的——Sequential 对应 pipeline,Parallel 对应 fan-out,Routing 对应 dispatcher,Supervisor 对应 orchestrator。
数据密集型 AI 后端的工程师,**多 Agent 编排能力是 2026 年必须掌握的”基本架构”**。比 LangChain、LangGraph 在 Python 生态里更工程化。
关联阅读