구현 도움말 (Dialogflow)

적절한 대화 설계 권장사항을 구현하기 위한 다음 도움말을 검토하세요. 드래그 앤 드롭합니다.

변동 예상

'사용자의 말'에서 처리합니다. Dialogflow의 입력 또한 2개 이상의 동일한 작업에 매핑될 수 있는 인텐트의 예입니다. 여기서 각 인텐트는 다양한 '사용자 의견' 집합 있습니다.

유용한 재요청 및 단계적 실패

입력을 받지 못해 작업을 진행할 수 없는 경우가 있습니다. (입력 없음) 또는 사용자의 입력을 이해하지 못함 (일치하지 않음) 이 경우 어시스턴트는 먼저 사용자가 원하는지 판단하려고 시도합니다. 다른 작업을 트리거합니다. 어시스턴트가 사용자 입력과 일치하지 않는 경우 사용자가 개발자의 작업의 컨텍스트 내에서 작업을 계속합니다. 이 시나리오는 언제든지 발생할 수 있으므로, 가장 좋은 방법은 입력 없는 상황과 일치하지 않는 상황을 대체를 포함하는 대화에서 만듭니다. 대체를 사용하면 사용자가 서비스를 다시 정상적으로 이용할 수 있도록 도울 수 있습니다.

이렇게 하려면 conv.data 객체에서 fallbackCount 변수를 초기화합니다. 0으로 설정합니다. 대체 프롬프트 2개의 배열을 준비합니다 (명확하게 에스컬레이션). 대화를 마무리하는 마지막 대체 프롬프트가 있습니다.

그런 다음 대체 인텐트를 만듭니다. 있습니다. 인텐트 핸들러의 conv.data에서 대체 수를 가져옵니다. 객체를 증분하고 3보다 작으면 배열에서 프롬프트를 가져옵니다. /3입니다. 개수가 4개 이상인 경우 마지막 메시지가 표시됩니다. 대체가 아닌 모든 인텐트에서 대체 횟수를 0으로 재설정합니다. 특정 인텐트에 맞게 대체를 템플릿화하는 것이 이상적입니다.

Node.js

const GENERAL_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t quite get that. I can help you find good local restaurants, what do you want to know about?',
];

const LIST_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t catch that. Could you tell me which one you prefer?',
];

const FINAL_FALLBACK = 'I\'m sorry I\'m having trouble here. Let\'s talk again later.';

const handleFallback = (conv, promptFetch, callback) => {
 conv.data.fallbackCount = parseInt(conv.data.fallbackCount, 10);
 conv.data.fallbackCount++;
 if (conv.data.fallbackCount > 2) {
   conv.close(promptFetch.getFinalFallbackPrompt());
 } else {
   callback();
 }
}
// Intent handlers below
const generalFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
    conv.ask(GENERAL_FALLBACK[conv.data.fallbackCount],
      getGeneralNoInputPrompts());
 });
}

const listFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
   conv.ask(LIST_FALLBACK[conv.data.fallbackCount],
       getGeneralNoInputPrompts());
 });
}

const nonFallback = (conv) => {
  conv.data.fallbackCount = 0;
  conv.ask('A non-fallback message here');
}

자바

private static final List<String> GENERAL_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t quite get that. I can tell you all about IO, like date or location, or about the sessions. What do you want to know about?");
private static final List<String> LIST_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t catch that. Could you tell me which one you liked?");
private static final List<String> FINAL_FALLBACK =
    Arrays.asList("I\'m sorry I\'m having trouble here. Maybe we should try this again later.");

@ForIntent("General Fallback")
public ActionResponse generalFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(GENERAL_FALLBACK));
  }
  return responseBuilder.build();
}

private String getRandomPromptFromList(List<String> prompts) {
  Random rand = new Random();
  int i = rand.nextInt(prompts.size());
  return prompts.get(i);
}

@ForIntent("List Fallback")
public ActionResponse listFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(LIST_FALLBACK));
  }
  return responseBuilder.build();
}

@ForIntent("Non Fallback")
public ActionResponse nonFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  request.getConversationData().put("fallbackCount", 0);
  responseBuilder.add("Non Fallback message");
  return responseBuilder.build();
}

언제든지 도울 준비가 되어 있음

'무엇을 할 수 있나요?'와 같은 도움말 문구를 수신 대기하는 인텐트를 만듭니다. '무엇을 말해 줄 수 있어' 또는 '도와줘'입니다. 이 인텐트에서 일부 (순환)를 제공합니다. 상담사가 할 수 있는 작업에 관한 개요를 제공하고 사용자를 상담사의 있습니다. Dialogflow에서 후속 도움말 인텐트를 사용하여 여러 가지 실행 가능한 인텐트에 대한 다양한 도움말 시나리오를 만들 수 있습니다.

Node.js

const HELP_PROMPTS = [
   'There\'s a lot you might want to know about the local restaurants, and I can tell you all about it, like where it is and what kind of food they have. What do you want to know?',
   'I\'m here to help, so let me know if you need any help figuring out where or what to eat. What do you want to know?',
];

// Intent handler
const help = (conv) => {
 reply(conv, promptFetch.getHelpPrompt(), // fetches random entry from HELP_PROMPTS
     promptFetch.getGeneralNoInputPrompts());
}

자바

private static final List<String> HELP_PROMPTS =
    Arrays.asList(
        "There's a lot you might want to know about IO, and I can tell you all about it, like where it is and what the sessions are. What do you want to know?",
        "IO can be a little overwhelming, so I\'m here to help. Let me know if you need any help figuring out the event, like when it is, or what the sessions are. What do you want to know?");

@ForIntent("Help")
public ActionResponse help(ActionRequest request) {
  return getResponseBuilder(request).add(getRandomPromptFromList(HELP_PROMPTS)).build();
}

사용자가 정보를 다시 재생하도록 허용

다음을 추가하는 프록시 함수로 모든 app.ask(output) 메서드를 래핑합니다. conv.data.lastPrompt로 출력됩니다. 수신 대기하는 반복 인텐트 만들기 '무엇을?', "다시 말해 줘" 또는 "다시 말해 봐" 반복해 주시겠습니까?" 다음에 사용할 수 있는 반복 접두사의 배열을 만듭니다. 사용자가 반복 요청을 받았음을 인정합니다. 반복 중 인텐트 핸들러에서 반복 접두사의 연결된 문자열로 ask()를 호출합니다. conv.data.lastPrompt의 값입니다. 다른 모든 장치의 SSML 시작 태그(마지막 프롬프트에서 사용된 경우)

Node.js

const REPEAT_PREFIX = [
    'Sorry, I said ',
    'Let me repeat that. ',
];

const reply = (conv, inputPrompt, noInputPrompts) => {
  conv.data.lastPrompt = inputPrompt;
  conv.data.lastNoInputPrompts = noInputPrompts;
  conv.ask(inputPrompt, noInputPrompts);
}
// Intent handlers
const normalIntent = (conv) => {
  reply(conv, 'Hey this is a question', SOME_NO_INPUT_PROMPTS);
}

const repeat = (conv) => {
  let repeatPrefix = promptFetch.getRepeatPrefix(); // randomly chooses from REPEAT_PREFIX
  // Move SSML start tags over
  if (conv.data.lastPrompt.startsWith(promptFetch.getSSMLPrefix())) {
    conv.data.lastPrompt =
        conv.data.lastPrompt.slice(promptFetch.getSSMLPrefix().length);
    repeatPrefix = promptFetch.getSSMLPrefix() + repeatPrefix;
  }
  conv.ask(repeatPrefix + conv.data.lastPrompt,
      conv.data.lastNoInputPrompts);
}

자바

private final List<String> REPEAT_PREFIX = Arrays.asList("Sorry, I said ", "Let me repeat that.");

private final String SsmlPrefix = "<speak>";

@ForIntent("Normal Intent")
public ActionResponse normalIntent(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.getConversationData().put("lastPrompt", "Hey this is a question");
  return responseBuilder.build();
}

@ForIntent("repeat")
public ActionResponse repeat(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String repeatPrefix = getRandomPromptFromList(REPEAT_PREFIX);
  // Move SSML start tags over
  String lastPrompt = (String) responseBuilder.getConversationData().get("lastPrompt");
  if (lastPrompt.startsWith(SsmlPrefix)) {
    String newLastPrompt = lastPrompt.substring(SsmlPrefix.length());
    responseBuilder.getConversationData().put("lastPrompt", newLastPrompt);
    repeatPrefix = SsmlPrefix + repeatPrefix;
  }
  responseBuilder.add(repeatPrefix + lastPrompt);
  return responseBuilder.build();
}

사용자 환경설정으로 대화 맞춤설정

작업이 사용자에게 선호도를 요청하고 기억할 수 있습니다. 향후 해당 사용자와의 대화를 맞춤설정할 수 있습니다.

이 액션 예시는 사용자에게 우편번호의 일기예보를 제공합니다. 다음 작업에서 우편번호를 기억할지 여부를 묻는 예시 코드 사용할 수 있습니다.

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  conv.data.zip = zip;
  conv.ask(getWeatherReport(zip));
  conv.ask(new Confirmation(`Should I remember ${zip} for next time?`));
});

app.intent('remember_zip', (conv, params, confirmation) => {
  if (confirmation) {
    conv.user.storage.zip = conv.data.zip;
    conv.close('Great! See you next time.');
  } else conv.close('Ok, no problem.');
});

자바

@ForIntent("weather_report")
public ActionResponse weatherReport(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  responseBuilder.getConversationData().put("zip", zip);
  responseBuilder.add(getWeatherReport(zip));
  responseBuilder.add(
      new Confirmation().setConfirmationText("Should I remember " + zip + " for next time?"));
  return responseBuilder.build();
}

@ForIntent("remember_zip")
public ActionResponse rememberZip(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUserConfirmation()) {
    responseBuilder.getUserStorage().put("zip", responseBuilder.getConversationData().get("zip"));
    responseBuilder.add("Great! See you next time.").endConversation();
  } else {
    responseBuilder.add("Ok, no problem.").endConversation();
  }
  return responseBuilder.build();
}

첫 번째 대화에서 사용자에게 어느 우편번호에 해당하는지 물어본 후 다음 호출 중에 해당 프롬프트를 건너뛰고 동일한 우편번호를 사용할 수 있습니다. 여전히 탈출 경로 (예: 제안 칩을 허용하는 경우)를 제공해야 합니다. 다른 우편번호를 선택할 수 있음) 하지만 훨씬 더 원활한 환경을 구축할 수 있습니다.

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  if (zip) {
    conv.close(getWeatherReport(zip));
  } else if (conv.user.storage.zip) {
    conv.ask(new SimpleResponse(getWeatherReport(conv.user.storage.zip)));
    conv.ask(new Suggestions('Try another zipcode'));
  } else {
    conv.ask('What\'s your zip code?');
  }
});

app.intent('provide_zip_df', (conv) => {
  conv.user.storage.zip = conv.arguments.get('zipcode');
  conv.close(getWeatherReport(conv.user.storage.zip));
});

자바

public ActionResponse weatherReport2(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  if (zip != null) {
    responseBuilder.add(getWeatherReport(zip)).endConversation();
  } else if ((zip = (String) responseBuilder.getUserStorage().get("zip")) != null) {
    responseBuilder.add(new SimpleResponse().setTextToSpeech(getWeatherReport(zip)));
    responseBuilder.add(new Suggestion().setTitle("Try another zipcode"));
  } else {
    responseBuilder.add("What's your zip code?");
  }
  return responseBuilder.build();
}

재방문 사용자를 위한 맞춤설정

대화 간에 어느 정도 상태를 유지하면 훨씬 더 자연스럽게 사용자 환경을 개선할 수 있습니다 이러한 환경을 구축하는 첫 단계는 다른 방식으로 재구매 사용자를 환영합니다. 예를 들어, 인사말을 테이퍼링하거나 이전 대화를 기반으로 유용한 정보를 표시합니다. 이렇게 하려면 AppRequest.User lastSeen 속성이 수신되면 사용자가 내 액션과 상호작용했는지 확인할 수 있습니다 lastSeen 속성이 포함된 경우 요청 페이로드에 있다면 평소와 다른 인사말을 사용할 수 있습니다.

아래 코드는 Node.js 클라이언트 라이브러리를 사용하여 last.seen

Node.js

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
const welcome = (conv) => {
  if (conv.user.last.seen) {
    conv.ask(`Hey you're back...`);
  } else {
    conv.ask('Welcome to World Cities Trivia!...');
  }
}

자바

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
public ActionResponse welcome(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUser().getLastSeen() != null) {
    responseBuilder.add("Hey you're back...");
  } else {
    responseBuilder.add("Welcome to Number Genie!...");
  }
  return responseBuilder.build();
}

응답을 실제 상황에 맞추어 이 인사말을 더욱 개선할 수 있습니다. lastSeen의 값입니다. 예를 들어 마지막 상호작용이 여러 번 발생한 사용자의 경우 현재 상호 작용하기 몇 달 전에 받은 인사말과 전날 Action을 사용했었죠.

대화 중 볼륨 제어

지원되는 기기에서 사용자는 어시스턴트를 통해 기기 볼륨을 제어할 수 있습니다. "볼륨 높여 줘"" 또는 "설정하기 50%로 설정합니다. 유사한 학습 문구를 처리하는 인텐트가 있는 경우 인텐트가 우선 적용됩니다 이러한 작업은 어시스턴트가 처리하도록 하는 것이 좋습니다. 사용자의 요청을 처리할 수 없습니다.