openCallHub的IVR系统设计与实现
文章详细介绍了openCallHub的IVR系统设计与实现,包括IVR模块的架构设计、工作流程、节点类型与处理逻辑、测试与性能调优等方面。系统采用分层架构,包含领域层、服务层、处理器层、状态机层和路由层,通过XML流程引擎与MRCP语音交互的协同实现动态语音交互。
IVR模块的架构与工作流程
IVR(Interactive Voice Response)模块是openCallHub的核心组件之一,负责处理电话自动流程,如语音导航、按键选择、转接等功能。以下将详细介绍其架构设计和工作流程。
架构设计
IVR模块采用分层架构,主要分为以下几个部分:
-
领域层(Domain Layer)
包含实体类(如FlowInfo、FlowInstances)和值对象(如FlowNodeVo、FlowEdgeVo),用于描述业务流程和数据模型。 -
服务层(Service Layer)
提供业务逻辑的实现,包括:FlowInfoServiceImpl:管理IVR流程的增删改查。FlowInstancesServiceImpl:处理流程实例的状态管理。FlowNodeExecutionHistoryServiceImpl:记录节点执行历史。
-
处理器层(Handler Layer)
负责具体节点的执行逻辑,包括:FlowMenuHandler:处理菜单节点。FlowTransferHandler:处理转接节点。FlowHttpHandler:处理HTTP请求节点。
-
状态机层(State Machine Layer)
通过RedisStateMachineConfig和FlowStateMachineListener实现流程状态的管理和监听。 -
路由层(Route Layer)
处理流程中的路由逻辑,如:FlowAgentRouteHandler:转接到指定坐席。FlowSkillGroupRouteHandler:转接到技能组。
工作流程
IVR模块的工作流程如下:
-
流程启动
- 用户拨打电话后,
FlowStartHandler初始化流程实例。 - 流程实例状态通过
FlowInstances记录。
- 用户拨打电话后,
-
节点执行
- 每个节点(如菜单、转接、播放语音)由对应的
Handler处理。 - 节点执行结果通过
FlowNodeExecutionHistory记录。
- 每个节点(如菜单、转接、播放语音)由对应的
-
状态转换
- 状态机(
RedisStateMachineConfig)驱动流程从一个节点跳转到下一个节点。 FlowStateMachineListener监听状态变化并触发后续逻辑。
- 状态机(
-
流程结束
- 流程结束时,
FlowEndHandler标记流程实例为完成状态。
- 流程结束时,
关键代码示例
以下是一个简单的菜单节点处理逻辑(FlowMenuHandler):
public class FlowMenuHandler extends AbstractIFlowNodeHandler {
@Override
public void execute(FlowDataContext flowData) {
FlowMenuNodeProperties properties = flowData.getNodeProperties();
// 播放菜单语音
playMenu(properties.getPrompt());
// 等待用户按键
String input = waitForInput();
// 根据按键跳转到下一个节点
String nextNode = getNextNode(input, properties.getButtons());
flowData.setNextNode(nextNode);
}
}
流程图
总结
IVR模块通过分层设计和状态机驱动,实现了灵活的电话自动流程管理。开发者可以通过扩展Handler和配置节点属性,快速定制复杂的IVR场景。
XML流程引擎与MRCP语音交互的协同
在IVR系统中,XML流程引擎与MRCP语音交互的协同是实现动态语音交互的核心机制。通过XML定义流程节点,结合MRCP协议与语音引擎(如ASR/TTS)交互,系统能够高效处理语音输入与输出。以下从设计、实现与协同机制三方面展开。
设计原理
-
XML流程引擎
通过XML文件定义IVR流程节点,每个节点包含以下属性:id: 节点唯一标识type: 节点类型(如menu、playback、transfer)properties: 节点配置(如语音文件路径、转接目标)
<node id="welcome" type="playback"> <properties> <property name="audio" value="welcome.wav"/> </properties> </node> -
MRCP协议
MRCP(Media Resource Control Protocol)通过以下消息类型与语音引擎交互:RECOGNIZE: 语音识别请求SPEAK: 语音合成请求INTERPRET: 语义解析请求
// MRCP请求示例 MrcpRequest request = new MrcpRequest(); request.setMethod("RECOGNIZE"); request.setHeader("Content-Type", "text/plain"); request.setBody("请说出您的需求");
实现机制
-
流程引擎解析
使用FlowInfoServiceImpl加载并解析XML流程,生成流程实例(FlowInstances)。关键方法:add(FlowInfoAddQuery query): 新增流程定义getInfo(Long id): 获取流程详情
@Override public FlowInfoVo getInfo(Long id) { FlowInfo flowInfo = flowInfoMapper.selectById(id); return convertToVo(flowInfo); } -
MRCP会话管理
MrcpSessionManager负责会话生命周期管理:createSession(String sessionId): 创建会话destroySession(String sessionId): 销毁会话
协同流程
-
语音播放与采集
FlowPlaybackHandler调用TTS引擎播放语音。FlowMenuHandler通过ASR引擎采集用户输入。
public void execute(FlowDataContext flowData) { MrcpRequest request = new MrcpRequest(); request.setMethod("SPEAK"); request.setBody(properties.getAudio()); mrcpSession.process(request); } -
动态语法加载
GrammarManager根据流程节点动态加载语法文件(如DTMF或语音命令):GrammarManager.storeGrammar(sessionId, "menu", "<grammar><rule id=\"command\"><one-of><item>1</item></one-of></rule></grammar>");
性能优化
-
会话复用
通过RedisStateMachineConfig缓存会话状态,减少重复创建开销。 -
异步处理
MRCP响应通过MrcpSessionHandler异步回调,避免阻塞主线程。
通过上述设计,XML流程引擎与MRCP语音交互实现了高效协同,为IVR系统提供了灵活的语音交互能力。
IVR节点的类型与处理逻辑
在openCallHub的IVR系统中,节点是构建交互式语音响应流程的核心组件。每个节点代表一个特定的交互步骤,例如播放语音、收集用户输入、转接电话等。本节将详细介绍IVR节点的类型及其处理逻辑,并通过代码示例和流程图展示其实现细节。
节点类型
IVR节点根据功能可分为以下几类:
-
起始节点(Start Node)
起始节点是IVR流程的入口点,通常用于初始化流程上下文或执行前置操作。其属性包括:- 欢迎语音提示
- 流程ID绑定
public class FlowStartNodeProperties extends FlowNodeProperties { private String welcomePrompt; private Long flowId; } -
播放节点(Playback Node)
播放节点用于向用户播放语音或提示音。其属性包括:- 语音文件路径
- 播放次数
- 超时设置
public class FlowPlaybackNodeProperties extends FlowNodeProperties { private String audioFile; private int repeatCount; private int timeout; } -
菜单节点(Menu Node)
菜单节点允许用户通过按键选择不同的选项。其属性包括:- 菜单提示音
- 按键映射(按键值与目标节点的关联)
public class FlowMenuNodeProperties extends FlowNodeProperties { private String menuPrompt; private Map<String, String> buttonMappings; } -
转接节点(Transfer Node)
转接节点用于将通话转接到其他分机或外部号码。其属性包括:- 目标号码
- 转接类型(内部/外部)
public class FlowTransferNodeProperties extends FlowNodeProperties { private String targetNumber; private TransferType transferType; } -
HTTP请求节点(HTTP Node)
HTTP请求节点用于与外部服务交互,例如验证用户输入或获取动态数据。其属性包括:- 请求URL
- 请求方法(GET/POST)
- 请求头
public class FlowHttpNodeProperties extends FlowNodeProperties { private String url; private HttpMethod method; private List<HttpHeader> headers; } -
结束节点(End Node)
结束节点用于终止IVR流程。其属性包括:- 结束语音提示
- 是否记录通话结果
public class FlowEndNodeProperties extends FlowNodeProperties { private String endPrompt; private boolean logResult; }
节点处理逻辑
每个节点的处理逻辑由对应的处理器(Handler)实现,这些处理器继承自AbstractIFlowNodeHandler基类。以下是典型节点的处理流程:
-
播放节点的处理逻辑
public class FlowPlaybackHandler extends AbstractIFlowNodeHandler { @Override public void execute(FlowDataContext flowData) { FlowPlaybackNodeProperties properties = flowData.getNodeProperties(); // 播放语音文件 playAudio(properties.getAudioFile(), properties.getRepeatCount()); // 更新流程状态 flowData.setNextNode(properties.getNextNode()); } } -
菜单节点的处理逻辑
-
转接节点的处理逻辑
public class FlowTransferHandler extends AbstractIFlowNodeHandler { @Override public void execute(FlowDataContext flowData) { FlowTransferNodeProperties properties = flowData.getNodeProperties(); // 根据转接类型执行转接 if (properties.getTransferType() == TransferType.INTERNAL) { transferToExtension(properties.getTargetNumber()); } else { transferToExternal(properties.getTargetNumber()); } } }
节点状态管理
IVR流程的状态通过FlowDataContext对象维护,该对象包含当前节点、用户输入和流程上下文等信息。状态转换由FlowStateMachineListener监听并处理。
public class FlowStateMachineListener {
@Override
public void stateEntered(State<Object, Object> state) {
// 记录节点进入事件
logNodeEntry(state.getId());
}
}
通过以上设计,openCallHub的IVR系统能够灵活支持多种交互场景,并为开发者提供清晰的扩展接口。
IVR流程的测试与性能调优
在IVR(Interactive Voice Response)系统的设计与实现中,测试与性能调优是确保系统稳定性和高效性的关键环节。本节将详细介绍如何对IVR流程进行全面的测试,并通过性能调优提升系统的响应速度和并发处理能力。
测试策略与方法
1. 单元测试
单元测试是验证IVR流程中每个独立模块功能正确性的基础。以下是一个针对FlowPlaybackHandler的单元测试示例:
@Test
public void testFlowPlaybackHandler() {
FlowDataContext flowData = new FlowDataContext();
FlowPlaybackNodeProperties properties = new FlowPlaybackNodeProperties();
properties.setAudioFile("welcome.wav");
FlowPlaybackHandler handler = new FlowPlaybackHandler();
handler.execute(flowData);
assertEquals("welcome.wav", flowData.getCurrentAudioFile());
}
2. 集成测试
集成测试用于验证IVR流程中多个模块的协同工作能力。例如,测试FlowTransferHandler与FlowSipRouteHandler的交互:
@Test
public void testFlowTransferToSipRoute() {
FlowDataContext flowData = new FlowDataContext();
FlowTransferNodeProperties properties = new FlowTransferNodeProperties();
properties.setTarget("sip:1001@example.com");
FlowTransferHandler transferHandler = new FlowTransferHandler();
transferHandler.execute(flowData);
FlowSipRouteHandler sipHandler = new FlowSipRouteHandler();
sipHandler.handler(flowData, properties);
assertEquals("sip:1001@example.com", flowData.getCurrentTarget());
}
3. 性能测试
性能测试用于评估IVR系统在高并发场景下的表现。以下是一个使用JMeter模拟并发调用的测试计划:
Thread Group:
- Number of Threads: 100
- Ramp-Up Period: 10
- Loop Count: 10
HTTP Request:
- Path: /ivr/start
- Method: POST
- Body: {"flowId": "123"}
性能调优
1. 数据库优化
IVR系统通常需要频繁读写数据库,优化数据库查询可以显著提升性能。例如,为FlowInstances表添加索引:
CREATE INDEX idx_flow_instance_status ON FlowInstances(status);
2. 缓存策略
使用Redis缓存高频访问的数据,减少数据库压力。以下是一个缓存FlowInfo的示例:
@Cacheable(value = "flowInfo", key = "#id")
public FlowInfoVo getInfo(Long id) {
return flowInfoMapper.selectById(id);
}
3. 异步处理
将非实时性任务(如日志记录)异步化,提升主流程的响应速度。例如,使用@Async注解:
@Async
public void logExecutionHistory(FlowNodeExecutionHistory history) {
flowNodeExecutionHistoryMapper.insert(history);
}
4. 资源池化
通过资源池化(如数据库连接池、线程池)避免频繁创建和销毁资源。以下是一个配置线程池的示例:
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
性能监控与分析
1. 监控指标
通过Prometheus和Grafana监控以下关键指标:
- 请求响应时间
- 并发连接数
- 数据库查询耗时
2. 日志分析
使用ELK(Elasticsearch, Logstash, Kibana)分析IVR流程中的异常日志,快速定位问题。
logstash.conf:
input {
file {
path => "/var/log/ivr.log"
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
}
}
总结
通过全面的测试策略和性能调优手段,可以确保IVR系统在高并发场景下依然稳定高效。单元测试和集成测试保障功能正确性,性能测试和调优提升系统响应能力,监控与分析则为持续优化提供数据支持。
总结
openCallHub的IVR系统通过分层设计和状态机驱动,实现了灵活的电话自动流程管理。系统支持多种节点类型,如起始节点、播放节点、菜单节点、转接节点等,并通过全面的测试策略和性能调优手段确保系统在高并发场景下的稳定性和高效性。开发者可以通过扩展Handler和配置节点属性,快速定制复杂的IVR场景。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



