队列与 ACD
ACD(Automatic Call Distribution)是呼叫中心的核心引擎,负责将排队中的呼叫智能分配给合适的坐席。
1. ACD 架构
入局呼叫
│
▼
队列 (Queue)
│
├── 优先级排序
├── 时段检查
├── 溢出判断
│
▼
坐席选择 (Strategy)
│
├── 技能过滤
├── 策略算法
│
▼
分配给坐席 ──► 坐席振铃 ──► 接听/未接
2. ACD 策略配置
2.1 策略结构
# 在 ACD 配置中定义策略
[acd]
enabled = true
default_policy = "support"
[acd.policies.support]
name = "Support Policy"
[acd.policies.support.priority]
wait_time_weight = 1.0
base_priority = 0
fifo_within_same_priority = true
[acd.policies.support.strategy]
strategy_type = "longest_idle" # 核心算法
max_concurrent_calls = 1
[acd.policies.support.overflow]
triggers = [
{ type = "timeout", value = 120, action = "overflow" }
]
chain = ["voicemail"]
retry_per_target = 1
2.2 坐席分配算法
| 算法 | 说明 | 适用场景 |
|---|---|---|
longest_idle | 最长空闲优先(默认) | 均匀分配工作量 |
least_answered | 最少接听数优先 | 新坐席保护 |
round_robin | 轮询 | 均匀分配 |
skill_based | 技能综合评分 | 多技能坐席 |
random | 随机 | 特殊场景 |
2.3 技能评分算法
skill_based 策略使用加权评分:
得分 = 技能匹配度 × 0.6 + 空闲时长 × 0.3 + 优先级 × 0.1
权重可在策略配置中自定义:
[acd.policies.support.strategy]
strategy_type = "skill_based"
max_concurrent_calls = 2
require_exact_skill = false
[acd.policies.support.strategy.skill_weights]
skill_match = 0.6
idle_time = 0.3
priority = 0.1
3. 优先级排队
3.1 优先级计算
优先级分 = base_priority + vip_bonus + wait_time × wait_time_weight
| 参数 | 说明 | 默认值 |
|---|---|---|
| base_priority | 基础分 | 0 |
| vip_bonus | VIP 等级加分(按等级映射) | 无 |
| wait_time_weight | 等待时间每秒加分 | 1.0 |
3.2 VIP 配置
[acd.policies.support.priority]
base_priority = 0
wait_time_weight = 1.5
[acd.policies.support.priority.vip_bonus]
gold = 100
silver = 50
bronze = 20
3.3 排队规则
- 同优先级内 FIFO(先到先服务)
- 高优先级呼叫始终优先分配
- 等待时间越长,优先级越高(防止饥饿)
4. 溢出处理
4.1 溢出模式(0.5+)
技能组的 overflow_mode 决定溢出链的推进方式:
| 模式 | 行为 |
|---|---|
replace(默认) | 溢出后呼叫转移到链中下一个技能组 |
cumulative | 累积式升级——追加更多技能组,原组与溢出组同时振铃 |
sequential | 顺序式溢出——呼叫在当前队列停留 threshold_secs 后出队,按链顺序重新排入下一个溢出技能组;链尾保持等待至全局 max_wait |
顺序式模式避免了一次性惊扰所有溢出组——只有真正在上游耗尽时间的呼叫,才会打断下游坐席。
4.2 溢出触发条件
| 触发类型 | 说明 | 示例 |
|---|---|---|
timeout | 等待超时(秒) | 120 秒未分配 |
queue_length | 队列长度超限 | 排队 ≥ 50 人 |
no_agents | 无可用坐席 | 所有坐席离线 |
4.3 溢出目标链
按顺序尝试,每个目标最多重试 N 次:
[[acd.policies.support.overflow.chain]]
skill_group = { id = "senior" } # 先溢出到高级组
[[acd.policies.support.overflow.chain]]
"voicemail" = {} # 再到语音信箱
| 目标类型 | 说明 |
|---|---|
skill_group | 溢出到其他技能组 |
voicemail | 转语音信箱 |
callback | 创建回呼任务 |
back_to_ivr | 返回 IVR |
hangup | 挂断 |
4.4 溢出事件与等待深度(0.5+)
- 链上每一次移交都会发出
overflow_joined事件,主管可以准确看到呼叫处于升级路径的哪一环。 - 等待深度按队列统计——多队列坐席在控制台看到的是每个队列的准确计数,而不是混在一起的单一数字。
4.5 跨节点严格 FIFO
集群部署下,派单门控强制跨节点严格 FIFO:在节点 A 等待更久的呼叫,会先于节点 B 上的新呼叫被派给 B 上注册的坐席,消除朴素的节点内排队带来的“插队“问题。
4.6 队列等待音(0.5+)
设置 PBX 级的队列默认等待音:
[proxy]
queue_hold_music = "sounds/hold-music.wav"
队列自身的等待音([proxy.queues.<name>.hold].audio_file)优先于默认值;呼叫者等待时听到循环音乐,而不是静默。
5. 时段规则
5.1 工作时间
[acd.policies.support.schedule]
[acd.policies.support.schedule.business_hours]
start = "09:00"
end = "18:00"
timezone = "Asia/Shanghai"
5.2 节假日
[acd.policies.support.schedule.holidays]
"2026-01-01" = { name = "元旦", overflow_chain = ["voicemail"] }
"2026-02-17" = { name = "春节", overflow_chain = ["back_to_ivr"] }
5.3 夜间模式
[acd.policies.support.schedule.night_mode]
enabled = true
start = "18:00"
end = "09:00"
action = "voicemail"
6. 队列管理 API
| 操作 | 端点 | 说明 |
|---|---|---|
| 查看队列状态 | GET /cc/queue-detail | 排队数、等待时长 |
| 实时统计 | GET /cc/realtime | 所有队列实时数据 |
| ACD 配置 | GET /cc/acd/policies | 策略列表 |
| 导出配置 | POST /cc/acd/export | 导出为 TOML |
| 重载配置 | POST /cc/acd/reload | 重新加载 |
| ACD 诊断 | GET /cc/acd/diagnostics | 检查配置问题 |
7. 通话事件
ACD 分配过程中产生事件(通过 Queue Event 系统):
Enqueued:呼叫入队AgentAssigned:分配坐席AgentRinging:坐席振铃AgentAnswered:坐席接听AgentNoAnswer:坐席未接Dequeued:出队(超时/取消)OverflowJoined(0.5+):呼叫进入溢出技能组
事件以队列信号类型承载,并携带解析后的坐席与入队追踪信息,每次派单决策事后均可审计。
8. 弹屏头字段(0.5+)
派单给坐席时,RustPBX 会在坐席 INVITE 上携带 Call-Info 与 User-to-User(RFC 7433) 头——并在动态拨号列表重拨时重新解析这些头,弹屏数据在重振与转接后依然保留,而不只是第一次振铃。话务台客户端利用这些头在振铃时刻弹出客户资料。
9. 配置参考
| 选项 | 作用域 | 取值 / 默认 | 效果 |
|---|---|---|---|
enabled | [acd] | bool | 总开关 |
default_policy | [acd] | 策略名 | 未单独配置的队列使用的策略 |
priority.wait_time_weight | policy | 浮点,1.0 | 每秒等待时长加权 |
priority.base_priority | policy | 整数,0 | 起始分值 |
priority.vip_bonus.<tier> | policy | 整数映射 | 等级加分(gold/silver/…) |
priority.fifo_within_same_priority | policy | bool,true | 同优先级内 FIFO |
strategy.strategy_type | policy | longest_idle | least_answered | round_robin | skill_based | random | 派单算法 |
strategy.max_concurrent_calls | policy | 整数,1 | 坐席同时通话数 |
strategy.require_exact_skill | policy | bool,false | 全技能匹配 vs 任一技能 |
strategy.skill_weights.* | policy | 浮点 | skill_match / idle_time / priority 权重 |
overflow.mode | 技能组 | replace | cumulative | sequential | 溢出链推进方式 |
overflow.chain | policy | 数组 | 有序目标(skill_group/voicemail/callback/back_to_ivr/hangup) |
overflow.retry_per_target | policy | 整数,1 | 每个目标重试次数 |
schedule.business_hours | policy | start/end/timezone | 工作时间 |
schedule.night_mode | policy | enabled/start/end/action | 非工作时段动作 |
schedule.holidays.<date> | policy | name + overflow_chain | 分节假日行为 |
max_wait_secs | 技能组 | 整数,0 = 无限 | 硬性等待上限 |
sla_target_secs | 技能组 | 整数,30 | 报表用 SLA 目标 |
queue_hold_music | [proxy] | 路径/URL | 队列默认等待音 |
队列管理接口:GET /cc/queue-detail、GET /cc/realtime、GET /cc/acd/policies、POST /cc/acd/export、POST /cc/acd/reload、GET /cc/acd/diagnostics。