场景案例:智能客户服务系统
构建一个智能客户服务系统,包含客户信息服务和订单服务两个MCP服务器,以及一个AI客户端应用。
第一步:理解架构设计
MCP架构允许多个Spring Boot应用作为MCP服务器,它们连接到数据库并使用Spring AI MCP服务器支持来向MCP客户端应用暴露@Tool方法。
我们的系统架构:
- 客户信息MCP服务器 (customer-mcp-service): 管理客户数据
- 订单MCP服务器 (order-mcp-service): 管理订单数据
- AI客户端应用 (ai-client-service): 整合工具并提供智能服务
第二步:创建客户信息MCP服务器
2.1 Maven依赖配置
xml
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
2.2 客户实体类
java
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String phone;
private String address;
private String membershipLevel; // BRONZE, SILVER, GOLD
@Column(name = "created_date")
private LocalDateTime createdDate;
// 构造函数、getter和setter
public Customer() {}
public Customer(String name, String email, String phone, String address, String membershipLevel) {
this.name = name;
this.email = email;
this.phone = phone;
this.address = address;
this.membershipLevel = membershipLevel;
this.createdDate = LocalDateTime.now();
}
// getters and setters...
}
2.3 数据访问层
java
@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByMembershipLevel(String membershipLevel);
Optional<Customer> findByEmail(String email);
List<Customer> findByNameContainingIgnoreCase(String name);
}
2.4 工具服务类
java
@Service
public class CustomerTools {
private final CustomerRepository customerRepository;
public CustomerTools(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@Tool(description = "根据客户ID查找客户信息")
public Customer getCustomerById(
@ToolParam(description = "客户ID") Long customerId) {
return customerRepository.findById(customerId).orElse(null);
}
@Tool(description = "根据邮箱查找客户")
public Customer getCustomerByEmail(
@ToolParam(description = "客户邮箱") String email) {
return customerRepository.findByEmail(email).orElse(null);
}
@Tool(description = "根据会员等级查找客户列表")
public List<Customer> getCustomersByMembershipLevel(
@ToolParam(description = "会员等级:BRONZE, SILVER, GOLD") String membershipLevel) {
return customerRepository.findByMembershipLevel(membershipLevel);
}
@Tool(description = "根据姓名搜索客户")
public List<Customer> searchCustomersByName(
@ToolParam(description = "客户姓名关键词") String name) {
return customerRepository.findByNameContainingIgnoreCase(name);
}
}
2.5 主应用类
java
@SpringBootApplication
public class CustomerMcpServerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerMcpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider customerTools(CustomerTools customerTools) {
return MethodToolCallbackProvider.builder()
.toolObjects(customerTools)
.build();
}
}
2.6 配置文件 (application.yml)
yaml
spring:
ai:
mcp:
server:
name: customer-mcp-server
version: 1.0.0
jpa:
database-platform: H2
generate-ddl: true
hibernate:
ddl-auto: create-drop
h2:
console:
enabled: true
server:
port: 8061
logging:
level:
org.springframework.ai: DEBUG
2.7 测试数据 (import.sql)
sql
INSERT INTO customers (name, email, phone, address, membership_level, created_date) VALUES
('张三', '[email protected]', '13812345678', '北京市朝阳区', 'GOLD', '2024-01-15T10:30:00'),
('李四', '[email protected]', '13987654321', '上海市浦东新区', 'SILVER', '2024-02-20T14:20:00'),
('王五', '[email protected]', '13555666777', '广州市天河区', 'BRONZE', '2024-03-10T09:15:00'),
('赵六', '[email protected]', '13666777888', '深圳市南山区', 'GOLD', '2024-01-25T16:45:00');
第三步:创建订单MCP服务器
3.1 订单实体类
java
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long customerId;
private String orderNumber;
private BigDecimal totalAmount;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@Column(name = "order_date")
private LocalDateTime orderDate;
private String productName;
private Integer quantity;
// 构造函数、getter和setter
public Order() {}
public Order(Long customerId, String orderNumber, BigDecimal totalAmount,
OrderStatus status, String productName, Integer quantity) {
this.customerId = customerId;
this.orderNumber = orderNumber;
this.totalAmount = totalAmount;
this.status = status;
this.productName = productName;
this.quantity = quantity;
this.orderDate = LocalDateTime.now();
}
// getters and setters...
}
enum OrderStatus {
PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
}
3.2 订单工具服务
java
@Service
public class OrderTools {
private final OrderRepository orderRepository;
public OrderTools(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Tool(description = "根据客户ID查找订单列表")
public List<Order> getOrdersByCustomerId(
@ToolParam(description = "客户ID") Long customerId) {
return orderRepository.findByCustomerId(customerId);
}
@Tool(description = "根据订单号查找订单")
public Order getOrderByOrderNumber(
@ToolParam(description = "订单号") String orderNumber) {
return orderRepository.findByOrderNumber(orderNumber).orElse(null);
}
@Tool(description = "计算客户的总消费金额")
public BigDecimal calculateCustomerTotalSpent(
@ToolParam(description = "客户ID") Long customerId) {
List<Order> orders = orderRepository.findByCustomerId(customerId);
return orders.stream()
.map(Order::getTotalAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Tool(description = "根据订单状态查找订单")
public List<Order> getOrdersByStatus(
@ToolParam(description = "订单状态") String status) {
try {
OrderStatus orderStatus = OrderStatus.valueOf(status.toUpperCase());
return orderRepository.findByStatus(orderStatus);
} catch (IllegalArgumentException e) {
return Collections.emptyList();
}
}
}
第四步:创建AI客户端应用
4.1 Maven依赖
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
</dependencies>
4.2 智能客服控制器
java
@RestController
@RequestMapping("/api/customer-service")
public class CustomerServiceController {
private final ChatClient chatClient;
public CustomerServiceController(ChatClient.Builder chatClientBuilder,
ToolCallbackProvider tools) {
this.chatClient = chatClientBuilder
.defaultTools(tools)
.build();
}
@PostMapping("/query")
public ResponseEntity<String> handleCustomerQuery(@RequestBody CustomerQuery query) {
PromptTemplate promptTemplate = new PromptTemplate("""
你是一个专业的客服助手。请根据客户的问题提供准确和友好的回答。
客户问题: {question}
请使用可用的工具来获取相关信息,并提供详细的回答。
如果需要客户信息,请先通过邮箱或姓名搜索客户。
如果涉及订单问题,请查询相关订单信息。
回答要求:
1. 语言友好、专业
2. 信息准确、完整
3. 如果无法找到信息,请说明并建议其他解决方案
""");
Prompt prompt = promptTemplate.create(Map.of("question", query.getQuestion()));
String response = chatClient.prompt(prompt)
.call()
.content();
return ResponseEntity.ok(response);
}
@GetMapping("/customer-summary/{email}")
public ResponseEntity<String> getCustomerSummary(@PathVariable String email) {
PromptTemplate promptTemplate = new PromptTemplate("""
请为邮箱为 {email} 的客户生成一个详细的客户档案摘要。
摘要应包含:
1. 客户基本信息(姓名、联系方式、地址、会员等级)
2. 订单历史(订单数量、总消费金额、最近订单状态)
3. 客户价值评估
请使用专业但友好的语言,格式清晰易读。
""");
Prompt prompt = promptTemplate.create(Map.of("email", email));
String response = chatClient.prompt(prompt)
.call()
.content();
return ResponseEntity.ok(response);
}
@GetMapping("/membership-analysis/{level}")
public ResponseEntity<String> getMembershipAnalysis(@PathVariable String level) {
PromptTemplate promptTemplate = new PromptTemplate("""
请分析 {level} 级别的会员情况。
分析内容包括:
1. 该级别会员的数量
2. 该级别会员的消费特点
3. 业务建议和优化方案
请基于实际数据提供分析结果。
""");
Prompt prompt = promptTemplate.create(Map.of("level", level));
String response = chatClient.prompt(prompt)
.call()
.content();
return ResponseEntity.ok(response);
}
}
// 请求数据类
class CustomerQuery {
private String question;
public CustomerQuery() {}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
}
4.3 配置文件
yaml
spring:
ai:
mcp:
client:
sse:
connections:
customer-mcp-server:
url: http://localhost:8061
order-mcp-server:
url: http://localhost:8062
openai:
api-key: ${SPRING_AI_OPENAI_API_KEY}
server:
port: 8080
logging:
level:
org.springframework.ai: DEBUG
第五步:运行和测试
5.1 启动应用
bash
# 启动客户信息MCP服务器
cd customer-mcp-service
mvn spring-boot:run
# 启动订单MCP服务器
cd order-mcp-service
mvn spring-boot:run
# 设置OpenAI API密钥并启动客户端
export SPRING_AI_OPENAI_API_KEY=你的OpenAI密钥
cd ai-client-service
mvn spring-boot:run
5.2 测试API调用
bash
# 测试客户咨询
curl -X POST http://localhost:8080/api/customer-service/query \
-H "Content-Type: application/json" \
-d '{"question": "我想查询张三的订单情况"}'
# 测试客户摘要
curl http://localhost:8080/api/customer-service/customer-summary/[email protected]
# 测试会员分析
curl http://localhost:8080/api/customer-service/membership-analysis/GOLD
核心优势和特点
这个案例展示了MCP的核心优势:
- 工具复用: MCP提供了一种标准化的协议,使AI模型能够以结构化的方式与外部工具和资源进行交互
- 松耦合架构: 每个服务都是独立的MCP服务器,可以独立部署和扩展
- 智能整合: AI客户端可以自动组合来自不同服务的工具来解决复杂问题
- 标准化接口: 所有工具都通过MCP协议暴露,便于集成和维护
这个场景案例展示了如何使用Spring AI和MCP构建一个智能的分布式系统,其中AI能够自动调用多个服务的功能来提供综合性的客户服务。