最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Spring AI Alibaba 1.1.2 实战详解:5大多Agent编排模式权威指南
时间:2026-05-29 17:50:02 编辑:袖梨 来源:一聚教程网
多Agent编排技术让AI协作更高效,Spring AI Alibaba 1.1.2版本提供了5种实用模式,本文将详细解析每种模式的实现方法与应用场景。
Spring AI Alibaba 1.1.2 实战:5种多Agent编排模式完全指南
先说结论
单一大型模型处理复杂任务往往效率低下,合理的方式是将任务分解,让专业AI分工协作。

任务分解的核心思路包括:
- 查询类任务由专门Agent处理
- 执行类任务交给特定Agent
- 汇总任务由协调Agent完成
这种分工协作就是多Agent编排的精髓。Spring AI Alibaba 1.1.2.2版本提供了5种编排模式:Supervisor / Routing / Handoffs / Skills / Workflow,本文将通过官方示例源码逐一讲解。
一、Supervisor模式:一个大总管调度多个小弟
1.1 适用场景
当用户提出包含多个子任务的复合请求时,例如"帮我安排明天9点站会,再发邮件通知团队",需要:
- 调用日历Agent安排会议
- 调用邮件Agent发送通知
- 汇总结果返回给用户
Supervisor模式就是这样的任务协调中心。
1.2 核心API速览
实现思路:先为子Agent配置name/description/systemPrompt/inputType等参数,再用AgentTool.getFunctionToolCallback(agent)方法封装。
关键API示例(来自官方源码SupervisorConfig.java):
// 第一步:构建子Agent - 需配置四个关键要素
ReactAgent orderAgent = ReactAgent.builder()
.name("query_order") // 工具标识名
.description("查询订单状态。当用户询问订单、物流时调用。") // 功能描述
.systemPrompt("你是订单查询助手。根据用户提供的订单号查询订单状态。") // 系统提示
.model(chatModel)
.methodTools(orderQueryTools) // 关联工具集
.inputType(String.class) // 输入类型
.build();// 第二步:封装为工具 - 仅接收ReactAgent参数
AgentTool.getFunctionToolCallback(orderAgent)// 第三步:构建Supervisor - 注册子Agent工具
ReactAgent supervisorAgent = ReactAgent.builder()
.name("personal_assistant")
.systemPrompt("你是一个智能个人助手。你可以查询订单状态和发送通知。"
+ "将用户请求分解为合适的工具调用,协调结果。")
.model(chatModel)
.saver(memorySaver) // 记忆存储
.tools(
AgentTool.getFunctionToolCallback(orderAgent), // 子工具注册
AgentTool.getFunctionToolCallback(notifyAgent))
.build();
1.3 完整代码
POM依赖
<properties>
<spring-ai.version>1.1.2spring-ai.version>
<spring-ai-alibaba.version>1.1.2.2spring-ai-alibaba.version>
<spring-ai-alibaba-extensions.version>1.1.2.2spring-ai-alibaba-extensions.version>
properties><dependencies>
<dependency>
<groupId>com.alibaba.cloud.aigroupId>
<artifactId>spring-ai-alibaba-starter-dashscopeartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloud.aigroupId>
<artifactId>spring-ai-alibaba-agent-frameworkartifactId>
dependency>
dependencies>
配置类
@Configuration
public class SupervisorConfig { @Bean
public MemorySaver memorySaver() { return new MemorySaver(); } @Bean
public ReactAgent orderAgent(ChatModel chatModel, OrderQueryTools orderQueryTools) {
return ReactAgent.builder()
.name("query_order")
.description("查询订单状态。当用户想查询订单、物流、发货情况时调用此工具。")
.systemPrompt("你是订单查询助手。根据用户提供的订单号查询订单状态。")
.model(chatModel)
.methodTools(orderQueryTools)
.inputType(String.class)
.build();
} @Bean
public ReactAgent notifyAgent(ChatModel chatModel, NotifyTools notifyTools) {
return ReactAgent.builder()
.name("send_notification")
.description("发送通知消息。当用户想发送通知、提醒时调用此工具。")
.systemPrompt("你是通知发送助手。根据用户的要求发送通知消息。")
.model(chatModel)
.methodTools(notifyTools)
.inputType(String.class)
.build();
} @Bean("supervisorAgent")
public ReactAgent supervisorAgent(
ChatModel chatModel,
ReactAgent orderAgent,
ReactAgent notifyAgent,
MemorySaver memorySaver) {
return ReactAgent.builder()
.name("personal_assistant")
.systemPrompt("你是一个智能个人助手。")
.model(chatModel)
.saver(memorySaver)
.tools(
AgentTool.getFunctionToolCallback(orderAgent),
AgentTool.getFunctionToolCallback(notifyAgent))
.build();
}
}
子Agent的工具类
@Component
public class OrderQueryTools {
@Tool(description = "查询订单状态,返回订单详情")
public String queryOrderStatus(@ToolParam(description = "订单号") String orderId) {
return "订单 " + orderId + " 状态:已发货,预计明天到达";
}
}@Component
public class NotifyTools {
@Tool(description = "发送通知给用户")
public String sendNotification(
@ToolParam(description = "收件人") String recipient,
@ToolParam(description = "通知内容") String message) {
return "已发送通知给 " + recipient + ":" + message;
}
}
使用效果
@Test
void testSupervisor() throws GraphRunnerException {
String query = "查一下订单456的状态,然后通知用户已发货";
AssistantMessage response = supervisorAgent.call(new UserMessage(query));
System.out.println(response.getText());
}
二、Routing模式:看菜下单,谁擅长谁来
2.1 适用场景
当用户问题可能有多种类型时:
- 咨询GitHub使用 → GitHub Agent
- 询问Notion功能 → Notion Agent
- 了解Slack操作 → Slack Agent
Routing模式实现智能路由——LLM先理解用户意图,再分发给最合适的子Agent。
2.2 实现思路
Routing与Supervisor的主要区别:
- Supervisor:协调多个子Agent同时工作
- Routing:仅负责分发,每次调用一个子Agent
@Bean("routingAgent")
public ReactAgent routingAgent(ChatModel chatModel,
ReactAgent githubAgent, ReactAgent notionAgent, ReactAgent slackAgent) {
return ReactAgent.builder()
.name("router")
.systemPrompt("""
你是一个智能路由器。根据用户的提问内容,
判断属于哪个专业领域,然后调用对应的专业工具。
重要规则:一次只调用一个工具。""")
.model(chatModel)
.tools(
AgentTool.getFunctionToolCallback(githubAgent),
AgentTool.getFunctionToolCallback(notionAgent),
AgentTool.getFunctionToolCallback(slackAgent))
.build();
}
三、Handoffs模式:A干不了就递给B
3.1 适用场景
客服系统中的典型流程:
- 收集保修信息 → 基础问题处理
- 故障分类 → 判断硬件/软件问题
- 解决方案 → 提供方案或转人工
Handoffs是状态驱动的模式——同一Agent根据当前步骤动态调整行为。
3.2 实现原理
三大核心组件:
- ModelHook:注册拦截器和状态管理策略
- ModelInterceptor:根据
current_step动态切换系统提示和工具 - ToolContextHelper:通过
getStateForUpdate(toolContext)更新状态
3.3 完整代码
Step 1: HandoffsConfig
@Configuration
public class HandoffsConfig { @Bean("supportAgent")
public ReactAgent supportAgent(ChatModel chatModel, MemorySaver memorySaver) {
List allTools = List.of(
SupportTools.recordWarrantyStatusTool(),
SupportTools.recordIssueTypeTool(),
SupportTools.provideSolutionTool(),
SupportTools.escalateToHumanTool()); return ReactAgent.builder()
.name("support_agent")
.systemPrompt("你是客服助手,帮助用户解决设备问题。")
.model(chatModel)
.tools(allTools)
.hooks(new HandoffsSupportHook())
.saver(memorySaver)
.build();
}
}
Step 2: HandoffsSupportHook
public class HandoffsSupportHook extends ModelHook { private final ModelInterceptor stepConfigInterceptor; public HandoffsSupportHook() {
this.stepConfigInterceptor = new StepConfigInterceptor(Map.of(
"warranty_collector", new StepConfig(
"你是客服助手,负责收集保修状态。",
List.of(SupportTools.recordWarrantyStatusTool()), List.of()),
"issue_classifier", new StepConfig(
"你是技术支持,判断硬件故障还是软件问题。",
List.of(SupportTools.recordIssueTypeTool()),
List.of("warranty_status")),
"resolution_specialist", new StepConfig(
"你是解决方案专家。提供方案或转人工。",
List.of(SupportTools.provideSolutionTool(),
SupportTools.escalateToHumanTool()),
List.of("warranty_status", "issue_type"))));
} @Override
public List getModelInterceptors() {
return List.of(stepConfigInterceptor);
} @Override
public Map getKeyStrategys() { // 注意方法名
return Map.of(
"current_step", new ReplaceStrategy(),
"warranty_status", new ReplaceStrategy(),
"issue_type", new ReplaceStrategy());
} public record StepConfig(String prompt, List tools,
List requiredKeys) {}
}
Step 3: StepConfigInterceptor
class StepConfigInterceptor extends ModelInterceptor { private final Map stepConfigMap; StepConfigInterceptor(Map stepConfigMap) {
this.stepConfigMap = stepConfigMap;
} @Override
public ModelResponse interceptModel(ModelRequest request,
ModelCallHandler handler) {
Map context = request.getContext();
String currentStep = (String) context.getOrDefault(
"current_step", "warranty_collector"); StepConfig stepConfig = stepConfigMap.getOrDefault(
currentStep, stepConfigMap.get("warranty_collector")); for (String required : stepConfig.requiredKeys()) {
if (context.get(required) == null) {
throw new IllegalStateException(
required + " 必须在进入 " + currentStep + " 之前设置");
}
} List toolNames = stepConfig.tools().stream()
.map(t -> t.getToolDefinition().name())
.toList(); ModelRequest overridden = ModelRequest.builder(request)
.systemMessage(new SystemMessage(stepConfig.prompt()))
.tools(toolNames)
.build(); return handler.call(overridden); // 必须调用handler继续执行
}
}
Step 4: SupportTools
public final class SupportTools { @Tool(name = "record_warranty_status",
description = "记录客户的保修状态,并切换到故障分类步骤")
public String recordWarrantyStatus(
@ToolParam(description = "in_warranty 或 out_of_warranty") String status,
ToolContext toolContext) {
ToolContextHelper.getStateForUpdate(toolContext)
.ifPresent(update -> { // Optional处理
update.put("warranty_status", status);
update.put("current_step", "issue_classifier");
});
return "已记录保修状态:" + status;
} @Tool(name = "record_issue_type",
description = "记录故障类型(硬件或软件),并切换到解决方案步骤")
public String recordIssueType(
@ToolParam(description = "hardware 或 software") String issueType,
ToolContext toolContext) {
ToolContextHelper.getStateForUpdate(toolContext)
.ifPresent(update -> {
update.put("issue_type", issueType);
update.put("current_step", "resolution_specialist");
});
return "已记录故障类型:" + issueType;
} // 其他工具方法...
}
使用效果(4轮对话,同一threadId)
@Test
void testHandoffsWorkflow() throws GraphRunnerException {
RunnableConfig config = RunnableConfig.builder()
.threadId("test-session-1")
.build(); AssistantMessage r1 = supportAgent.call(new UserMessage("我手机屏幕碎了"), config);
AssistantMessage r2 = supportAgent.call(new UserMessage("还在保修期内"), config);
AssistantMessage r3 = supportAgent.call(new UserMessage("摔了一下屏幕裂了"), config);
AssistantMessage r4 = supportAgent.call(new UserMessage("怎么办"), config);
}
四、Skills模式:需要时才召唤
4.1 适用场景
当Agent拥有大量技能时,全量加载会导致上下文过长,资源浪费。Skills模式实现按需加载——初始只提供描述,使用时才加载完整内容。
4.2 实现原理
Skills模式基于渐进披露原则:
- 启动时注入技能元数据
- 通过
read_skill工具按需加载完整SKILL.md - 核心组件包括SkillRegistry、SkillsAgentHook和标准化的SKILL.md格式
4.3 完整代码
技能文件结构
src/main/resources/skills/
├── sales_analytics/
│ └── SKILL.md
└── inventory_management/
└── SKILL.md
SKILL.md示例:
---
name: sales_analytics
description: 数据库Schema和业务逻辑,用于销售数据分析。包含客户、订单、收入等表。
---# 销售数据分析## 数据库Schema| 表名 | 说明 | 主要字段 |
|------|------|----------|
| customers | 客户信息 | id, name, email |
| orders | 订单信息 | id, customer_id, amount |
| revenue | 收入记录 | id, order_id, amount |## 示例查询SELECT c.name, SUM(o.amount) as total_amount
FROM customers c JOIN orders o ON c.id = o.customer_id
WHERE o.order_date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY c.id, c.name HAVING total_amount > 1000;
配置类
@Configuration
public class SkillsConfig { @Bean
public SkillRegistry skillRegistry() {
return ClasspathSkillRegistry.builder()
.classpathPath("skills")
.build();
} @Bean
public SkillsAgentHook skillsAgentHook(SkillRegistry skillRegistry) {
return SkillsAgentHook.builder()
.skillRegistry(skillRegistry)
.build();
} @Bean("sqlAssistantAgent")
public ReactAgent sqlAssistantAgent(ChatModel chatModel,
SkillsAgentHook skillsAgentHook) {
return ReactAgent.builder()
.name("sql_assistant")
.systemPrompt("""
你是一个SQL查询助手,帮助用户编写针对业务数据库的查询。
当需要特定领域的详细表结构或业务逻辑时,使用read_skill工具。""")
.model(chatModel)
.hooks(List.of(skillsAgentHook))
.build();
}
}