# 填槽对话

# 多轮对话

在语音技能中,绝大多数的表述都是一句话完成的,但是在某些特殊场景或技能中,存在多轮对话的使用,从概念说,多轮对话分为两种,分别是意图内多轮对话、意图间多轮对话。

# 意图内多轮对话

示例

  • 我要订闹钟
  • 您要订几点的闹钟
  • 明早六点
  • 已为您设置了明天上午六点的闹钟

在以上示例中,虽然进行了两轮对话,但是仅为了满足用户的一个意图,即「定闹钟」,这类多轮对话的特点是计算机需要知道一些必要信息完成业务逻辑处理,但是用户一次的表述不包含完整的信息,后续的对话是引导用户补充必要的槽位,为此技能工作室提出了填槽对话的概念,开发者可以通过平台可视化的配置完成填槽对话。

# 意图间多轮对话

示例

  • 帮我预约一间家庭房
  • 好的,已经预约成功。为您推荐特惠自助早餐39元/人,请问您需要吗?
  • 来三份吧
  • 好的,已为您同时预订了三份早餐,提前祝您用餐愉快。

上述的示例,包含了两个意图,第一个意图是「定房间」,第二个意图是「定早餐」,目前实现意图间的多轮对话,需要开发者在技能云函数中,通过代码判断业务逻辑来实现,具体实现方式,请参考技能云函数章节。

# 基本概念

填槽对话包含三个重要概念

  1. 必要的槽值和追问语句

    例如在房贷计算器中,拥有三个槽值,分别是贷款金额(loanMoney)、贷款年限(loanYear)、贷款利率(loanRate)。其中,贷款金额(loanMoney)和贷款年限(loanYear)为必须的信息,贷款利率(loanRate)可以采用银行默认基准利率,用户可以指定利率,但非必须信息。

  2. 槽位确认

    你可以选择将所需槽位指定为需要确认,例如在打车技能中,当用户指定目的地为“客运西站”时,你可以要求用户对槽信息进行确认,“你确认是客运西站吗”。使用槽位确认意味着用户在继续使用前必须响应系统的反问,请谨慎使用槽位确认,避免给用户带来繁琐的交互体验。

  3. 意图确认

    你可以对整个意图进行确认,例如在购物技能中,当用户选购完商品后,你可以要求对意图进行确认,“你购买了一副黑色墨镜,确认下单吗”。与槽位确认的注意点相同,使用意图确认意味着用户在继续使用前必须响应系统的反问,请谨慎使用。

# 图示

如下图所示,当填槽对话开始后,用户的每次请求,系统都会进入这个流程图。

  • 如果技能开发者使用 Delegate(托管)或者关闭云函数,系统会依次遍历每一个环节(每次请求都是从第一个环节开始遍历)。当系统发现该环节被开发者在平台上标记为必选或者开启,且该环节的值为 nul 或者 none,就会触发该环节,否则会跳过该环节直至流程结束。
  • 如果开发者调用了ElicitSlotDirective(槽追问)、ConfirmSlotDirective(槽确认)、ConfirmIntentDirective(意图确认),则以开发者指定的环节为准。

# 示例

下面以一个"订票"的技能举例,帮助开发者更好的理解这三个概念,在买飞机票(buyPlaneTicket)意图下,拥有三个语义槽,分别是fromCity(出发城市)、toCity(到达城市)、time(出发时间),其中 fromCity 通过 GPS 信息获取,toCity和time为用户必须回答的槽位。

示例对话如下:

槽追问

  • 用户:买一张周三的飞机票
  • 系统:你想到哪个城市?
{

  "name": "buyPlaneTicket",
  "confirmationStatus": "NONE"
  "slots": [
    {
      "name": "fromCity",
      "value": "",//开发者通过获取 GPS 信息,通过代码填写为合肥
      "confirmationStatus": "NONE"
    },
    {
      "name": "toCity",
      "value": "",
      "confirmationStatus": "NONE"
    },
    {
      "name": "time",
      "value": "周三",★★★
      "confirmationStatus": "NONE"
    }
  ],

}

槽确认

  • 用户:我想去北京
  • 系统:你确认目的地是北京吗 ( 槽确认 )
{
  "name": "buyPlaneTicket",
  "slots": [
    {
      "name": "fromCity",
      "value": "合肥",
      "confirmationStatus": "NONE"
    },
    {
      "name": "toCity",
      "value": "北京",★★★
      "confirmationStatus": "NONE"
    },
    {
      "name": "time",
      "value": "周三",
      "confirmationStatus": "NONE"
    }
  ],
  "confirmationStatus": "NONE"
}

意图确认

  • 用户:确认
  • 系统:好的,周三从合肥去北京的机票确认下单吗 ( 意图确认 )
{
  "name": "buyPlaneTicket",
  "slots": [
    {
      "name": "fromCity",
      "value": "合肥",
      "confirmationStatus": "NONE"
    },
    {
      "name": "toCity",
      "value": "北京",
      "confirmationStatus": "CONFIRMED"
    },
    {
      "name": "time",
      "value": "周三",
      "confirmationStatus": "NONE"
    }
  ],
  "confirmationStatus": "NONE"
}

填槽对话结束

  • 用户:确认下单
  • 系统:好的,已下单 (填槽对话结束)
{

  "name": "buyPlaneTicket",
  "slots": [
    {
      "name": "fromCity",
      "value": "",
      "confirmationStatus": "NONE"
    },
    {
      "name": "toCity",
      "value": "北京",
      "confirmationStatus": "CONFIRMED"
    },
    {
      "name": "time",
      "value": "周三",
      "confirmationStatus": "NONE"
    }
  ],
  "confirmationStatus": "CONFIRMED"
}

# 系统配置与云函数的相互配合

用快递查询技能举例,拥有两个槽位,分别是 express_number 和 express_company。假如我们现在拥有一个快递查询 API,99%的快递单号,可以自动判断属于哪一家快递公司,1%的快递单号需要用户人工选择。

此时在技能开放平台中,我们应当如下图,把 express_number 和 express_company 勾选为必选槽

实际使用中云函数中的伪代码如下:


if(express_number.value==null){ 
    if(express_company.value==null){
        //如果用户没有标明快递公司,则使用自动识别
        express_company.value="自动识别"
    }
	//如果快递单号为空,因为在平台上配置了必选槽,可以直接托管给系统
	//此时使用ElicitSlotDirective效果相同
	DelegateDirective()
	return
}

// 调用 API 获取快递信息
express_result = express_api(express_number.value)

if(express_result=='无法自动判断快递公司'){
	// 如果无法自动判断快递公司,使用ElicitSlot追问用户
	ElicitSlotDirective(express_company,'请问你的快递公司是什么')
	
}else{
	// 可以自动判断快递公司,直接播报查询结果给用户
	speak(express_result)
}

# 注意事项

填槽对话只是为了准确理解用户需求的一个必要技术手段,但我们不鼓励开发者设计过多的多轮对话。

以一个录取分数线查询技能为例。

反例

  • 用户:清华大学的录取分数线是多少
  • 系统:请问你想查询的省份是哪一个?
  • 用户:安徽
  • 系统:请问你是文科还是理科?
  • 用户:理科
  • 系统:请问你想查询哪一年的分数?
  • 用户:2017年
  • 系统:请问你想查询的是提前批还是本科一批?
  • 用户:本科一批
  • 系统:2017年清华大学在安徽的本科一批理科投档线是670分

正例

  • 用户:清华大学的录取分数线是多少
  • 系统:清华大学2017年在安徽的本科一批投档线是理科670分、文科648分。你还可以问我往年和提前批的分数线。

技能开发者应当通过 GPS 信息获取地理位置,默认返回最近一年的分数,多数情况下用户想要知道的是本科一批的信息,文科理科分数线可以同时返回,在返回了关键信息后,提醒用户可以通过进一步的对话,获取更多信息。