电话机器人话术引擎说明
介绍
介绍请看这个页面 http://www.ddrj.com/smartivr/robot.html 。
和smartivr接口的区别,smartivr接口只实现了把ASR识别结果提交给http接口进行处理,根据http接口返回的动作执行放音等操作。
新一代电话机器人接口实现了话术解析引擎,可以不依赖外部接口直接完成整个机器人对话过程。
开始执行流程
<action application="cti_robot" data="flowname"/> <action application="set" data="park_timeout=3600000"/> <action application="park"/>
|
流程执行步骤记录
CREATE TABLE `conversation` ( `createtime` DATETIME NULL DEFAULT NULL COMMENT '记录生成事件', `callid` VARCHAR(50) NULL DEFAULT NULL COMMENT '通话ID' COLLATE 'utf8_unicode_ci', `current_appid` VARCHAR(50) NULL DEFAULT NULL COMMENT '当前执行APPID' COLLATE 'utf8_unicode_ci', `sequence` INT(11) NULL DEFAULT NULL COMMENT '序列号', `current_flowid` VARCHAR(50) NULL DEFAULT NULL COMMENT '当前流程ID' COLLATE 'utf8_unicode_ci', `input_type` INT(11) NULL DEFAULT NULL COMMENT '输入类型0:TEXT 1:DTMF 2:COMPLETE 10:CREATE 11:DESTORY', `input_args` VARCHAR(1024) NULL DEFAULT NULL COMMENT '输入参数' COLLATE 'utf8_unicode_ci', `input_nlp_args` VARCHAR(50) NULL DEFAULT NULL COMMENT 'nlp处理后的参数' COLLATE 'utf8_unicode_ci', `input_start_time` DATETIME NULL DEFAULT NULL COMMENT '输入开始时间', `input_duration` INT(11) NULL DEFAULT NULL COMMENT '输入持续时间', `input_play_time` INT(11) NULL DEFAULT NULL COMMENT '放音时间', `matching_method` INT(11) NULL DEFAULT NULL COMMENT '匹配方法0:mismatch 1:boot 2:regex 3:full 4:any', `matching_condition` VARCHAR(256) NULL DEFAULT NULL COMMENT '匹配表达式' COLLATE 'utf8_unicode_ci', `condition_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '匹配条件ID' COLLATE 'utf8_unicode_ci', `condition_weight` INT(11) NULL DEFAULT NULL, `matching_keyword` VARCHAR(50) NULL DEFAULT NULL COMMENT '匹配关键词' COLLATE 'utf8_unicode_ci', `response_type` INT(11) NULL DEFAULT NULL COMMENT '响应类型 1:flow 2:kb 3:mismatch', `response_description` VARCHAR(50) NULL DEFAULT NULL COMMENT '响应描述' COLLATE 'utf8_unicode_ci', `response_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '响应的FlowID,或者PromptID' COLLATE 'utf8_unicode_ci', `response_action` VARCHAR(50) NULL DEFAULT NULL COMMENT '响应动作' COLLATE 'utf8_unicode_ci', `response_args` VARCHAR(2048) NULL DEFAULT NULL COMMENT '响应参数' COLLATE 'utf8_unicode_ci', `response_text` VARCHAR(8192) NULL DEFAULT NULL COMMENT '响应文本' COLLATE 'utf8_unicode_ci, `repetition` INT(11) NULL DEFAULT NULL COMMENT 'kb:rompt重复播放次数 ,mismatch:连续未匹配次数 flow:已经执行次数', `potential` VARCHAR(50) NULL DEFAULT NULL COMMENT '意向ID' COLLATE 'utf8_unicode_ci', `record` VARCHAR(260) NULL DEFAULT NULL COMMENT '录音' COLLATE 'utf8_unicode_ci' ) COLLATE='utf8_unicode_ci' ENGINE=InnoDB ;
|
createtime 记录生成事件
callid 通话ID
current_appid 当前执行APPID
sequence 序列号,当前执行动作的次数
current_flowid 当前流程ID
input_type 输入类型0:TEXT 1:DTMF 2:COMPLETE 10:CREATE 11:DESTORY 20:FLOWID 30:ERROR 40:NOTIFY
- TEXT asr转换后的文字
- DTMF 按键
- COMPLETE 动作执行完成
- CREATE 进入流程创建上下文(input_args是话术名字:version[话术文件.json可以设置一个version字段设置话术版本])
- DESTORY 离开流程销毁上下文
- FLOWID 流程ID,比如通过知识库或者return动作切换流程(input_args:如果空就是返回父流程,否则就是流程ID)
- ERROR 错误信息,比如切断流程失败(input_args:发生错误的流程ID,matching_condition:错误的流程ID,response_description:错误信息)
- NOTIFY 触发通知
input_args 输入参数,input_type TEXT时asr识别结果,DTMF时按键内容,COMPLETE是完成输入参数,DESTORY是结束原因,FLOWID是切换流程参数,NOTIFY是通知参数
asr识别结果前缀说明
- 前缀F:一句话识别完成
- 前缀E:ASR错误
- 前缀S:用户还在说话,实时识别中。
- 前缀P:放音时的识别结果(打断模式128和256时放音时候说话才触发)
dtmf按键内容
完成输入参数
DONE() 输入完成,DONE(F:识别内容1F:识别内容2)
TIMEOUT() 输入超时了,TIMEOUT(F:放音时候的识别内容S:超过最大说话时间了)。如果没检测到声音就是TIMEOUT()。TIMEOUT(S:识别内容)这样的也代表一次ASR调用,也要对ASR进行计费。
- ERROR() 遇到错误
- BREAK() 外部程序执行了uuid_break
- HANGUP() 挂机了,如果用户说完就挂机了,识别结果会HANGUP(F说话内容)推送。
结束原因
- send_bye 系统挂机
- recv_bye 对方挂机
- hangup 未知方挂机
- transfer 转接
- limit 授权限制
- manual() 转人工
切换流程
- 空或者return 切换到上一个流程
- top 切换到主流程
- 切换到指定返回流程ID
通知参数
{ "trigger_type": "calculate", "trigger_time":10, "url":"" "linegroup": "121", "stop_robot": false, "beep_time": 0, "rest_time": 0 }
|
- trigger_type 触发通知类型
- calculate 根据意向配置计算触发
- kb 知识库配置触发
- flow 节点配置触发
- trigger_time 机器人对话多久后触发
- url 通知到URL时是http地址
- linegroup 通知到坐席组时是坐席组名
- stop_robot true对话模式,false监听模式
- beep_time 坐席beep时间
- rest_time 坐席话后休息时间
input_nlp_args nlp 接口返回的数据
input_start_time 输入开始时间,比如说话开始时的时间
input_duration 输入持续时间 ,比如说话的持续时间
input_play_time 输入时的放音时间,
正数 说明抢话了,input_play_time -input_duration 就是放音多少秒的时候用户开始说话的。
负数 就是放音完成之后多少秒,用户才开始说法的。
matching_method 匹配方法0:mismatch 1:boot 2:regex 3:full 4:any 5:flowid
- mismatch 未匹配到条件
- boot 创建流程时从start进入第一个引导结点(开场白)
- regex 正则表达式匹配
- full 完整的关键词匹配
- any 任意匹配(就是关键词设置为any)
- flowid 匹配到流程ID
matching_condition 匹配表达式 ,就是被匹配成功的关键词,或者正则表达式
condition_id 匹配条件ID ,话术版本2加入
condition_weight 匹配条件权重,话术版本3加入
matching_keyword 匹配关键词,就是text中被匹配中的部分
response_type 响应类型 0:none 1:flow 2:kb 3:mismatch 4:switchflow 5:timeout 6:globalflow 7:brotherflow 8:noiserule 9:disablebreak
- none 没反应动作
- flow 匹配到子流程
- kb 匹配到知识库
- mismatch 执行未匹配放音
- switchflow 切换流程节点
- timeout 执行无输入放音
- globalflow 匹配到全局流程
- brotherflow 匹配到源流程的子流程
- noiserule 匹配到噪音规则
- disablebreak 匹配到禁止打断。
response_id 响应的FlowID,或者PromptID
response_action 响应动作,执行那个FS的APP
response_args 响应参数,APP的参数
response_text 响应文本,话术中添加一个 playbacks_text:[“放音描述”],重复放音replaybacks_text:[“重复放音内容”]其他类似,就可以记录到每次放音的文本内容。
repetition kb:prompt重复播放次数 ,timeout和mismatch:连续未匹配次数 flow:已经执行次数
potential 意向信息
record 当前输入的录音文件,text输入的时候才有,一个动作(一次放音)的多次说话会记录到一个录音文件。
例子
执行流程
{ "createtime": "2024-10-17 16:39:48", "callid": "dfd3585d-1209-4c69-bb5f-777a48a66321", "current_appid": "", "sequence": 0, "current_flowid": "Start", "input_type": 10, "input_args": "debug/905ee60c2703a80d318ed17b7eeee75d", "input_nlp_args": "", "input_start_time": "2024-10-17 16:39:48", "input_duration": 0, "matching_method": 1, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "", "response_type": 1, //1表示执行流程 "response_description": "是否有贷款意向", //流程名称 "response_id": "F1", "response_action": "cti_play_and_detect_speech", //放音 "response_text": "你好,这里是信贷中心,请问你最近是否有资金上的需求?", //放音内容 "repetition": 0, "potential": "", //流程意向 1:有意向 -1:无意向 A-F:意向标签 "record": "", }
|
用户回答
{ "createtime": "2024-10-17 16:44:49", "callid": "65b53f05-a2c8-4fb4-a141-a7eccdad516e", "current_appid": "28515905-47c1-41d7-a7bc-1aa8395694fc", "sequence": 2, "current_flowid": "F1", "input_type": 0, //0表示本次为ASR识别结果通知 "input_args": "F有的。", //ASR识别结果内容,前缀F表示一句话, 显示的时候去除前缀,去除的方法去除第一个字符,如果第一个字符是P,则去前2个字符。 "input_nlp_args": "", "input_start_time": "2024-10-17 16:44:48", //说话开始时间 "input_duration": 1439, //说话持续多少毫秒 "matching_method": 3, //匹配方法 2:正则 3:字符串匹配 4:兜底 "matching_condition": "", "condition_id": "test1", "condition_weight": 1, //匹配到的关键词的权重 1:积极回答 -1:消极回答 0:中性 "matching_keyword": "有", //匹配到的关键词 "response_type": 1, //1 表示匹配到了子流程 "response_description": "需要多少资金", "response_id": "F4", "response_action": "cti_play_and_detect_speech", "response_text": "请问你需要多少资金呢?", "repetition": 1, "potential": "1", }
|
触发知识库
{ "createtime": "2024-10-17 17:03:15", "callid": "acb3fb63-66e7-4e1f-8c9d-89ebfa33d710", "current_appid": "7c2cbf39-15ad-45aa-9c8f-90ad43fcee8a", "sequence": 1, "current_flowid": "F1", "input_type": 0, "input_args": "F公司。", "input_nlp_args": "", "input_start_time": "2024-10-17 17:03:13", "input_duration": 1581, "matching_method": 3, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "公司", "response_type": 2, //2 表示 匹配到了知识库 "response_description": "公司介绍", //知识库节点名字 "response_id": "P1", "response_action": "cti_play_and_detect_speech", "response_text": "我们是正规贷款公司,专业提供金融服务的。", //知识库放音内容 "repetition": 1, "potential": "7", //知识库意向 1:有意向 -1:无意向 A-F:意向标签 }
|
切换流程
{ "createtime": "2024-10-17 17:08:14", "callid": "116ac20b-f3af-485a-bf95-8b3dd01f944a", "current_appid": "957c5e70-0153-4e1d-9eae-4ae808bcd016", "sequence": 1, "current_flowid": "F1", "input_type": 0, "input_args": "F听不清。", "input_nlp_args": "", "input_start_time": "2024-10-17 17:08:12", "input_duration": 2220, "matching_method": 3, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "听不清", "response_type": 6, //6表示匹配到了全局流程 "response_description": "返回流程重复执行", "response_id": "F33", "response_action": "return", //表示执行返回动作 "response_args": "", //返回到哪里 top 主流程 空或者return 上一个流程 其他值指定流程 "response_text": "好的,我重新说一下了。", "repetition": 1, "potential": "", }
|
{ "createtime": "2024-10-17 17:47:07", "callid": "767cbfdf-48d8-4544-a05b-b67e7980a0d7", "current_appid": "4aad1709-641d-4b5c-a746-c4c8eadb2686", "sequence": 2, "current_flowid": "F33", "input_type": 20, "input_args": "", "input_nlp_args": "", "input_start_time": "2024-10-17 17:47:07", "input_duration": 0, "matching_method": 5, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "", "response_type": 4, "response_description": "是否有贷款意向", "response_id": "F1", "response_action": "cti_play_and_detect_speech", "response_text": "好的,我重新说一下了。 请问你最近是否有资金上的需求吗?", "repetition": 2, "potential": "", }
|
挂机
{ "createtime": "2024-10-17 17:14:48", "callid": "3b5d2384-aa4b-4165-a8e6-b36626f5090c", "current_appid": "1b805dbd-44ae-4e5e-9ad8-677d98df67c7", "sequence": 2, "current_flowid": "F2", "input_type": 2, // "input_args": "DONE()", //动作执行完成 "input_nlp_args": "", "input_start_time": "2024-10-17 17:14:48", "input_duration": 0, "matching_method": 4, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "", "response_type": 1, "response_description": "", "response_id": "F3", "response_action": "hangup", // 执行挂机 "response_args": "", "response_text": "", "repetition": 1, "potential": "", "record": "", }
|
对话结束
{ "createtime": "2024-10-17 17:14:48", "callid": "3b5d2384-aa4b-4165-a8e6-b36626f5090c", "current_appid": "d5f16661-fca7-4e3a-baf8-30dacd2eca60", "sequence": 3, "current_flowid": "F3", "input_type": 11, //11表示 对话结束 "input_args": "send_bye", //表示挂机方 前缀send 系统挂机,前缀recv,手机挂机 "input_nlp_args": "", "input_start_time": "2024-10-17 17:14:48", "input_duration": 0, "matching_method": 0, "matching_condition": "", "condition_id": "", "condition_weight": 0, "matching_keyword": "", "response_type": 0, "response_description": "", "response_id": "", "response_action": "", "response_args": "", "response_text": "", "repetition": 0, "potential": "b", "record": "", }
|
- input_args 结束原因
- send_bye 系统挂机
- recv_bye 对方挂机
- hangup 未知方挂机
- transfer 转接
- limit 授权限制
- manual 转人工
根据CDR配置,流程执行步骤可以记录到数据库或者redis
如果配置为记录到数据库,input_type 等于DESTORY是 即流程执行结束,可以通知到http接口或者redis的list或者channel。
{ "robot": { /*机器人对话的执行流程记录*/ "record": { 通知包含的通道变量 "notify_fields": [ "caller_id_name", "destination_number", "call_source", "source_name", "cti_dial_number" ], /*机器人交换记录是否推送到redis的channel和list*/ "redis": { "channel": "", "list": "", }, "database": { /*机器人的交换记录插入数据库的那个表*/ "table": "conversation", }, "log": false //是否输出到redis的JSON和输出SQL。 }, /*机器人对话交互的统计数据*/ "statistic": { /*是否推送到redis的channel和list*/ "redis": { "channel": "", "list": "" }, "database": { /*插入数据库的那个表*/ "table":"classify" }, "log": false //是否输出到redis的JSON和SQL到日志。 }, "nlp": { "debug": false //是否输出机器人引擎调试日志,比如要输出正则表达式匹配过程,可以设置为true }, "httpflow": { "usecurl": false, //默认使用顶顶通实现的http库,修改成true,使用curl库执行http请求 "retries": 2, //http请求失败时重试次数 "connecttimeout": 3000, //连接超时 "responsetimeout": 10000 //等待响应超时 }, "event_after_hangup":true // 挂断之后是否继续处理事件,如果不开启 用户说话之后没等ASR识别完成就挂机,会丢失识别结果,开启后会有complete事件参数HANGUP(F说话内容)。 } }
|
机器人对话交互的统计数据
用于意向分析和比如客户分类
CREATE TABLE `classify` ( `callid` VARCHAR(50) NOT NULL, `talk_time` INT(11) NULL DEFAULT NULL, `respond_count` INT(11) NULL DEFAULT NULL, `positive_respond_count` INT(11) NULL DEFAULT NULL, `passive_respond_count` INT(11) NULL DEFAULT NULL, `intentional_count` INT(11) NULL DEFAULT NULL, `unintentional_count` INT(11) NULL DEFAULT NULL, `trigger_kb` INT(11) NULL DEFAULT NULL, `trigger_global_flow` INT(11) NULL DEFAULT NULL, `proactively_hangup` INT(11) NULL DEFAULT NULL, `label_result` VARCHAR(50) NULL DEFAULT NULL, `label_hit_id` VARCHAR(50) NULL DEFAULT NULL, `label_hit_type` INT(11) NULL DEFAULT NULL, PRIMARY KEY (`callid`) )
|
- talk_time 通话时长
- respond_count 回答次数
- positive_respond_count 积极回答(对所以命中关键词权重大于0的进行求和)。举例:比如肯定关键词权重都设置1,那么积极回答的值就是肯定回答了多少次。
- passive_respond_count 消极回答(对所有命中关键词权重小于0的进行求和然后取绝对值)。举例:比如否定关键词权重都设置-1,那么消极回答的值就是否定回答了多少次。
- intentional_count 有意向节点(对所有执行节点意向大于0的进行求和)。举例:比如有意向的节点意向都设置1,那么这个值就是执行了多少个有意向的节点。
- unintentional_count 无意向节点(对所有执行节点意向小于0的进行求和然后取绝对值)。举例:比如无意向的节点意向都设置-1,那么这个值就是执行了多少个无意向的节点。
- trigger_kb 触发知识库次数
- trigger_global_flow 触发全局流程次数
- proactively_hangup 机器人主动挂断设置为1,否则设置为0
- label_result 分类结果
- label_hit_type 分类结果的类型
- 流程直接设置的分类(label_hit_id为设置分类的的流程ID)
- 知识库直接设置的分类(label_hit_id为设置分类的知识库ID)
- 根据配置规则分类(label_hit_id为命中的分配配置规则ID)
NLP接口
全局配置设置了NLP接口地址,并且节点配置了FLOWID,那么会调用NLP接口进行处理。
NLP接口原理,话术引擎把输入的数据和需要匹配的关键词发送给NLP接口,由NLP接口返回匹配命中的关键词。
请求参数
{ "flowid": "F1", "nlpid": "1", "callid": "58b0733b-8a80-4fdc-860b-ad7e5bb85fbe", "flowkeywords": "o%7Chello%7Cok%7Cyes%7Cno%7Cwo%7Cxuhuaiyi", "kbkeywords": "lixi%7Cgongs%7Cnali%7Chello%7Cok%7Cyes%7Cno", "input": "text", "text": "SHello%20hello" }
|
flowkeywords 所有子流程的所有关键词
kbkeywords 关联知识库的所有关键词
input 输入类型
text 输入参数
NLP接口返回数据
{ "keyword":"输入结果匹配到的关键词", "description":“描述” }
|
话术编辑
请看这个页面 http://www.ddrj.com/smartivr/robot.html ,用户可以设计自己的话术编辑界面,只需要按照话术脚本格式生成JSON文件就可以。
2个不同的匹配条件进入同一个流程的实现方法
可以在流程名字名字前面加上冒号区分不同条件进入同一个流程。注意:需要json添加一个version:2。
{ "version":2, "flow": { "F1": { "action":"cti_play_and_detect_speech", "subflow": { "肯定:F3": { "id":"匹配条件ID", "condition": { "text": [ "是" ], } }, "默认:F3": { "id":"匹配条件ID", "condition": { "complete": [ "any" ], } } } } }
|
话术脚本
{ "flow": { /*节点ID*/ "F1": { /*节点执行的动作*/ "action": "cti_play_and_detect_speech", /*动作参数*/ "argument": "'1' '' '' '0' '' '' '' '' '' '' ''", /*节点位置信息*/ "position": { "x": 2499, "y": 156 }, /*nlp ID*/ "nlpid": "", /*节点描述*/ "description": "描述", /*节点放音文件列表*/ "playbacks": [ "测试声音" ], /*子节点信息*/ "subflow": { /*子节点ID*/ "F3": { /*进入字节点的条件*/ "condition": { "matching_id":"匹配条件ID", /*ASR识别到关键词*/ "text": [ "any" ], /*动作执行完成*/ "complete": [ "any" ], /*DTMF输入按键*/ "dtmf": [ "any" ] } } }, /*节点重复执行是放音,用来替换playbacks配置*/ "replaybacks": [], "filter": { "text": "S", "dtmf": "none" }, /*知识库返回时放音*/ "kbplaybacks": [ "测试声音" ], /*未匹配到关键词时放音*/ "mismatchplaybacks": [ "不好意思,我没听清!" ], /*未匹配到关键词放音次数*/ "mismatchrepetition": "2", /*关联的知识库ID*/ "kb": "C1", /*节点最大重复进入次数*/ "repetition": "", /*节点的意向信息*/ "potential": "" } } }
|
知识库
{ "kb": { /*分类ID*/ "C1": { /*分类名字*/ "name": "常见问题回答", /*分类下面的条目*/ "prompts": [ "P1" ], "description": "" } }, "prompt": { /*条目ID*/ "P1": { /*条目名字*/ "name": "公司介绍", "ref": 2, /*最大重复执行次数*/ "repetition": "2", /*进入知识库的关键词*/ "keyworks": [ "谁", "哪里", "公司" ], /*进入后的放音文件*/ "playbacks": [ "放音测试" ], /*意向等级*/ "potential": "7", /*切换到流程 可以配置流程ID,或者当前流程的匹配关键词,"text:"前缀匹配子流程的文本输入,"DTMF:"前缀匹配子流程的DTMF输入,"complete:"前缀匹配子流程的完成输入*/ "switchflow":"", "description": "" } } }
|
同义词
{ "synonym": { /*分类*/ "肯定词": [/*同义词列表*/ "是", "好", "要", "没错", "有", "对" ], "否定词": [ "不", "没" ] } }
|
全局配置
/*配置tts和asr默认配置*/ "global": { "voicelist": [], "defaultvoice": "", "voicedir": "", "ttsurl": "http:\/\/180.76.224.191:9989\/tts", "ttsengine": "", "ttsconfig": "", "ttsvolume": 0, "ttsspeechrate": 0, "ttspitchrate": 0, "interrupt": "2", "asrproxy_addr": "180.76.224.191:9988", "vad_min_active_time_ms": "150", "vad_max_end_silence_time_ms": "800", "wait_speech_timeout_ms": "5000", "max_speech_time_ms": "20000", "hot_word": "", "asr_params": "{\"group\":\"default\"}", "nlpurl": "", "vad": "0", "vad_mode": "0", "vad_filter": "0.3" },
|
tts接口
等待完成
话术流程存入redis
fs启动的时候会自动同步cti_robot_flow和cti_robot_flow@domain 2个哈希表里的话术流程,到fs话术目录,然后自动加载。
cti_robot_flow和cti_robot_flow@domain的区别,cti_robot_flow@domain指定的domain的fs才加载,cti_robot_flow连接这个redis的所有fs都会加载,用于群集模式。
cti_robot_flow改变通知
cti_robot_flow改变PUBLISH 通知到config@all [通道] ,cti_robot_flow@domain改变PUBLISH 通知到config@domain[通道],先修改hash表内容,然后推送通知,fs收到通知会自动同步话术脚本到本地,然后加载。
{ "type":"config_change", "table":"cti_robot_flow", "key":"t1" }
|