第六篇:实现多客服系统与任务分配

在前几篇中,我们已经实现了机器人将客户的提问转发到群聊,并支持客服通过群聊回复客户。本篇将进一步升级系统,支持多客服功能,并实现任务分配机制,让多个客服可以高效地协作处理客户问题。

推荐正在找工作的朋友们:

就业指导面试指导 (不是机构)
公众号:Java直达Offer
微信:
添加微信

多客服的核心挑战

任务分配:如何在多个客服之间合理分配客户问题,避免重复处理或遗漏。
客服状态管理:需要跟踪每个客服的在线/离线状态,确保问题不会分配给离线客服。
负载均衡:在客服数量较多的情况下,需要均匀分配客户问题,防止单个客服被过度占用。

1. 设计多客服任务分配机制

1.1 客服列表管理

首先,我们需要一个数据结构来管理所有客服的信息,包括:

客服的 Telegram 用户 ID。
客服的当前状态(在线/离线)。
客服当前处理的客户数。
可以使用一个 Map 存储客服状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

class CustomerService {
private Long userId; // 客服 Telegram 用户 ID
private boolean isOnline; // 是否在线
private int currentLoad; // 当前处理客户数量

public CustomerService(Long userId, boolean isOnline, int currentLoad) {
this.userId = userId;
this.isOnline = isOnline;
this.currentLoad = currentLoad;
}

// Getter 和 Setter 方法
public Long getUserId() {
return userId;
}

public boolean isOnline() {
return isOnline;
}

public void setOnline(boolean online) {
isOnline = online;
}

public int getCurrentLoad() {
return currentLoad;
}

public void incrementLoad() {
this.currentLoad++;
}

public void decrementLoad() {
this.currentLoad--;
}
}

// 全局客服列表
private final ConcurrentHashMap<Long, CustomerService> customerServiceList = new ConcurrentHashMap<>();

1.2 添加客服

机器人管理员可以通过发送命令 /add客服 来添加新的客服。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String messageText = update.getMessage().getText();
Long chatId = update.getMessage().getChatId();

// 判断是否是管理员添加客服
if (messageText.startsWith("/add客服")) {
Long newCustomerServiceId = extractUserIdFromCommand(messageText);
addCustomerService(newCustomerServiceId);
sendReplyToAdmin(chatId, "成功添加客服: " + newCustomerServiceId);
}
}
}

// 从命令中提取用户 ID
private Long extractUserIdFromCommand(String command) {
// 假设命令格式为 "/add客服 12345"
String[] parts = command.split(" ");
return Long.parseLong(parts[1]);
}

// 添加客服到列表
private void addCustomerService(Long userId) {
customerServiceList.put(userId, new CustomerService(userId, true, 0));
}

2. 实现任务分配逻辑

2.1 选择最优客服

在任务分配时,我们需要选择一个合适的客服。优先选择:

当前负载最小的在线客服。
如果存在多名客服负载相同,则随机选择一个。
实现代码如下:

1
2
3
4
5
6
7
8
private Long allocateCustomerService() {
return customerServiceList.values().stream()
.filter(CustomerService::isOnline) // 仅选择在线客服
.min(Comparator.comparingInt(CustomerService::getCurrentLoad)) // 按负载升序排序
.map(CustomerService::getUserId)
.orElse(null); // 如果没有在线客服,返回 null
}

2.2 转发问题到指定客服

当客户发送问题时,机器人会自动分配一个客服,并将问题转发给该客服。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void forwardToAllocatedCustomerService(Long customerChatId, String question) {
Long allocatedCustomerServiceId = allocateCustomerService();

if (allocatedCustomerServiceId != null) {
// 转发问题到客服
String message = "客户 ID: " + customerChatId + "\n问题: " + question;
sendMessageToCustomerService(allocatedCustomerServiceId, message);

// 更新客服负载
customerServiceList.get(allocatedCustomerServiceId).incrementLoad();

// 记录分配关系
customerQuestionMap.put(customerChatId, allocatedCustomerServiceId);
} else {
// 如果没有在线客服,通知客户
sendReplyToCustomer(customerChatId, "暂时没有在线客服,请稍后再试!");
}
}

// 发送消息到客服
private void sendMessageToCustomerService(Long customerServiceId, String message) {
SendMessage sendMessage = new SendMessage();
sendMessage.setChatId(customerServiceId);
sendMessage.setText(message);

try {
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}

3. 客服状态切换

客服可以通过命令 /上线 或 /离线 切换自己的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public void onUpdateReceived(Update update) {
if (update.hasMessage() && update.getMessage().hasText()) {
String messageText = update.getMessage().getText();
Long chatId = update.getMessage().getChatId();

// 客服上线
if (messageText.equals("/上线")) {
setCustomerServiceOnline(chatId, true);
sendReplyToCustomerService(chatId, "您已上线,开始接收客户问题。");
}

// 客服离线
if (messageText.equals("/离线")) {
setCustomerServiceOnline(chatId, false);
sendReplyToCustomerService(chatId, "您已离线,停止接收客户问题。");
}
}
}

private void setCustomerServiceOnline(Long userId, boolean isOnline) {
CustomerService customerService = customerServiceList.get(userId);
if (customerService != null) {
customerService.setOnline(isOnline);
}
}

4. 离线消息提醒

当客户发送消息时,如果分配的客服不在线,可以将问题存储为离线消息,并在客服上线时提醒。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 客服上线时发送未处理问题
private void notifyPendingMessages(Long customerServiceId) {
List<Long> pendingCustomers = customerQuestionMap.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), customerServiceId))
.map(Map.Entry::getKey)
.collect(Collectors.toList());

for (Long customerId : pendingCustomers) {
String message = "您有未处理的客户问题:客户 ID " + customerId;
sendMessageToCustomerService(customerServiceId, message);
}
}

下一步规划

我们已经实现了:

多客服管理。
客服任务分配和负载均衡。
客服上线/离线状态切换。
接下来,可以进一步扩展以下功能:

智能客服机器人:结合 AI 技术,为简单问题提供自动回复。
统计与报表:记录每个客服的工作量,生成报表分析。
在下一篇中,我们将探索如何将 AI 整合到客服系统中,打造更高效的智能化客服系统。敬请期待!