# 技能后处理简介

为了扩展自定义技能的能力,技能工作室提供了技能后处理帮助开发者实现丰富的自定义功能,【技能后处理】位于【语义理解引擎】之后,可以直接与万维网通信。

# 业务逻辑

# 能力

  1. 实现多轮对话。
  2. 获取语义结果后,直接与万维网通信,缩短链路时间。
  3. 无需开发者拥有服务器,即可完成业务逻辑处理。

每次客户请求事件会触发技能后处理,引擎将每次的语义理解结果(request:JSON)发送给技能后处理,开发者加工完数据,返回一个处理结果(response:JSON),引擎通过解析 response 来决定最终下发到客户端的数据。

# 调用方式

讯飞技能工作室的技能后处理可以通过云函数和webhook来进行调用。

# 云函数

云函数是讯飞技能工作室提供的在线代码编辑器,开发者可以通过云函数提供的内置函数存储多轮对话,开发者可以在技能云函数中调用信源,处理业务逻辑,填写技能的回复 answer,通过 HTTP 请求通信。

云函数的本质是 FaaS (Function as a Service)服务,运行在讯飞云服务器上。

支持在线编辑,也可上传JS文件。

# 运行环境

目前支持的运行环境为 NodeJS,云端提供 NodeJS 环境为v9.10.1。除 nodejs 携带的标准模块(http crypto https url dgram net stream string_decoder timers buffer)外,还提供了以下第三方模块供开发者使用:

promise asap async bson caseless concat-stream

data-format double-ended-queue fibers http-basic

http-response-object inherits ioredis isarray

json5 minimist ms node-zookeeper-client qs

readable-stream resolve-from safe-buffer semver

streamroller string_decoder request-promise

then-request typedarray util-deprecate

除此之外,云函数为开发者提供了一个全局变量 AIUI,以及用于打印日志的 console。点击查看更多云函数接口:v2.0v2.1

# 示例

我们在函数中通过 dialogState判断填槽对话的状态是否完成,当填槽对话未完成时,开发者不做任何操作,交由系统自动处理,当填槽对话完成时,开发者拼接了一句 answer 回复给开发者。

示例代码如下:

AIUI.create("v2",  function(aiui,  err){
  //打印 request 结构体
  requestObject = aiui.getRequest().getObject();
  console.log(requestObject);
  //获取 response 对象
  var response = aiui.getResponse();
  // 获取填槽对话状态
  dialogState= requestObject.request.dialogState;
  
  if(dialogState!=null&&dialogState!="COMPLETED"){
  // 填槽对话未完成时,托管给系统管理
    response.addDelegateDirective();
  }else{
    // 填槽对话完成时,回复用户一句 answer
    updatedIntent = aiui.getUpdatedIntent();
    companyValue = updatedIntent.getSlotValue("company");
    numberValue = updatedIntent.getSlotValue("number");
    answer="你的"+companyValue+"快递,快递单号是是:"+numberValue+",已经达到合肥市"
    esponse.setOutputSpeech(answer);
  }
  // 提交
  aiui.commit();
})

TIP

如果您不会编写代码,但是想为您的技能增加回复,只需要把以下代码复制进入代码编辑框,修改第12行之后,保存并构建即可。

 AIUI.create("v2",  function(aiui,  err){
    requestObject = aiui.getRequest().getObject();
    var response = aiui.getResponse();
    // 获取当前意图名
    intentName = requestObject.request.intents[0].name;
    console.log("本次意图来自:"+intentName);
    // 获取填槽对话状态
    dialogState= requestObject.request.dialogState;
    if(dialogState!=null&&dialogState!="COMPLETED"){
        response.addDelegateDirective();
    }else{
        response.setOutputSpeech("这里修改成您想要的回复");
    }
    aiui.commit();
 })

TIP

如果您想根据 intent 回复不同的 answer,可以使用以下代码。

 AIUI.create("v2",  function(aiui,  err){
    requestObject = aiui.getRequest().getObject();
    var response = aiui.getResponse();
    // 获取当前意图名
    intentName = requestObject.request.intents[0].name;
    console.log("本次意图来自:"+intentName);
    // 获取填槽对话状态
    dialogState= requestObject.request.dialogState;
    if(dialogState!=null&&dialogState!="COMPLETED"){
        response.addDelegateDirective();
    }else if(intentName==="这里填写intent A 的名称"){
        response.setOutputSpeech("这里是是 intent A的回复");
    }else if(intentName==="这里填写intent B 的名称"){
        response.setOutputSpeech("这里是是 intent B的回复");
    }else if(intentName==="这里填写intent C 的名称"){
        response.setOutputSpeech("这里是是 intent C的回复");
    }else{
        response.setOutputSpeech("这里是一个默认回复");
    };
    aiui.commit();
 })


# 安全

云端对于技能运行环境都进行了资源隔离以及运行时监测,危险的代码并不会影响云函数服务器的正常运行,但系统检测到云端代码运行异常时,云端将下线该技能并判断技能开发者是否有违规行为。

凡 NodeJS 标准不建议的代码请勿编写,如:阻止事件循环。NodeJS 为单线程环境运行,如果存在死循环、无限递归等无限占用 cpu 的情况,技能将不能接收用户消息,云端检测到后也会对技能进行下线处理,云端默认每次请求交互800毫秒超时,开发者技能应该在该超时时间内调用 api 的 response 接口,否则云端代替返回超时错误,此类情况可能出现在:

  • 上述事件循环阻塞。
  • 开发者在异步操作(如 http 调用)回调中调用返回接口,该异步操作可能返回时间较长,此类情况应该对该异步操作设置超时,不要让云端触发超时。

注意

event(Deprecated)、response(Deprecated)、context(Deprecated)、eventName(Deprecated)为四个过时的全局变量点击阅读接口参数 (opens new window)。建议尽快迁移到最新的接口,以使用填槽对话等新特性。

# Webhook

Webhook的本质是一个web调用,若通过公网部署,会对技能的使用产生一些额外的耗时。

当技能使用Webhook时,在Webhook部署时需要完成以下操作。

  • 在技能平台上填写部署地址,即技能部署在服务器上的地址,这里请填写URL地址。
  • 技能需要验证发送的请求,验证步骤请参考技能请求校验

注意

Webhook只支持v2.1协议