De Sdk's voor Bot Framework JavaScript, C# en Python blijven ondersteund, maar de Java SDK wordt buiten gebruik gesteld met definitieve langetermijnondersteuning die eindigt op november 2023.
Bestaande bots die zijn gebouwd met de Java SDK blijven functioneren.
Het skills skillDialog-voorbeeld bevat projecten voor twee bots:
De hoofdmap van het dialoogvenster, dat gebruikmaakt van een vaardigheidsdialoogvensterklasse om een vaardigheid te gebruiken.
De dialoogvenster-vaardigheidsbot, die een dialoogvenster gebruikt voor het afhandelen van activiteiten die afkomstig zijn van gebruikers van vaardigheden.
Dit artikel is gericht op het gebruik van een vaardigheidsdialoogvenster in een hoofdbot om de vaardigheid te beheren, berichten en gebeurtenisactiviteiten te verzenden en de vaardigheid te annuleren.
Zie hoe u een vaardigheidsconsumer implementeert voor informatie over andere aspecten van het maken van een vaardigheidsconsumer.
Voor geïmplementeerde bots vereist bot-naar-bot-verificatie dat elke deelnemende bot een geldige identiteit heeft.
U kunt echter lokaal vaardigheden en vaardigheidsgebruikers testen met de Bot Framework Emulator zonder identiteitsgegevens.
Toepassingsconfiguratie
Voeg eventueel de identiteitsgegevens van de hoofdbot toe aan het configuratiebestand.
Voeg het hosteindpunt voor vaardigheden (de service- of callback-URL) toe waaraan de vaardigheden moeten reageren op de vaardigheidsgebruiker.
Voeg een vermelding toe voor elke vaardigheid die de consument gaat gebruiken. Elke vermelding omvat:
Een id die de consument gebruikt om elke vaardigheid te identificeren.
Optioneel, de app of client-id van de vaardigheidsbot.
Het berichteindpunt van de vaardigheid.
Notitie
Als de gebruiker van de vaardigheid of vaardigheid een identiteit aangeeft, moeten beide identiteiten worden opgegeven.
Voeg eventueel de identiteitsgegevens van de hoofdbot toe en voeg de app- of client-id voor de bot met echovaardigheden toe aan de BotFrameworkSkills matrix.
Voeg eventueel de app-id en het wachtwoord van de hoofdbot toe en voeg de app-id voor de bot met echovaardigheden toe aan de BotFrameworkSkills matrix.
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
Voeg eventueel de app-id en het wachtwoord van de hoofdbot toe en voeg de app-id voor de bot met echovaardigheden toe.
Het hoofddialoogvenster van de bot bevat een dialoogvenster voor vaardigheden voor elke vaardigheid die door deze bot wordt gebruikt. Het vaardigheidsdialoogvenster beheert de vaardigheid via de verschillende vaardigheidsgerelateerde objecten, zoals de vaardigheidsclient en de id-objecten van de vaardigheidsgespreks-id.
Het hoofddialoogvenster laat ook zien hoe u de vaardigheid (via het vaardigheidsdialoogvenster) annuleert op basis van gebruikersinvoer.
De vaardigheid die deze bot gebruikt, ondersteunt een aantal verschillende functies. Het kan een vlucht boeken of het weer voor een stad krijgen. Als er bovendien een bericht wordt ontvangen buiten een van deze contexten en een LUIS-recognizer is geconfigureerd, wordt geprobeerd de intentie van de gebruiker te interpreteren.
Notitie
Language Understanding (LUIS) wordt op 1 oktober 2025 buiten gebruik gesteld.
Vanaf 1 april 2023 kunt u geen nieuwe LUIS-resources maken.
Er is nu een nieuwere versie van taalkennis beschikbaar als onderdeel van Azure AI Language.
Conversational Language Understanding (CLU), een functie van Azure AI Language, is de bijgewerkte versie van LUIS.
Zie Natuurlijke taalkennis voor meer informatie over ondersteuning voor taalkennis in de Bot Framework SDK.
Het vaardigheidsmanifest (C#, JavaScript, Java, Python) beschrijft de acties die de vaardigheid kan uitvoeren, de invoer- en uitvoerparameters en de eindpunten van de vaardigheid.
Opmerking: de vaardigheid kan een gebeurtenis 'BookFlight' of 'GetWeather' afhandelen. Het kan ook berichten verwerken.
Het hoofddialoogvenster wordt overgenomen van de klasse van het onderdeeldialoogvenster . Zie voor meer informatie over onderdeeldialoogvensters hoe u de complexiteit van dialoogvensters beheert.
Het hoofddialoogvenster initialiseren
Het hoofddialoogvenster bevat dialoogvensters (voor het beheren van de gespreksstroom buiten de vaardigheid) en een dialoogvenster voor vaardigheden (voor het beheren van de vaardigheden).
De waterval bevat de volgende stappen, die in de volgende secties gedetailleerder worden beschreven.
Vraag de gebruiker om de vaardigheid te selecteren die moet worden gebruikt. (De hoofdbot verbruikt één vaardigheid.)
Vraag de gebruiker om de actie te selecteren die voor die vaardigheid moet worden gebruikt. (De vaardigheidsbot definieert drie acties.)
Start de gekozen vaardigheid met een initiële activiteit op basis van de gekozen actie.
Zodra de vaardigheid is voltooid, worden de resultaten weergegeven, indien van toepassing. Start vervolgens de waterval opnieuw op.
De MainDialog klasse is afgeleid van ComponentDialog.
Naast de gespreksstatus heeft het dialoogvenster de identiteit en verwijzingen van de hoofdbot nodig naar de vaardigheidsgespreks-id factory, de vaardigheids-HTTP-client en de vaardighedenconfiguratieobjecten.
De dialoogvensterconstructor controleert de invoerparameters, voegt dialoogvensters voor vaardigheden toe, voegt prompt- en watervaldialoogvensters toe voor het beheren van de gespreksstroom buiten de vaardigheid en maakt een eigenschapstoegangsfunctie voor het bijhouden van de actieve vaardigheid, indien van toepassing.
De constructor roept AddSkillDialogseen helpermethode aan om een SkillDialog voor elke vaardigheid te maken die is opgenomen in het configuratiebestand, zoals gelezen uit het configuratiebestand in een SkillsConfiguration object.
// 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
De MainDialog klasse is afgeleid van ComponentDialog.
Naast de gespreksstatus heeft het dialoogvenster de identiteit en verwijzingen van de hoofdbot nodig naar de vaardigheidsgespreks-id factory, de vaardigheids-HTTP-client en de vaardighedenconfiguratieobjecten. De code haalt de identiteit van de bot op uit de gebruikersomgeving.
De dialoogvensterconstructor controleert de invoerparameters, voegt dialoogvensters voor vaardigheden toe, voegt prompt- en watervaldialoogvensters toe voor het beheren van de gespreksstroom buiten de vaardigheid en maakt een eigenschapstoegangsfunctie voor het bijhouden van de actieve vaardigheid, indien van toepassing.
De constructor roept addSkillDialogseen helpermethode aan om een SkillDialog voor elke vaardigheid te maken die is opgenomen in het configuratiebestand, zoals gelezen uit het configuratiebestand in een SkillsConfiguration object.
De MainDialog klasse is afgeleid van ComponentDialog.
Naast de gespreksstatus heeft het dialoogvenster de app-id van de hoofdbot nodig en verwijzingen naar de vaardigheidsgespreks-id factory, de vaardigheids-HTTP-client en de vaardighedenconfiguratieobjecten.
De dialoogvensterconstructor controleert de invoerparameters, voegt dialoogvensters voor vaardigheden toe, voegt prompt- en watervaldialoogvensters toe voor het beheren van de gespreksstroom buiten de vaardigheid en maakt een eigenschapstoegangsfunctie voor het bijhouden van de actieve vaardigheid, indien van toepassing.
De constructor roept addSkillDialogseen helpermethode aan om een SkillDialog voor elke vaardigheid te maken die is opgenomen in het configuratiebestand, zoals gelezen uit het configuratiebestand in een SkillsConfiguration object.
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
De MainDialog klasse is afgeleid van ComponentDialog.
Naast de gespreksstatus heeft het dialoogvenster de app-id van de hoofdbot nodig en verwijzingen naar de vaardigheidsgespreks-id factory, de vaardigheids-HTTP-client en de vaardighedenconfiguratieobjecten.
De dialoogvensterconstructor controleert de invoerparameters, voegt dialoogvensters voor vaardigheden toe, voegt prompt- en watervaldialoogvensters toe voor het beheren van de gespreksstroom buiten de vaardigheid en maakt een eigenschapstoegangsfunctie voor het bijhouden van de actieve vaardigheid, indien van toepassing.
De constructor roept AddSkillDialogseen helpermethode aan om een SkillDialog voor elke vaardigheid te maken die is opgenomen in het configuratiebestand, zoals gelezen uit het configuratiebestand in een SkillConfiguration object.
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))
Een vaardigheid selecteren
In de eerste stap vraagt het hoofddialoogvenster de gebruiker om welke vaardigheid ze willen aanroepen en gebruikt de keuzeprompt SkillPrompt om het antwoord op te halen. (Deze bot definieert slechts één vaardigheid.)
// 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)
Een vaardigheidsactie selecteren
In de volgende stap, het hoofddialoogvenster:
Hiermee wordt informatie opgeslagen over de vaardigheid die de gebruiker heeft geselecteerd.
Vraagt de gebruiker om welke vaardigheidsactie ze willen gebruiken en gebruikt de keuzeprompt SkillActionPrompt om het antwoord op te halen.
Er wordt een helpermethode gebruikt om een lijst met acties op te halen waaruit u kunt kiezen.
De promptvalidator die aan deze prompt is gekoppeld, verzendt standaard een bericht over de vaardigheid als de invoer van de gebruiker niet overeenkomt met een van de opties.
De keuzes in deze bot helpen bij het testen van de acties die voor deze vaardigheid zijn gedefinieerd. Normaal gesproken leest u de opties uit het manifest van de vaardigheid en presenteert u opties aan de gebruiker op basis van die lijst.
// 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
Een vaardigheid starten
In de volgende stap, het hoofddialoogvenster:
Haalt informatie op over de vaardigheids- en vaardigheidsactiviteit die de gebruiker heeft geselecteerd.
Gebruikt een helpermethode om de activiteit te maken die in eerste instantie naar de vaardigheid moet worden verzonden.
Hiermee maakt u de dialoogvensteropties waarmee u het dialoogvenster vaardigheid wilt starten. Dit omvat de eerste activiteit die moet worden verzonden.
Hiermee wordt de status opgeslagen voordat u de vaardigheid aanroept. (Dit is nodig, omdat het antwoord op vaardigheden kan komen tot een ander exemplaar van de vaardigheidsconsumer.)
Hiermee begint u het vaardigheidsdialoogvenster, waarbij u de vaardigheids-id doorgeeft die moet worden aangeroepen en de opties waarmee u deze wilt aanroepen.
// 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)
Het vaardigheidsresultaat samenvatten
In de laatste stap, het hoofddialoogvenster:
Als de vaardigheid een waarde heeft geretourneerd, geeft u het resultaat weer aan de gebruiker.
Hiermee wist u de actieve vaardigheid uit de dialoogvensterstatus.
Hiermee verwijdert u de actieve vaardigheidseigenschap uit de gespreksstatus.
Start zichzelf opnieuw op (het hoofddialoogvenster).
// 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?',
)
Toestaan dat de gebruiker de vaardigheid annuleert
In het hoofddialoogvenster wordt het standaardgedrag van de dialoogvenstermethode voor doorgaan overschreven, zodat de gebruiker de huidige vaardigheid kan annuleren, indien van toepassing. Binnen de methode:
Als er een actieve vaardigheid is en de gebruiker een bericht 'afgebroken' verzendt, annuleert u alle dialoogvensters en zet u het hoofddialoogvenster in de wachtrij om vanaf het begin opnieuw op te starten.
Roep vervolgens de basisuitvoering van de dialoogvenstermethode Voor doorgaan aan om door te gaan met het verwerken van de huidige draai.
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)
Logica voor activiteitshandler
Omdat vaardigheidslogica voor elke beurt wordt verwerkt door een hoofddialoogvenster, ziet de activiteitshandler er ongeveer hetzelfde uit als voor andere dialoogvensters.
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)
Serviceregistratie
De services die nodig zijn om een dialoogvenster voor vaardigheden te gebruiken, zijn hetzelfde als de services die nodig zijn voor een vaardigheidsconsumer in het algemeen.
Bekijk hoe u een vaardigheidsconsumer implementeert voor een bespreking van de vereiste services.
De hoofdbot testen
U kunt de vaardigheidsconsumer in de emulator testen alsof het een normale bot is; U moet echter tegelijkertijd zowel de vaardigheid als de vaardigheid van consumentenbots uitvoeren. Zie hoe u dialoogvensters in een vaardigheid gebruikt voor informatie over het configureren van de vaardigheid.
Voer de bot voor dialoogvenstervaardigheden en de hoofdmap van het dialoogvenster lokaal uit op uw computer. Als u instructies nodig hebt, raadpleegt u de voorbeelden README voor C#, JavaScript, Java, Python.
Gebruik de emulator om de bot te testen.
Wanneer u voor het eerst deelneemt aan het gesprek, geeft de bot een welkomstbericht weer en wordt u gevraagd welke vaardigheid u wilt bellen. De vaardigheidsbot voor dit voorbeeld heeft slechts één vaardigheid.
Selecteer DialogSkillBot.
Vervolgens vraagt de bot u om een actie voor de vaardigheid te kiezen. Kies 'BookFlight'.
Beantwoord de aanwijzingen.
De vaardigheid is voltooid en de hoofdbot geeft de reserveringsgegevens weer voordat u opnieuw wordt gevraagd om de vaardigheid die u wilt aanroepen.
Selecteer DialogSkillBot opnieuw en 'BookFlight'.
Beantwoord de eerste prompt en voer vervolgens 'afbreken' in om de vaardigheid te onderbreken.
De hoofdbot annuleert de vaardigheid en vraagt om de vaardigheid die u wilt aanroepen.
Meer informatie over foutopsporing
Omdat verkeer tussen vaardigheden en vaardigheidsgebruikers wordt geverifieerd, zijn er extra stappen bij het opsporen van fouten in dergelijke bots.
De vaardigheidsconsumer en alle vaardigheden die het verbruikt, moeten direct of indirect worden uitgevoerd.
Als de bots lokaal worden uitgevoerd en als een van de bots een app-id en wachtwoord heeft, moeten alle bots geldige id's en wachtwoorden hebben.