Как продолжить поток диалога из предыдущего вопроса - PullRequest
1 голос
/ 05 апреля 2020

У меня есть сценарий, в котором первый вопрос «Сколько человек в 2018 году» и возвращается 2. Затем я хочу продолжить разговор, спросив «Сколько там мужчин и женщин». Должно быть возвращено 1 мужчина и 1 женщина, не задавая год, исходя из предыдущего вопроса.

Как Dialogflow и мой код выполнения выводят год?

data

Я пытался подсчитать общее количество, а также подсчитать количество мужского и женского пола, но я не уверен, как продолжить разговор естественным образом.

function countresponders2018(agent){
    const year = agent.parameters.year;
    return admin.database().ref('data').once('value')
      .then((snapshot) => {
        let totalCount=0;
        snapshot.forEach( childSnapshot => {
          var value = childSnapshot.val();
          if (value.SurveyYear==year){
          totalCount+=1;  
          }
        });
            agent.add(`The total responders are ${totalCount}`);
        
    });

1 Ответ

2 голосов
/ 05 апреля 2020

Это отличный вопрос, о котором нужно подумать при разработке хороших разговоров.

Я собираюсь игнорировать запросы к базе данных, поскольку, похоже, у вас есть эта часть под контролем, и это не так. не имеет прямого отношения к разговорной части.

Решение проблемы

Чтобы перефразировать то, что вы хотите сделать, вы хотели бы обрабатывать все следующие фразы одинаково путь:

  • Сколько человек в 2018 году?
  • Сколько людей в 2019 году?
  • Сколько людей там?

Точно так же все они должны быть одинаковыми:

  • Сколько мужчин и женщин в 2018 году?
  • В 2017 году, сколько мужчин и женщин там?
  • Сколько существует мужчин и женщин?
  • Можете ли вы разделить это на мужчин и женщин?

ie - пользователи должны иметь возможность задавать вопросы, и с указанием года, и, возможно, без.

Во время разговора, если они говорят Укажите год, это значение должно быть принято для дальнейших вопросов, если они не указывают другой год. Это вполне естественно - люди создают краткий контекст в наших беседах.

У них также есть проблема, которую вы не поднимали в своем вопросе - как решить вопрос, если они еще не указали год , Хороший дизайн беседы предполагает, что вы должны задать год, а затем выполнить вопрос, который был задан изначально. Таким образом, разговор может выглядеть примерно так:

User:  How many people are there?
Agent: What year would you like that for?
User:  2018
Agent: There were 2 people in 2018

Общий подход: контексты

К счастью - Dialogflow поддерживает эту концепцию напрямую с Contexts . Это позволяет вам сохранять параметры между утверждениями пользователя, так что это может быть хорошим способом сохранить год для последующих вопросов.

Вы также можете создавать Интенты, которые могут быть вызваны только при указании c Контексты активный. Это может быть полезно, чтобы убедиться, какие намерения имеют смысл в некоторых частях беседы.

Существует два хороших подхода к использованию контекстов для подобных вопросов. Хотя у каждого есть компромиссы, то, что вы используете, во многом зависит от личного стиля. Вы также можете использовать контексты для поддержки сценария, в котором вам нужно задать год, если у нас его еще нет.

Подход 1: Одно намерение на вопрос

При такой схеме у вас будет одно намерение, которое отвечает на каждый вопрос пользователя. Ваше выполнение увидит, установлен ли параметр year, и, если это так, использует этот параметр в качестве года и задает его в параметрах Context. Если он не установлен - тогда используйте значение из параметров в контексте.

Так что в нашем намерении "askPeople" могут быть фразы, о которых мы говорили выше:

  • Сколько человек в [году]?
  • В [году] сколько людей там?
  • Сколько людей там?

И мы определяем "год" "в качестве параметра @sys.number-integer например. (Возможны и другие типы сущностей, но пока это подойдет.)

Если вы используете библиотеку исполнения диалогового потока, наша функция-обработчик для этого может выглядеть примерно так:

function askPeople( agent ){
  // Try to get the year from the context first
  let context = agent.context.get('RememberYear');
  let year = context && context.parameters && context.parameters.year;

  // If we don't have a year, get it from the phrase parameters
  year = year || agent.parameters.year;

  if( year ){
    // If we do have a value, get the result, reply,
    // and save the year in the context.
    return getPeople( year )
      .then( count => replyPeople( agent, year, count ) );

  } else {
    // We don't have a value
    // FIXME: We'll discuss what to do about this below
  }
}

Вам нужно написать функцию getPeople(), чтобы вернуть Promise, который разрешает результаты из вашей базы данных. Я также намеренно вытащил функцию replyPeople(). Это может выглядеть примерно так:

function replyPeople( agent, year, count ){
  agent.context.set({
    name: 'RememberYear',
    lifespan: 99,
    parameters:{
      year: year
    }
  });
  agent.add( `The total count for ${year} was ${count}.` );
}

Подход 2: Несколько интентов на вопрос

С этим у нас будет два разных интента, которые обрабатывают вопрос. Один принимает его с годом, а другой обрабатывает фразу без года. Большая разница в том, что для того, у кого в обучающей фразе не указан год, для запуска потребуется установить контекст «RememberYear».

Базовый Intent («askPeopleYear») является довольно знакомым с обучением. такие фразы, как

  • Сколько человек в [год]?
  • В [год], сколько людей там?

И параметр "year" определен так же, как и выше.

Наше другое намерение ("askPeopleNoYear") будет иметь установленный входной контекст "RememberYear" и иметь обучающую фразу, такую ​​как

  • Сколько там людей?

И не будет иметь никаких параметров.

Нам, вероятно, понадобится третье намерение или, по крайней мере, дополнительный способ решения с, что произойдет, если контекст «RememberYear» не установлен , но они говорят эту фразу. Мы обсудим это ниже.

Для выполнения кода потребуются две разные функции-обработчики, которые могут выглядеть примерно так:

function askPeopleYear( agent ){
  // We know the year is in the parameter
  let year = agent.parameters.year;

  // Get the result, reply, and set the context
  return getPeople( year )
    .then( count => replyPeople( agent, year, count ) );
}

function askPeopleNoYear( agent ){
  // We know the year is in the context
  let context = agent.context.get('RememberYear');
  let year = context && context.parameters && context.parameters.year;

  // Get the result, reply, and set the context
  return getPeople( year )
    .then( count => replyPeople( agent, year, count ) );
}

Функции getPeople() и replyPeople() будут одинаковыми как в нашем предыдущем подходе.

Работа без установленного года

Итак, что произойдет, если они скажут: «Сколько людей там», но у нас нет Контекст «RememberYear» установлен со значением?

В первом подходе это приводит к условию else, которое мы пометили как «FIXME». Во втором подходе сработает резервное намерение, если мы не разместим что-то еще на месте, и это на самом деле не поможет пользователю.

В любом случае мы должны спросить пользователя на год они хотят и создают намерение захватить год. Поскольку нам может потребоваться сделать это для разных типов вопросов, мы также должны сохранить, какую функцию выполнить в ... как вы уже догадались ... контексте. Итак, давайте предположим, что мы установили контекст «NeedsYear» с параметром «functionName», чтобы отслеживать, какую функцию нам нужно вызвать.

Для этого намерения (назовем его «provideYear») потребуется «NeedsYear». «Входной контекст и может иметь обучающие фразы, такие как:

  • [год]
  • Получить его за [год]

и взять« год » параметр, такой же, как мы определили выше. (Мы можем даже пометить это как необходимое.)

Обработчик для этого может выглядеть примерно так:

function provideYear( agent ){
  // We know we have the parmeter
  let year = agent.parameters.year;

  // We also know we have the context with the function name
  let context = agent.context.get('NeedsYear');
  let functionName = context && context.parameters && context.parameters.functionName;

  // We should clear this context, since we no longer need the year
  agent.context.set({
    name: 'NeedsYear',
    lifespan: 0
  };

  // And then call whichever function is appropriate
  if( functionName === 'people' ){
    return getPeople( year )
      .then( count => replyPeople( agent, year, count ) );

  } else if( functionName === 'gender' ){
    // ...
  }
}

Сводка

Использовать контексты.

Контексты являются хорошими привратниками, для которых можно запускать Интенты, а также хорошим способом хранения значений между ходами разговора.

Контексты мощны.

...