Spring AI 多Agent协同实战:构建企业级智能客服系统
·
一、背景:为什么需要多Agent协同?
在企业级智能客服场景中,单一大模型Agent往往面临"样样通、样样松"的困境。用户的问题可能涉及订单查询、售后退换、技术支持、财务开票等多个领域,单个Agent既需要理解意图,又需要调用工具,还要处理业务逻辑,结果就是响应慢、准确率低、体验差。
多Agent协同的核心价值:
- 🎯 专业分工:每个Agent聚焦特定领域,能力更精准
- ⚡ 并行处理:复杂任务可拆解为多Agent并行执行
- 📈 可扩展性:新增业务场景只需添加新Agent,不影响现有系统
- 🔒 安全可控:不同Agent分配不同数据权限,降低风险
本文将基于 Spring AI + Function Calling 技术栈,手把手带你构建一个企业级多Agent智能客服系统。
二、方案设计:整体架构与角色分工
2.1 系统架构图
┌─────────────────────────────────────────────────────┐
│ 用户请求入口 │
└────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 接待 Agent (ReceptionAgent) │
│ 职责:意图识别、情绪分析、任务分发、会话管理 │
└────────────────────────┬────────────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 订单Agent │ │ 售后Agent │ │ 技术支持Agent│
│ OrderAgent │ │ AfterSaleAgent│ │ SupportAgent │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└─────────────┼─────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ Function Calling 工具层 │
│ 订单查询API │ 物流查询API │ 知识库检索 │
└─────────────────────────────────────────────────────┘
2.2 核心角色定义
| Agent角色 | 核心职责 | 拥有工具 |
|---|---|---|
| 接待Agent | 意图识别、情绪感知、任务分发、会话上下文管理 | 意图分类器、情绪分析 |
| 订单Agent | 订单查询、物流跟踪、退款进度查询 | orderQuery、logisticsQuery |
| 售后Agent | 退换货申请、售后政策解答、投诉受理 | afterSaleApply、policyQuery |
| 技术支持Agent | 产品使用问题、故障排查、解决方案推荐 | knowledgeBaseSearch、troubleshoot |
三、核心代码实现
3.1 环境依赖与配置
首先添加Spring AI依赖(Maven):
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0-M3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
Spring AI 配置类:
/**
* Spring AI 配置类
* 配置多Agent所需的ChatClient、FunctionCallback等
*/
@Configuration
@Slf4j
public class SpringAiConfig {
/**
* 通用ChatClient,用于接待Agent
*/
@Bean("generalChatClient")
public ChatClient generalChatClient(OpenAiChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultSystem("""
你是一个智能客服接待员,需要识别用户意图并分发到对应专业Agent。
请用友好、专业的语气与用户交流。
""")
.build();
}
/**
* 订单专用ChatClient,绑定订单相关工具
*/
@Bean("orderChatClient")
public ChatClient orderChatClient(OpenAiChatModel chatModel,
OrderQueryFunction orderQueryFunction,
LogisticsQueryFunction logisticsQueryFunction) {
return ChatClient.builder(chatModel)
.defaultSystem("""
你是专业的订单客服专员,负责处理订单查询、物流跟踪、退款查询等问题。
回答要准确、简洁,涉及金额和时间请务必核实。
""")
.defaultFunctions("orderQuery", "logisticsQuery")
.build();
}
/**
* 技术支持ChatClient,绑定知识库和排障工具
*/
@Bean("supportChatClient")
public ChatClient supportChatClient(OpenAiChatModel chatModel,
KnowledgeBaseFunction knowledgeBaseFunction,
TroubleshootFunction troubleshootFunction) {
return ChatClient.builder(chatModel)
.defaultSystem("""
你是资深技术支持工程师,负责解答产品使用问题、排查故障。
请分步骤引导用户排查,必要时提供解决方案。
""")
.defaultFunctions("knowledgeBaseSearch", "troubleshoot")
.build();
}
}
3.2 Function Calling 工具实现
以订单查询为例,实现Spring AI的FunctionCallback:
/**
* 订单查询工具函数
* 实现FunctionCallback接口,供大模型调用
*/
@Component("orderQuery")
@Slf4j
public class OrderQueryFunction implements FunctionCallback<OrderQueryFunction.Request, OrderQueryFunction.Response> {
@Override
public String getName() {
return "orderQuery";
}
@Override
public String getDescription() {
return "根据订单号查询订单详情,包括商品信息、金额、状态、下单时间";
}
@Override
public Class<Request> getInputType() {
return Request.class;
}
@Override
public Response apply(Request request) {
log.info("调用订单查询接口,订单号: {}", request.orderId());
// 模拟业务逻辑:实际项目中此处调用订单服务API
if ("ORD123456".equals(request.orderId())) {
return new Response(
request.orderId(),
"Spring AI 实战教程(实体书)",
new BigDecimal("99.00"),
"已发货",
LocalDateTime.of(2026, 6, 10, 14, 30),
"SF1234567890"
);
}
return new Response(request.orderId(), null, null, "未找到订单", null, null);
}
/**
* 请求参数定义 - 大模型会自动填充此字段
*/
public record Request(
@JsonProperty(required = true, value = "orderId")
@JsonPropertyDescription("订单号,格式为ORD开头+6位数字")
String orderId
) {}
/**
* 响应结果定义 - 返回给大模型的结构化数据
*/
public record Response(
String orderId, // 订单号
String productName, // 商品名称
BigDecimal amount, // 订单金额
String status, // 订单状态
LocalDateTime createTime, // 下单时间
String trackingNo // 物流单号
) {}
}
物流查询工具实现:
/**
* 物流查询工具函数
*/
@Component("logisticsQuery")
@Slf4j
public class LogisticsQueryFunction implements FunctionCallback<LogisticsQueryFunction.Request, LogisticsQueryFunction.Response> {
@Override
public String getName() {
return "logisticsQuery";
}
@Override
public String getDescription() {
return "根据物流单号查询物流跟踪信息";
}
@Override
public Class<Request> getInputType() {
return Request.class;
}
@Override
public Response apply(Request request) {
log.info("调用物流查询接口,单号: {}", request.trackingNo());
// 模拟物流信息
List<TrackingInfo> tracks = List.of(
new TrackingInfo(LocalDateTime.of(2026, 6, 12, 9, 0), "快件已到达【北京朝阳营业部】,正在派送"),
new TrackingInfo(LocalDateTime.of(2026, 6, 11, 18, 30), "快件已从【北京转运中心】发出"),
new TrackingInfo(LocalDateTime.of(2026, 6, 10, 20, 0), "快件已揽收")
);
return new Response(request.trackingNo(), "顺丰速运", "派送中", tracks);
}
public record Request(
@JsonProperty(required = true, value = "trackingNo")
@JsonPropertyDescription("物流单号")
String trackingNo
) {}
public record Response(
String trackingNo,
String carrier,
String status,
List<TrackingInfo> trackingHistory
) {}
public record TrackingInfo(LocalDateTime time, String description) {}
}
3.3 Agent 抽象与实现
定义Agent接口:
/**
* Agent 通用接口
*/
public interface Agent {
/**
* 获取Agent名称
*/
String getName();
/**
* 获取Agent描述(用于路由决策)
*/
String getDescription();
/**
* 处理用户消息
* @param userMessage 用户消息
* @param context 会话上下文
* @return Agent响应
*/
AgentResponse process(String userMessage, ChatContext context);
}
接待Agent实现 - 核心路由逻辑:
/**
* 接待Agent - 负责意图识别与任务分发
*/
@Component
@Slf4j
public class ReceptionAgent implements Agent {
private final ChatClient generalChatClient;
private final List<Agent> specialistAgents;
@Autowired
public ReceptionAgent(@Qualifier("generalChatClient") ChatClient generalChatClient,
List<Agent> specialistAgents) {
this.generalChatClient = generalChatClient;
this.specialistAgents = specialistAgents;
}
@Override
public String getName() {
return "接待客服";
}
@Override
public String getDescription() {
return "负责接待用户、识别意图、分发到专业客服";
}
@Override
public AgentResponse process(String userMessage, ChatContext context) {
// 步骤1:识别用户意图,判断应该路由到哪个专业Agent
String intentPrompt = buildIntentPrompt(userMessage);
String intentResult = generalChatClient.prompt()
.user(intentPrompt)
.call()
.content();
log.info("意图识别结果: {}", intentResult);
// 步骤2:根据意图路由到对应专业Agent
Agent targetAgent = routeToAgent(intentResult);
if (targetAgent != null) {
log.info("路由到专业Agent: {}", targetAgent.getName());
// 将当前上下文传递给专业Agent处理
AgentResponse specialistResponse = targetAgent.process(userMessage, context);
// 包装响应,添加路由说明
return AgentResponse.builder()
.agentName(targetAgent.getName())
.content(specialistResponse.getContent())
.routed(true)
.build();
}
// 步骤3:无法识别意图时,由接待Agent直接回复(澄清问题)
String reply = generalChatClient.prompt()
.user("用户问:" + userMessage + ",请礼貌地询问用户具体需要哪方面帮助," +
"可选方向:订单查询、售后问题、技术支持")
.call()
.content();
return AgentResponse.builder()
.agentName(getName())
.content(reply)
.routed(false)
.build();
}
/**
* 构建意图识别提示词
*/
private String buildIntentPrompt(String userMessage) {
StringBuilder sb = new StringBuilder();
sb.append("请分析以下用户问题属于哪个客服类别,只返回类别名称:\n");
sb.append("用户问题:").append(userMessage).append("\n\n");
sb.append("可选类别:\n");
for (Agent agent : specialistAgents) {
sb.append("- ").append(agent.getName()).append(":").append(agent.getDescription()).append("\n");
}
sb.append("\n如果都不匹配,请返回'接待客服'");
return sb.toString();
}
/**
* 根据意图识别结果路由到对应Agent
*/
private Agent routeToAgent(String intentResult) {
return specialistAgents.stream()
.filter(agent -> intentResult.contains(agent.getName()))
.findFirst()
.orElse(null);
}
}
订单Agent实现:
/**
* 订单专业Agent - 处理订单相关问题
*/
@Component
@Slf4j
public class OrderAgent implements Agent {
private final ChatClient orderChatClient;
@Autowired
public OrderAgent(@Qualifier("orderChatClient") ChatClient orderChatClient) {
this.orderChatClient = orderChatClient;
}
@Override
public String getName() {
return "订单客服";
}
@Override
public String getDescription() {
return "处理订单查询、物流跟踪、退款进度、发票开具等订单相关问题";
}
@Override
public AgentResponse process(String userMessage, ChatContext context) {
log.info("订单Agent处理用户请求: {}", userMessage);
// 调用带Function Calling的ChatClient,自动完成工具调用
String response = orderChatClient.prompt()
.user(userMessage)
// 携带历史会话上下文
.messages(context.getConversationHistory())
.call()
.content();
return AgentResponse.builder()
.agentName(getName())
.content(response)
.routed(false)
.build();
}
}
3.4 会话上下文管理
/**
* 会话上下文 - 管理多轮对话历史
*/
@Data
@Builder
public class ChatContext {
/**
* 会话ID
*/
private String sessionId;
/**
* 用户ID
*/
private String userId;
/**
* 当前对话历史
*/
private List<Message> conversationHistory;
/**
* 当前活跃的Agent
*/
private String activeAgent;
/**
* 扩展属性
*/
private Map<String, Object> attributes;
/**
* 添加消息到历史
*/
public void addMessage(Message message) {
if (conversationHistory == null) {
conversationHistory = new ArrayList<>();
}
conversationHistory.add(message);
// 保留最近20条消息,防止上下文溢出
if (conversationHistory.size() > 20) {
conversationHistory = conversationHistory.subList(
conversationHistory.size() - 20,
conversationHistory.size()
);
}
}
}
四、运行效果与测试
编写测试用例验证多Agent协同效果:
@SpringBootTest
@Slf4j
class MultiAgentCustomerServiceTest {
@Autowired
private ReceptionAgent receptionAgent;
@Test
void testOrderQuery() {
ChatContext context = ChatContext.builder()
.sessionId("test-001")
.userId("user-123")
.conversationHistory(new ArrayList<>())
.build();
String userMessage = "帮我查一下订单ORD123456的物流到哪了";
AgentResponse response = receptionAgent.process(userMessage, context);
log.info("=== 测试:订单物流查询 ===");
log.info("用户问题:{}", userMessage);
log.info("处理Agent:{}", response.getAgentName());
log.info("回复内容:\n{}", response.getContent());
// 验证:应该路由到订单客服
assertEquals("订单客服", response.getAgentName());
}
}
运行输出示例:
=== 测试:订单物流查询 ===
用户问题:帮我查一下订单ORD123456的物流到哪了
处理Agent:订单客服
回复内容:
您好,已为您查询到订单信息:
📦 订单号:ORD123456
🛍️ 商品:Spring AI 实战教程(实体书)
💰 金额:¥99.00
📊 状态:已发货
📅 下单时间:2026-06-10 14:30
🚚 物流信息:
- 承运商:顺丰速运
- 当前状态:派送中
- 物流轨迹:
06-12 09:00 快件已到达【北京朝阳营业部】,正在派送
06-11 18:30 快件已从【北京转运中心】发出
06-10 20:00 快件已揽收
您的包裹正在派送中,请保持电话畅通哦~
五、生产级优化建议
5.1 性能优化
- Agent路由缓存:相同意图的对话可直接复用上次路由结果,避免重复意图识别
- 流式响应:使用
stream()替代call(),提升首字响应速度 - 工具结果缓存:相同参数的Function Calling结果可缓存(如订单详情10分钟内有效)
// 流式响应示例
Flux<String> stream = orderChatClient.prompt()
.user(userMessage)
.stream()
.content();
5.2 稳定性保障
- 熔断降级:当某个专业Agent不可用时,自动降级由接待Agent兜底
- 超时控制:为每个Agent调用设置独立超时时间
- 重试机制:Function Calling失败时的自动重试策略
5.3 监控与可观测性
- 调用链追踪:记录每个Agent的调用耗时、Token消耗、工具调用次数
- 质量评估:定期抽检Agent回复质量,识别bad case
- 成本监控:按Agent维度统计Token消耗,优化Prompt降低成本
六、总结
本文基于Spring AI框架,实现了一个完整的多Agent协同智能客服系统。核心技术点包括:
- ✅ 使用Spring AI ChatClient构建不同角色的Agent
- ✅ 通过Function Calling实现业务工具与大模型的集成
- ✅ 设计接待Agent实现智能意图路由
- ✅ 会话上下文管理支持多轮对话
- ✅ 生产级优化建议,保障系统稳定运行
多Agent协同是企业级AI应用的必然趋势,Spring AI提供的Function Calling和灵活的ChatClient抽象,让多Agent系统的构建变得更加简单。
如果觉得文章对你有帮助,欢迎点赞👍、收藏⭐、关注👀 一键三连!
参考资料:
更多推荐



所有评论(0)