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

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

构建一个智能客户服务系统,包含客户信息服务和订单服务两个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 
('张三', 'zhangsan@example.com', '13812345678', '北京市朝阳区', 'GOLD', '2024-01-15T10:30:00'),
('李四', 'lisi@example.com', '13987654321', '上海市浦东新区', 'SILVER', '2024-02-20T14:20:00'),
('王五', 'wangwu@example.com', '13555666777', '广州市天河区', 'BRONZE', '2024-03-10T09:15:00'),
('赵六', 'zhaoliu@example.com', '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/zhangsan@example.com

# 测试会员分析
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 小时前
Spring @TransactionalEventListener 解读
spring boot·后端·spring
小小工匠3 小时前
Maven - Spring Boot 项目打包本地 jar 的 3 种方法
spring boot·maven·jar·system scope
板板正5 小时前
Spring Boot 整合MongoDB
spring boot·后端·mongodb
泉城老铁6 小时前
在高并发场景下,如何优化线程池参数配置
spring boot·后端·架构
泉城老铁6 小时前
Spring Boot中实现多线程6种方式,提高架构性能
spring boot·后端·spring cloud
hrrrrb7 小时前
【Java Web 快速入门】九、事务管理
java·spring boot·后端
AI大模型7 小时前
基于 Ollama 本地 LLM 大语言模型实现 ChatGPT AI 聊天系统
程序员·llm·ollama
AI大模型7 小时前
AI大模型选择指南:从ChatGPT到国产新秀,一文看懂如何选对你的AI助手
gpt·程序员·llm
布朗克1689 小时前
Spring Boot项目通过RestTemplate调用三方接口详细教程
java·spring boot·后端·resttemplate
IT毕设实战小研10 小时前
基于Spring Boot校园二手交易平台系统设计与实现 二手交易系统 交易平台小程序
java·数据库·vue.js·spring boot·后端·小程序·课程设计