构建一个简单智能客户服务系统的案例

场景案例:智能客户服务系统

构建一个智能客户服务系统,包含客户信息服务和订单服务两个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的核心优势:

  1. 工具复用: MCP提供了一种标准化的协议,使AI模型能够以结构化的方式与外部工具和资源进行交互
  2. 松耦合架构: 每个服务都是独立的MCP服务器,可以独立部署和扩展
  3. 智能整合: AI客户端可以自动组合来自不同服务的工具来解决复杂问题
  4. 标准化接口: 所有工具都通过MCP协议暴露,便于集成和维护

这个场景案例展示了如何使用Spring AI和MCP构建一个智能的分布式系统,其中AI能够自动调用多个服务的功能来提供综合性的客户服务。

相关推荐
再学一点就睡2 小时前
🌆 一个人的城市,一群人的代码:前端小白的两个月“渡劫”实录
程序员
14L3 小时前
互联网大厂Java面试:从Spring Cloud到Kafka的技术考察
spring boot·redis·spring cloud·kafka·jwt·oauth2·java面试
地藏Kelvin3 小时前
Spring Ai 从Demo到搭建套壳项目(二)实现deepseek+MCP client让高德生成昆明游玩4天攻略
人工智能·spring boot·后端
一个有女朋友的程序员3 小时前
Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)
spring boot·redis·缓存
wh_xia_jun4 小时前
在 Spring Boot 中使用 JSP
java·前端·spring boot
yuren_xia4 小时前
在Spring Boot中集成Redis进行缓存
spring boot·redis·缓存
小奏技术5 小时前
基于 Spring AI 和 MCP:用自然语言查询 RocketMQ 消息
后端·aigc·mcp
yuren_xia5 小时前
Spring Boot + MyBatis 集成支付宝支付流程
spring boot·tomcat·mybatis
我爱Jack6 小时前
Spring Boot统一功能处理深度解析
java·spring boot·后端
RainbowJie17 小时前
Spring Boot 使用 SLF4J 实现控制台输出与分类日志文件管理
spring boot·后端·单元测试