Använda en dialogruta för att använda en färdighet
Artikel
GÄLLER FÖR: SDK v4
Den här artikeln visar hur du använder en kunskapsdialogruta inom en kunskapskonsument.
Kunskapsdialogrutan publicerar aktiviteter från den överordnade roboten till kunskapsroboten och returnerar kunskapssvaren till användaren.
Kunskapsroboten som nås av den här konsumenten kan hantera både meddelande- och händelseaktiviteter.
Ett exempel på ett kunskapsmanifest och information om hur du implementerar färdigheten finns i hur du använder dialogrutor inom en färdighet.
Bot Framework JavaScript-, C#- och Python-SDK:erna fortsätter att stödjas, men Java SDK dras tillbaka med slutligt långsiktigt stöd som slutar i november 2023.
Befintliga robotar som skapats med Java SDK fortsätter att fungera.
Exemplet skills skillDialog innehåller projekt för två robotar:
Dialogrutans rotrobot, som använder en kunskapsdialogruta för att använda en färdighet.
Dialogrutans kunskapsrobot, som använder en dialogruta för att hantera aktiviteter som kommer från kunskapskonsumenter.
Den här artikeln fokuserar på hur du använder en kunskapsdialogruta i en rotrobot för att hantera kunskapen, skicka meddelande- och händelseaktiviteter och avbryta färdigheten.
För distribuerade robotar kräver robot-till-robot-autentisering att varje deltagande robot har en giltig identitet.
Du kan dock testa kunskaper och kunskapskonsumenter lokalt med Bot Framework-emulatorn utan identitetsinformation.
Tillämpningskonfiguration
Du kan också lägga till rotrobotens identitetsinformation i konfigurationsfilen.
Lägg till den färdighetsvärdslutpunkt (tjänsten eller motringnings-URL:en) som färdigheterna ska svara kunskapskonsumenten på.
Lägg till en post för varje färdighet som kunskapskonsumenten kommer att använda. Varje post innehåller:
Ett ID som kunskapskonsumenten använder för att identifiera varje färdighet.
Du kan också använda kunskapsrobotens app eller klient-ID.
Kunskapens slutpunkt för meddelanden.
Kommentar
Om antingen kunskaps- eller färdighetskonsumenten anger en identitet måste båda två.
Du kan också lägga till rotrobotens identitetsinformation och lägga till appen eller klient-ID:t för ekofärdighetsroboten i matrisen BotFrameworkSkills .
Du kan också lägga till rotrobotens app-ID och lösenord och lägga till app-ID:t för ekofärdighetsroboten i matrisen BotFrameworkSkills .
MicrosoftAppId=
MicrosoftAppPassword=
server.port=3978
SkillhostEndpoint=http://localhost:3978/api/skills/
#replicate these three entries, incrementing the index value [0] for each successive Skill that is added.
BotFrameworkSkills[0].Id=DialogSkillBot
BotFrameworkSkills[0].AppId=
BotFrameworkSkills[0].SkillEndpoint=http://localhost:39783/api/messages
dialog-root-bot/config.py
Du kan också lägga till rotrobotens app-ID och lösenord och lägga till app-ID:t för ekofärdighetsroboten.
Robotens huvuddialogruta innehåller en kunskapsdialogruta för varje färdighet som roboten använder. Kunskapsdialogrutan hanterar färdigheten genom de olika kunskapsrelaterade objekten åt dig, till exempel kunskapsklienten och kunskapskonversationens ID-fabriksobjekt.
Huvuddialogrutan visar också hur du avbryter färdigheten (via kunskapsdialogrutan) baserat på användarindata.
Den kunskap som roboten använder har stöd för ett par olika funktioner. Det kan boka ett flyg eller få vädret för en stad. Om det dessutom tar emot ett meddelande utanför någon av dessa kontexter och en LUIS-identifierare har konfigurerats, försöker den tolka användarens avsikt.
Conversational Language Understanding (CLU), en funktion i Azure AI Language, är den uppdaterade versionen av LUIS.
Mer information om stöd för språktolkning i Bot Framework SDK finns i Förstå naturligt språk.
Kunskapsmanifestet (C#, JavaScript, Java, Python) beskriver de åtgärder som färdigheten kan utföra, dess indata- och utdataparametrar och färdighetens slutpunkter.
Observera att färdigheten kan hantera en "BookFlight" eller "GetWeather"-händelse. Den kan också hantera meddelanden.
Huvuddialogrutan ärver från komponentdialogrutans klass. Mer information om komponentdialogrutor finns i hantera dialogkomplexitet.
Initiera huvuddialogrutan
Huvuddialogrutan innehåller dialogrutor (för att hantera konversationsflöden utanför kunskapen) och en kunskapsdialogruta (för att hantera färdigheterna).
Vattenfallet innehåller följande steg, som beskrivs mer detaljerat i de kommande avsnitten.
Uppmana användaren att välja den färdighet som ska användas. (Rotroboten använder en färdighet.)
Uppmana användaren att välja den åtgärd som ska användas för den färdigheten. (Kunskapsroboten definierar tre åtgärder.)
Starta den valda färdigheten med en inledande aktivitet baserat på den valda åtgärden.
När kunskapen har slutförts visar du resultatet, om det finns några. Starta sedan om vattenfallet.
Klassen MainDialog härleds från ComponentDialog.
Förutom konversationstillståndet behöver dialogrutan rotrobotens identitet och referenser till kunskapskonversationens ID-fabrik, kunskaps-HTTP-klienten och konfigurationsobjekten för färdigheter.
Dialogkonstruktorn kontrollerar sina indataparametrar, lägger till kunskapsdialogrutor, lägger till dialogrutor för frågor och vattenfall för att hantera konversationsflöden utanför kunskapen och skapar en egenskapsåtkomst för att spåra den aktiva kompetensen, om någon.
Konstruktorn anropar AddSkillDialogs, en hjälpmetod, för att skapa en SkillDialog för varje färdighet som ingår i konfigurationsfilen, som läst från konfigurationsfilen till ett SkillsConfiguration objekt.
// Helper method that creates and adds SkillDialog instances for the configured skills.
private void AddSkillDialogs(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillsConfiguration skillsConfig, string botId)
{
foreach (var skillInfo in _skillsConfig.Skills.Values)
{
// Create the dialog options.
var skillDialogOptions = new SkillDialogOptions
{
BotId = botId,
ConversationIdFactory = conversationIdFactory,
SkillClient = _auth.CreateBotFrameworkClient(),
SkillHostEndpoint = skillsConfig.SkillHostEndpoint,
ConversationState = conversationState,
Skill = skillInfo
};
// Add a SkillDialog for the selected skill.
AddDialog(new SkillDialog(skillDialogOptions, skillInfo.Id));
}
}
dialogRootBot/dialogs/mainDialog.js
Klassen MainDialog härleds från ComponentDialog.
Förutom konversationstillståndet behöver dialogrutan rotrobotens identitet och referenser till kunskapskonversationens ID-fabrik, kunskaps-HTTP-klienten och konfigurationsobjekten för färdigheter. Koden hämtar robotens identitet från användarmiljön.
Dialogkonstruktorn kontrollerar sina indataparametrar, lägger till kunskapsdialogrutor, lägger till dialogrutor för frågor och vattenfall för att hantera konversationsflöden utanför kunskapen och skapar en egenskapsåtkomst för att spåra den aktiva kompetensen, om någon.
Konstruktorn anropar addSkillDialogs, en hjälpmetod, för att skapa en SkillDialog för varje färdighet som ingår i konfigurationsfilen, som läst från konfigurationsfilen till ett SkillsConfiguration objekt.
Klassen MainDialog härleds från ComponentDialog.
Förutom konversationstillståndet behöver dialogrutan rotrobotens app-ID och referenser till kunskapskonversationens ID-fabrik, kunskaps-HTTP-klienten och konfigurationsobjekten för färdigheter.
Dialogkonstruktorn kontrollerar sina indataparametrar, lägger till kunskapsdialogrutor, lägger till dialogrutor för frågor och vattenfall för att hantera konversationsflöden utanför kunskapen och skapar en egenskapsåtkomst för att spåra den aktiva kompetensen, om någon.
Konstruktorn anropar addSkillDialogs, en hjälpmetod, för att skapa en SkillDialog för varje färdighet som ingår i konfigurationsfilen, som läst från konfigurationsfilen till ett SkillsConfiguration objekt.
private void addSkillDialogs(
ConversationState conversationState,
SkillConversationIdFactoryBase conversationIdFactory,
SkillHttpClient skillClient,
SkillsConfiguration skillsConfig,
String botId
) {
for (BotFrameworkSkill skillInfo : _skillsConfig.getSkills().values()) {
// Create the dialog options.
SkillDialogOptions skillDialogOptions = new SkillDialogOptions();
skillDialogOptions.setBotId(botId);
skillDialogOptions.setConversationIdFactory(conversationIdFactory);
skillDialogOptions.setSkillClient(skillClient);
skillDialogOptions.setSkillHostEndpoint(skillsConfig.getSkillHostEndpoint());
skillDialogOptions.setConversationState(conversationState);
skillDialogOptions.setSkill(skillInfo);
// Add a SkillDialog for the selected skill.
addDialog(new SkillDialog(skillDialogOptions, skillInfo.getId()));
}
}
dialog-root-bot/dialogs/main_dialog.py
Klassen MainDialog härleds från ComponentDialog.
Förutom konversationstillståndet behöver dialogrutan rotrobotens app-ID och referenser till kunskapskonversationens ID-fabrik, kunskaps-HTTP-klienten och konfigurationsobjekten för färdigheter.
Dialogkonstruktorn kontrollerar sina indataparametrar, lägger till kunskapsdialogrutor, lägger till dialogrutor för frågor och vattenfall för att hantera konversationsflöden utanför kunskapen och skapar en egenskapsåtkomst för att spåra den aktiva kompetensen, om någon.
Konstruktorn anropar AddSkillDialogs, en hjälpmetod, för att skapa en SkillDialog för varje färdighet som ingår i konfigurationsfilen, som läst från konfigurationsfilen till ett SkillConfiguration objekt.
def _add_skill_dialogs(
self,
conversation_state: ConversationState,
conversation_id_factory: ConversationIdFactoryBase,
skill_client: SkillHttpClient,
skills_config: SkillConfiguration,
bot_id: str,
):
"""
Helper method that creates and adds SkillDialog instances for the configured skills.
"""
for _, skill_info in skills_config.SKILLS.items():
# Create the dialog options.
skill_dialog_options = SkillDialogOptions(
bot_id=bot_id,
conversation_id_factory=conversation_id_factory,
skill_client=skill_client,
skill_host_endpoint=skills_config.SKILL_HOST_ENDPOINT,
conversation_state=conversation_state,
skill=skill_info,
)
# Add a SkillDialog for the selected skill.
self.add_dialog(SkillDialog(skill_dialog_options, skill_info.id))
Välj en färdighet
I det första steget uppmanar huvuddialogrutan användaren för vilken färdighet de vill anropa och använder "SkillPrompt"-alternativprompten för att få svaret. (Den här roboten definierar bara en färdighet.)
// Render a prompt to select the skill to call.
private async Task<DialogTurnResult> SelectSkillStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Create the PromptOptions from the skill configuration which contain the list of configured skills.
var messageText = stepContext.Options?.ToString() ?? "What skill would you like to call?";
var repromptMessageText = "That was not a valid choice, please select a valid skill.";
var options = new PromptOptions
{
Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
RetryPrompt = MessageFactory.Text(repromptMessageText, repromptMessageText, InputHints.ExpectingInput),
Choices = _skillsConfig.Skills.Select(skill => new Choice(skill.Value.Id)).ToList()
};
// Prompt the user to select a skill.
return await stepContext.PromptAsync("SkillPrompt", options, cancellationToken);
}
dialogRootBot/dialogs/mainDialog.js
/**
* Render a prompt to select the skill to call.
*/
async selectSkillStep(stepContext) {
// Create the PromptOptions from the skill configuration which contains the list of configured skills.
const messageText = stepContext.options && stepContext.options.text ? stepContext.options.text : 'What skill would you like to call?';
const repromptMessageText = 'That was not a valid choice, please select a valid skill.';
const options = {
prompt: MessageFactory.text(messageText, messageText, InputHints.ExpectingInput),
retryPrompt: MessageFactory.text(repromptMessageText, repromptMessageText, InputHints.ExpectingInput),
choices: Object.keys(this.skillsConfig.skills)
};
// Prompt the user to select a skill.
return await stepContext.prompt(SKILL_PROMPT, options);
}
DialogRootBot\Dialogs\MainDialog.java
public CompletableFuture<DialogTurnResult> selectSkillStep(WaterfallStepContext stepContext) {
String messageText = "What skill would you like to call?";
// Create the PromptOptions from the skill configuration which contain the list
// of configured skills.
if (stepContext.getOptions() != null) {
messageText = stepContext.getOptions().toString();
}
String repromptMessageText = "That was not a valid choice, please select a valid skill.";
PromptOptions options = new PromptOptions();
options.setPrompt(MessageFactory.text(messageText, messageText, InputHints.EXPECTING_INPUT));
options
.setRetryPrompt(MessageFactory.text(repromptMessageText, repromptMessageText, InputHints.EXPECTING_INPUT));
List<Choice> choicesList = new ArrayList<Choice>();
for (BotFrameworkSkill skill : _skillsConfig.getSkills().values()) {
choicesList.add(new Choice(skill.getId()));
}
options.setChoices(choicesList);
// Prompt the user to select a skill.
return stepContext.prompt("SkillPrompt", options);
}
dialog-root-bot/dialogs/main_dialog.py
async def _select_skill_action_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
"""
Render a prompt to select the action for the skill.
"""
# Get the skill info based on the selected skill.
selected_skill_id = step_context.result.value
selected_skill = self._skills_config.SKILLS.get(selected_skill_id)
# Remember the skill selected by the user.
step_context.values[self._selected_skill_key] = selected_skill
# Create the PromptOptions with the actions supported by the selected skill.
message_text = (
f"Select an action # to send to **{selected_skill.id}** or just type in a message "
f"and it will be forwarded to the skill"
)
options = PromptOptions(
prompt=MessageFactory.text(
message_text, message_text, InputHints.expecting_input
),
choices=self._get_skill_actions(selected_skill),
)
# Prompt the user to select a skill action.
return await step_context.prompt("SkillActionPrompt", options)
Välj en färdighetsåtgärd
I nästa steg är huvuddialogrutan:
Sparar information om den kompetens som användaren har valt.
Uppmanar användaren för vilken färdighetsåtgärd de vill använda och använder "SkillActionPrompt"-valprompten för att få svaret.
Den använder en hjälpmetod för att hämta en lista över åtgärder att välja mellan.
Frågeverifieraren som är associerad med den här prompten skickar som standard ett meddelande om användarens indata inte matchar något av alternativen.
De val som ingår i den här roboten hjälper dig att testa de åtgärder som definierats för den här färdigheten. Mer normalt skulle du läsa alternativen från färdighetens manifest och presentera alternativ för användaren baserat på den listan.
// Render a prompt to select the action for the skill.
private async Task<DialogTurnResult> SelectSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Get the skill info based on the selected skill.
var selectedSkillId = ((FoundChoice)stepContext.Result).Value;
var selectedSkill = _skillsConfig.Skills.FirstOrDefault(s => s.Value.Id == selectedSkillId).Value;
// Remember the skill selected by the user.
stepContext.Values[_selectedSkillKey] = selectedSkill;
// Create the PromptOptions with the actions supported by the selected skill.
var messageText = $"Select an action # to send to **{selectedSkill.Id}** or just type in a message and it will be forwarded to the skill";
var options = new PromptOptions
{
Prompt = MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput),
Choices = GetSkillActions(selectedSkill)
};
// Prompt the user to select a skill action.
return await stepContext.PromptAsync("SkillActionPrompt", options, cancellationToken);
}
// Helper method to create Choice elements for the actions supported by the skill.
private IList<Choice> GetSkillActions(BotFrameworkSkill skill)
{
// Note: the bot would probably render this by reading the skill manifest.
// We are just using hardcoded skill actions here for simplicity.
var choices = new List<Choice>();
switch (skill.Id)
{
case "DialogSkillBot":
choices.Add(new Choice(SkillActionBookFlight));
choices.Add(new Choice(SkillActionBookFlightWithInputParameters));
choices.Add(new Choice(SkillActionGetWeather));
break;
}
return choices;
}
// This validator defaults to Message if the user doesn't select an existing option.
private Task<bool> SkillActionPromptValidator(PromptValidatorContext<FoundChoice> promptContext, CancellationToken cancellationToken)
{
if (!promptContext.Recognized.Succeeded)
{
// Assume the user wants to send a message if an item in the list is not selected.
promptContext.Recognized.Value = new FoundChoice { Value = SkillActionMessage };
}
return Task.FromResult(true);
}
dialogRootBot/dialogs/mainDialog.js
/**
* Render a prompt to select the action for the skill.
*/
async selectSkillActionStep(stepContext) {
// Get the skill info based on the selected skill.
const selectedSkillId = stepContext.result.value;
const selectedSkill = this.skillsConfig.skills[selectedSkillId];
// Remember the skill selected by the user.
stepContext.values[this.selectedSkillKey] = selectedSkill;
// Create the PromptOptions with the actions supported by the selected skill.
const messageText = `Select an action # to send to **${ selectedSkill.id }** or just type in a message and it will be forwarded to the skill`;
const options = {
prompt: MessageFactory.text(messageText, messageText, InputHints.ExpectingInput),
choices: this.getSkillActions(selectedSkill)
};
// Prompt the user to select a skill action.
return await stepContext.prompt(SKILL_ACTION_PROMPT, options);
}
/**
* Helper method to create Choice elements for the actions supported by the skill.
*/
getSkillActions(skill) {
// Note: The bot would probably render this by reading the skill manifest.
// We are just using hardcoded skill actions here for simplicity.
const choices = [];
switch (skill.id) {
case 'DialogSkillBot':
choices.push({ value: SKILL_ACTION_BOOK_FLIGHT });
choices.push({ value: SKILL_ACTION_BOOK_FLIGHT_WITH_INPUT_PARAMETERS });
choices.push({ value: SKILL_ACTION_GET_WEATHER });
break;
}
return choices;
}
/**
* This validator defaults to Message if the user doesn't select an existing option.
*/
async skillActionPromptValidator(promptContext) {
if (!promptContext.recognized.succeeded) {
promptContext.recognized.value = { value: SKILL_ACTION_MESSAGE };
}
return true;
}
DialogRootBot\Dialogs\MainDialog.java
public CompletableFuture<DialogTurnResult> selectSkillActionStep(WaterfallStepContext stepContext) {
// Get the skill info super. on the selected skill.
String selectedSkillId = ((FoundChoice) stepContext.getResult()).getValue();
BotFrameworkSkill selectedSkill = _skillsConfig.getSkills()
.values()
.stream()
.filter(x -> x.getId().equals(selectedSkillId))
.findFirst()
.get();
// Remember the skill selected by the user.
stepContext.getValues().put(_selectedSkillKey, selectedSkill);
// Create the PromptOptions with the actions supported by the selected skill.
String messageText = String.format(
"Select an action # to send to **%n** or just type in a " + "message and it will be forwarded to the skill",
selectedSkill.getId()
);
PromptOptions options = new PromptOptions();
options.setPrompt(MessageFactory.text(messageText, messageText, InputHints.EXPECTING_INPUT));
options.setChoices(getSkillActions(selectedSkill));
// Prompt the user to select a skill action.
return stepContext.prompt("SkillActionPrompt", options);
}
private List<Choice> getSkillActions(BotFrameworkSkill skill) {
// Note: the bot would probably render this by reading the skill manifest.
// We are just using hardcoded skill actions here for simplicity.
List<Choice> choices = new ArrayList<Choice>();
switch (skill.getId()) {
case "DialogSkillBot":
choices.add(new Choice(SkillActionBookFlight));
choices.add(new Choice(SkillActionBookFlightWithInputParameters));
choices.add(new Choice(SkillActionGetWeather));
break;
}
return choices;
}
addDialog(new ChoicePrompt("SkillActionPrompt", (promptContext) -> {
if (!promptContext.getRecognized().getSucceeded()) {
// Assume the user wants to send a message if an item in the list is not
// selected.
FoundChoice foundChoice = new FoundChoice();
foundChoice.setValue(SkillActionMessage);
promptContext.getRecognized().setValue(foundChoice);
}
return CompletableFuture.completedFuture(true);
}, ""));
dialog-root-bot/dialogs/main_dialog.py
async def _select_skill_action_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
"""
Render a prompt to select the action for the skill.
"""
# Get the skill info based on the selected skill.
selected_skill_id = step_context.result.value
selected_skill = self._skills_config.SKILLS.get(selected_skill_id)
# Remember the skill selected by the user.
step_context.values[self._selected_skill_key] = selected_skill
# Create the PromptOptions with the actions supported by the selected skill.
message_text = (
f"Select an action # to send to **{selected_skill.id}** or just type in a message "
f"and it will be forwarded to the skill"
)
options = PromptOptions(
prompt=MessageFactory.text(
message_text, message_text, InputHints.expecting_input
),
choices=self._get_skill_actions(selected_skill),
)
# Prompt the user to select a skill action.
return await step_context.prompt("SkillActionPrompt", options)
def _get_skill_actions(self, skill: BotFrameworkSkill) -> List[Choice]:
"""
Helper method to create Choice elements for the actions supported by the skill.
"""
# Note: the bot would probably render this by reading the skill manifest.
# We are just using hardcoded skill actions here for simplicity.
choices = []
if skill.id == "DialogSkillBot":
choices.append(Choice(self._skill_action_book_flight))
choices.append(Choice(self._skill_action_book_flight_with_input_parameters))
choices.append(Choice(self._skill_action_get_weather))
return choices
async def _skill_action_prompt_validator(
self, prompt_context: PromptValidatorContext
) -> bool:
"""
This validator defaults to Message if the user doesn't select an existing option.
"""
if not prompt_context.recognized.succeeded:
# Assume the user wants to send a message if an item in the list is not selected.
prompt_context.recognized.value = FoundChoice(
self._skill_action_message, None, None
)
return True
Starta en färdighet
I nästa steg är huvuddialogrutan:
Hämtar information om den kompetens- och färdighetsaktivitet som användaren har valt.
Använder en hjälpmetod för att skapa aktiviteten som ska skickas till färdigheten.
Skapar de dialogalternativ som du vill starta kunskapsdialogrutan med. Detta inkluderar den första aktiviteten som ska skickas.
Sparar tillstånd innan du anropar färdigheten. (Detta är nödvändigt eftersom kunskapssvaret kan komma till en annan instans av kunskapskonsumenten.)
Börjar kunskapsdialogrutan och skickar in kunskaps-ID:t att anropa och de alternativ som du kan anropa den med.
// Starts the SkillDialog based on the user's selections.
private async Task<DialogTurnResult> CallSkillActionStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var selectedSkill = (BotFrameworkSkill)stepContext.Values[_selectedSkillKey];
Activity skillActivity;
switch (selectedSkill.Id)
{
case "DialogSkillBot":
skillActivity = CreateDialogSkillBotActivity(((FoundChoice)stepContext.Result).Value, stepContext.Context);
break;
// We can add other case statements here if we support more than one skill.
default:
throw new Exception($"Unknown target skill id: {selectedSkill.Id}.");
}
// Create the BeginSkillDialogOptions and assign the activity to send.
var skillDialogArgs = new BeginSkillDialogOptions { Activity = skillActivity };
// Save active skill in state.
await _activeSkillProperty.SetAsync(stepContext.Context, selectedSkill, cancellationToken);
// Start the skillDialog instance with the arguments.
return await stepContext.BeginDialogAsync(selectedSkill.Id, skillDialogArgs, cancellationToken);
}
dialogRootBot/dialogs/mainDialog.js
/**
* Starts the SkillDialog based on the user's selections.
*/
async callSkillActionStep(stepContext) {
const selectedSkill = stepContext.values[this.selectedSkillKey];
let skillActivity;
switch (selectedSkill.id) {
case 'DialogSkillBot':
skillActivity = this.createDialogSkillBotActivity(stepContext.result.value, stepContext.context);
break;
// We can add other case statements here if we support more than one skill.
default:
throw new Error(`Unknown target skill id: ${ selectedSkill.id }`);
}
// Create the BeginSkillDialogOptions and assign the activity to send.
const skillDialogArgs = { activity: skillActivity };
// Save active skill in state.
await this.activeSkillProperty.set(stepContext.context, selectedSkill);
// Start the skillDialog instance with the arguments.
return await stepContext.beginDialog(selectedSkill.id, skillDialogArgs);
}
DialogRootBot\Dialogs\MainDialog.java
public CompletableFuture<DialogTurnResult> callSkillActionStep(WaterfallStepContext stepContext) {
BotFrameworkSkill selectedSkill = (BotFrameworkSkill) stepContext.getValues().get(_selectedSkillKey);
Activity skillActivity;
switch (selectedSkill.getId()) {
case "DialogSkillBot":
skillActivity = createDialogSkillBotActivity(
((FoundChoice) stepContext.getResult()).getValue(),
stepContext.getContext()
);
break;
// We can add other case statements here if we support more than one skill.
default:
throw new RuntimeException(String.format("Unknown target skill id: %s.", selectedSkill.getId()));
}
// Create the BeginSkillDialogOptions and assign the activity to send.
BeginSkillDialogOptions skillDialogArgs = new BeginSkillDialogOptions();
skillDialogArgs.setActivity(skillActivity);
// Save active skill in state.
activeSkillProperty.set(stepContext.getContext(), selectedSkill);
// Start the skillDialog instance with the arguments.
return stepContext.beginDialog(selectedSkill.getId(), skillDialogArgs);
}
dialog-root-bot/dialogs/main_dialog.py
async def _call_skill_action_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
"""
Starts the SkillDialog based on the user's selections.
"""
selected_skill: BotFrameworkSkill = step_context.values[
self._selected_skill_key
]
if selected_skill.id == "DialogSkillBot":
skill_activity = self._create_dialog_skill_bot_activity(
step_context.result.value, step_context.context
)
else:
raise Exception(f"Unknown target skill id: {selected_skill.id}.")
# Create the BeginSkillDialogOptions and assign the activity to send.
skill_dialog_args = BeginSkillDialogOptions(skill_activity)
# Save active skill in state.
await self._active_skill_property.set(step_context.context, selected_skill)
# Start the skillDialog instance with the arguments.
return await step_context.begin_dialog(selected_skill.id, skill_dialog_args)
Sammanfatta kunskapsresultatet
I det sista steget, huvuddialogrutan:
Om färdigheten returnerade ett värde visar du resultatet för användaren.
Rensar den aktiva färdigheten från dialogtillståndet.
Tar bort egenskapen aktiv kompetens från konversationstillståndet.
// The SkillDialog has ended, render the results (if any) and restart MainDialog.
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var activeSkill = await _activeSkillProperty.GetAsync(stepContext.Context, () => null, cancellationToken);
// Check if the skill returned any results and display them.
if (stepContext.Result != null)
{
var message = $"Skill \"{activeSkill.Id}\" invocation complete.";
message += $" Result: {JsonConvert.SerializeObject(stepContext.Result)}";
await stepContext.Context.SendActivityAsync(MessageFactory.Text(message, message, inputHint: InputHints.IgnoringInput), cancellationToken: cancellationToken);
}
// Clear the skill selected by the user.
stepContext.Values[_selectedSkillKey] = null;
// Clear active skill in state.
await _activeSkillProperty.DeleteAsync(stepContext.Context, cancellationToken);
// Restart the main dialog with a different message the second time around.
return await stepContext.ReplaceDialogAsync(InitialDialogId, $"Done with \"{activeSkill.Id}\". \n\n What skill would you like to call?", cancellationToken);
}
dialogRootBot/dialogs/mainDialog.js
/**
* The SkillDialog has ended, render the results (if any) and restart MainDialog.
*/
async finalStep(stepContext) {
const activeSkill = await this.activeSkillProperty.get(stepContext.context, () => null);
// Check if the skill returned any results and display them.
if (stepContext.result != null) {
let message = `Skill "${ activeSkill.id }" invocation complete.`;
message += `\nResult: ${ JSON.stringify(stepContext.result, null, 2) }`;
await stepContext.context.sendActivity(message, message, InputHints.IgnoringInput);
}
// Clear the skill selected by the user.
stepContext.values[this.selectedSkillKey] = null;
// Clear active skill in state.
await this.activeSkillProperty.delete(stepContext.context);
// Restart the main dialog with a different message the second time around.
return await stepContext.replaceDialog(this.initialDialogId, { text: `Done with "${ activeSkill.id }". \n\n What skill would you like to call?` });
}
DialogRootBot\Dialogs\MainDialog.java
public CompletableFuture<DialogTurnResult> finalStep(WaterfallStepContext stepContext) {
return activeSkillProperty.get(stepContext.getContext(), () -> null).thenCompose(activeSkill -> {
if (stepContext.getResult() != null) {
String jsonResult = "";
try {
jsonResult =
new JacksonAdapter().serialize(stepContext.getResult()).replace("{", "").replace("}", "");
} catch (IOException e) {
e.printStackTrace();
}
String message =
String.format("Skill \"%s\" invocation complete. Result: %s", activeSkill.getId(), jsonResult);
stepContext.getContext().sendActivity(MessageFactory.text(message, message, InputHints.IGNORING_INPUT));
}
// Clear the skill selected by the user.
stepContext.getValues().put(_selectedSkillKey, null);
// Clear active skill in state.
activeSkillProperty.delete(stepContext.getContext());
// Restart the main dialog with a different message the second time around.
return stepContext.replaceDialog(
getInitialDialogId(),
String.format("Done with \"%s\". \n\n What skill would you like to call?", activeSkill.getId())
);
});
// Check if the skill returned any results and display them.
}
dialog-root-bot/dialogs/main_dialog.py
async def _final_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
"""
The SkillDialog has ended, render the results (if any) and restart MainDialog.
"""
active_skill = await self._active_skill_property.get(step_context.context)
if step_context.result:
message = f"Skill {active_skill.id} invocation complete."
message += f" Result: {step_context.result}"
await step_context.context.send_activity(
MessageFactory.text(message, input_hint=InputHints.ignoring_input)
)
# Clear the skill selected by the user.
step_context.values[self._selected_skill_key] = None
# Clear active skill in state.
await self._active_skill_property.delete(step_context.context)
# Restart the main dialog with a different message the second time around
return await step_context.replace_dialog(
self.initial_dialog_id,
f'Done with "{active_skill.id}". \n\n What skill would you like to call?',
)
Tillåt att användaren avbryter färdigheten
Huvuddialogrutan åsidosätter standardbeteendet för on continue-dialogmetoden så att användaren kan avbryta den aktuella kompetensen, om någon. I -metoden:
Om det finns en aktiv färdighet och användaren skickar ett "avbryt"-meddelande avbryter du alla dialogrutor och köar huvuddialogrutan för att starta om från början.
Anropa sedan basimplementeringen av on continue-dialogmetoden för att fortsätta bearbeta den aktuella svängen.
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
// This is an example on how to cancel a SkillDialog that is currently in progress from the parent bot.
var activeSkill = await _activeSkillProperty.GetAsync(innerDc.Context, () => null, cancellationToken);
var activity = innerDc.Context.Activity;
if (activeSkill != null && activity.Type == ActivityTypes.Message && activity.Text.Equals("abort", StringComparison.OrdinalIgnoreCase))
{
// Cancel all dialogs when the user says abort.
// The SkillDialog automatically sends an EndOfConversation message to the skill to let the
// skill know that it needs to end its current dialogs, too.
await innerDc.CancelAllDialogsAsync(cancellationToken);
return await innerDc.ReplaceDialogAsync(InitialDialogId, "Canceled! \n\n What skill would you like to call?", cancellationToken);
}
return await base.OnContinueDialogAsync(innerDc, cancellationToken);
}
dialogRootBot/dialogs/mainDialog.js
async onContinueDialog(innerDc) {
const activeSkill = await this.activeSkillProperty.get(innerDc.context, () => null);
const activity = innerDc.context.activity;
if (activeSkill != null && activity.type === ActivityTypes.Message && activity.text.toLowerCase() === 'abort') {
// Cancel all dialogs when the user says abort.
// The SkillDialog automatically sends an EndOfConversation message to the skill to let the
// skill know that it needs to end its current dialogs, too.
await innerDc.cancelAllDialogs();
return await innerDc.replaceDialog(this.initialDialogId, { text: 'Canceled! \n\n What skill would you like to call?' });
}
return await super.onContinueDialog(innerDc);
}
DialogRootBot\Dialogs\MainDialog.java
// Cancel all dialogs when the user says abort.
// The SkillDialog automatically sends an EndOfConversation message to the skill
// to let the
// skill know that it needs to end its current dialogs, too.
return innerDc.cancelAllDialogs()
.thenCompose(
result -> innerDc
.replaceDialog(getInitialDialogId(), "Canceled! \n\n What skill would you like to call?")
);
dialog-root-bot/dialogs/main_dialog.py
async def on_continue_dialog(self, inner_dc: DialogContext) -> DialogTurnResult:
# This is an example on how to cancel a SkillDialog that is currently in progress from the parent bot.
active_skill = await self._active_skill_property.get(inner_dc.context)
activity = inner_dc.context.activity
if (
active_skill
and activity.type == ActivityTypes.message
and "abort" in activity.text
):
# Cancel all dialogs when the user says abort.
# The SkillDialog automatically sends an EndOfConversation message to the skill to let the
# skill know that it needs to end its current dialogs, too.
await inner_dc.cancel_all_dialogs()
return await inner_dc.replace_dialog(self.initial_dialog_id)
return await super().on_continue_dialog(inner_dc)
Logik för aktivitetshanterare
Eftersom kunskapslogik för varje tur hanteras av en huvuddialogruta ser aktivitetshanteraren ungefär ut som för andra dialogexempel.
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
if (turnContext.Activity.Type != ActivityTypes.ConversationUpdate)
{
// Run the Dialog with the Activity.
await _mainDialog.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
}
else
{
// Let the base class handle the activity.
await base.OnTurnAsync(turnContext, cancellationToken);
}
// Save any state changes that might have occurred during the turn.
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
}
dialogRootBot/bots/rootBot.js
class RootBot extends ActivityHandler {
constructor(conversationState, dialog) {
super();
if (!conversationState) throw new Error('[RootBot]: Missing parameter. conversationState is required');
if (!dialog) throw new Error('[RootBot]: Missing parameter. dialog is required');
this.conversationState = conversationState;
this.dialog = dialog;
this.onTurn(async (turnContext, next) => {
if (turnContext.activity.type !== ActivityTypes.ConversationUpdate) {
// Run the Dialog with the activity.
await runDialog(this.dialog, turnContext, this.conversationState.createProperty('DialogState'));
}
await next();
});
/**
* Override the ActivityHandler.run() method to save state changes after the bot logic completes.
*/
async run(context) {
await super.run(context);
// Save any state changes. The load happened during the execution of the Dialog.
await this.conversationState.saveChanges(context, false);
}
DialogRootBot\Bots\RootBot.java
public class RootBot<T extends Dialog> extends ActivityHandler {
public RootBot(ConversationState conversationState, T mainDialog) {
this.conversationState = conversationState;
this.mainDialog = mainDialog;
}
@Override
public CompletableFuture<Void> onTurn(TurnContext turnContext) {
return handleTurn(turnContext).thenCompose(result -> conversationState.saveChanges(turnContext, false));
}
private CompletableFuture<Void> handleTurn(TurnContext turnContext) {
if (!turnContext.getActivity().getType().equals(ActivityTypes.CONVERSATION_UPDATE)) {
// Run the Dialog with the Activity.
return Dialog.run(mainDialog, turnContext, conversationState.createProperty("DialogState"));
} else {
// Let the super.class handle the activity.
return super.onTurn(turnContext);
}
}
dialog-root-bot/bots/root_bot.py
class RootBot(ActivityHandler):
def __init__(
self, conversation_state: ConversationState, main_dialog: Dialog,
):
self._conversation_state = conversation_state
self._main_dialog = main_dialog
async def on_turn(self, turn_context: TurnContext):
if turn_context.activity.type != ActivityTypes.conversation_update:
# Run the Dialog with the Activity.
await DialogExtensions.run_dialog(
self._main_dialog,
turn_context,
self._conversation_state.create_property("DialogState"),
)
else:
# Let the base class handle the activity.
await super().on_turn(turn_context)
# Save any state changes that might have occurred during the turn.
await self._conversation_state.save_changes(turn_context)
Tjänstregistrering
De tjänster som behövs för att använda en kunskapsdialogruta är desamma som de som behövs för en kunskapskonsument i allmänhet.
Se hur du implementerar en kunskapskonsument för en diskussion om de tjänster som krävs.
Testa rotroboten
Du kan testa kunskapskonsumenten i emulatorn som om det vore en vanlig robot. Du måste dock köra både kunskaps- och kunskapsrobotarna på samma gång. Se hur du använder dialogrutor inom en färdighet för information om hur du konfigurerar kunskapen.
Kör dialogrutans kunskapsrobot och dialogrotrobot lokalt på datorn. Om du behöver instruktioner kan du läsa exempel README på C#, JavaScript, Java, Python.
Använd emulatorn för att testa roboten.
När du först ansluter till konversationen visar roboten ett välkomstmeddelande och frågar dig vilken färdighet du vill ringa. Kunskapsroboten för det här exemplet har bara en färdighet.
Välj DialogSkillBot.
Sedan ber roboten dig att välja en åtgärd för färdigheten. Välj "BookFlight".
Svara på anvisningarna.
Kunskapen slutförs och rotroboten visar bokningsinformationen innan du frågar igen om den färdighet du vill anropa.
Välj DialogSkillBot igen och "BookFlight".
Svara på den första uppmaningen och ange sedan "abort" för att avbryta färdigheten.
Rotroboten avbryter kunskapen och frågar efter den färdighet som du vill anropa.
Mer om felsökning
Eftersom trafiken mellan kompetens och kunskapskonsumenter autentiseras finns det extra steg när du felsöker sådana robotar.
Kunskapskonsumenten och alla färdigheter som den förbrukar, direkt eller indirekt, måste köras.
Om robotarna körs lokalt och om någon av robotarna har ett app-ID och lösenord måste alla robotar ha giltiga ID:er och lösenord.