Partager via


Utiliser des dialogues au sein d’une compétence

S'APPLIQUE À : SDK v4

Cet article explique comment créer une compétence prenant en charge plusieurs actions. Elle prend en charge ces actions à l’aide de dialogues. Le dialogue principal reçoit l’entrée initiale du consommateur de compétences, puis démarre l’action appropriée. Pour plus d’informations sur l’implémentation du consommateur de compétences pour le code associé, découvrez comment consommer une compétence à l’aide de dialogues.

Cet article présuppose que vous maîtrisez déjà les compétences de création. Pour savoir comment créer un bot de compétences d’une manière générale, voir comment implémenter une compétence.

Remarque

Les kits SDK JavaScript, C# et Python Bot Framework continueront d’être pris en charge. Toutefois, le kit de développement logiciel (SDK) Java est mis hors service avec une prise en charge finale à long terme se terminant en novembre 2023.

Les bots existants créés avec le kit de développement logiciel (SDK) Java continueront de fonctionner.

Pour la nouvelle génération de bots, envisagez d’utiliser Microsoft Copilot Studio et lisez-en plus sur le choix de la solution copilote appropriée.

Pour plus d’informations, consultez Les futures versions de bot.

Prérequis

Remarque

Compréhension du langage (LUIS) sera mis hors service le 1er octobre 2025. À compter du 1er avril 2023, vous ne pourrez pas créer de nouvelles ressources LUIS. Une version plus récente de Compréhension du langage est désormais disponible dans le cadre d'Azure AI Language.

Compréhension du langage courant (CLU), une fonctionnalité d’Azure AI Language, est la version mise à jour de LUIS. Pour plus d'informations sur la prise en charge de compréhension du langage dans le kit de développement logiciel (SDK) Bot Framework, consultez Compréhension du langage naturel.

À propos de cet exemple

L’exemple de compétences skillDialog inclut des projets pour deux bots :

  • Le bot racine du dialogue, qui utilise une classe de dialogue de compétence pour consommer une compétence.
  • Le bot de compétences du dialogue, qui utilise un dialogue pour gérer les activités provenant des consommateurs de compétences. Cette compétence est une adaptation de l’exemple de bot principal. (Pour plus d’informations sur le bot principal, découvrez comment ajouter une compréhension du langage naturel à votre bot.)

Cet article se concentre sur l'utilisation de dialogue dans un bot de compétences pour gérer plusieurs actions.

Pour plus d’informations sur le bot consommateur de compétences, découvrez comment consommer une compétence à l’aide de dialogues.

Ressources

Pour les bots déployés, l'authentification entre bots exige que chaque bot participant ait une identité valide. Toutefois, vous pouvez tester les compétences et les consommateurs de compétences localement avec Bot Framework Emulator sans informations d'identité.

Pour mettre la compétence à la disposition des bots en contact avec l'utilisateur, enregistrez la compétence auprès d'Azure. Pour plus d'informations, découvrez comment enregistrer un bot auprès d'Azure AI Bot Service.

Si vous le souhaitez, le bot de compétences peut utiliser un modèle de réservation de vol LUIS. Pour utiliser ce modèle, utilisez le fichier CognitiveModels/FlightBooking.json pour créer, former et publier le modèle LUIS.

Configuration de l’application

  1. Vous pouvez également ajouter les informations relatives à l'identité de la compétence au fichier de configuration de la compétence. (Si la compétence ou le consommateur de compétences spécifie une identité, les deux doivent être indiqués.)

  2. Si vous utilisez le modèle LUIS, ajoutez l'identifiant d'application, la clé API et le nom d'hôte d'API de LUIS.

DialogSkillBot\appsettings.json

{
  "MicrosoftAppType": "",
  "MicrosoftAppId": "",
  "MicrosoftAppPassword": "",
  "MicrosoftAppTenantId": "",
  "ConnectionName": "",

  "LuisAppId": "",
  "LuisAPIKey": "",
  "LuisAPIHostName": "",

  // This is a comma separate list with the App IDs that will have access to the skill.
  // This setting is used in AllowedCallersClaimsValidator.
  // Examples: 
  //    [ "*" ] allows all callers.
  //    [ "AppId1", "AppId2" ] only allows access to parent bots with "AppId1" and "AppId2".
  "AllowedCallers": [ "*" ]
}

Logique activity-routing

La compétence prend en charge plusieurs fonctionnalités différentes. Elle peut réserver un vol ou donner la météo d’une ville. De plus, si elle reçoit un message en dehors de l’un de ces contextes, elle peut utiliser LUIS pour essayer de l’interpréter. Le manifeste de la compétence décrit ces actions, leurs paramètres d’entrée et de sortie, ainsi que les points de terminaison de la compétence. Notez que la compétence peut gérer un événement « BookFlight » ou « GetWeather ». Elle peut également gérer des activités de messages.

La compétence définit un dialogue activity-routing (routage d’activités) qu’elle utilise pour sélectionner l’action à lancer, en fonction de l’activité entrante initiale du consommateur de compétence. Le cas échéant, le modèle LUIS peut reconnaître des intentions book-flight (réservation de vols) et get-weather (prévisions météo) dans un message initial.

L’action book-flight est un processus à plusieurs étapes, implémenté sous forme de dialogue distinct. Une fois que l’action commence, les activités entrantes sont gérées par ce dialogue. L’action get-weather a une logique d’espace réservé qui serait remplacée dans un bot entièrement implémenté.

Le dialogue de routage des activités inclut du code permettant d’effectuer les opérations suivantes :

Les dialogues utilisés dans la compétence héritent de la classe dialogue du composant. Pour plus d’informations sur les dialogues de composants, découvrez comment gérer la complexité des dialogues.

Initialiser le dialogue

Le dialogue activity-routing inclut un dialogue enfant pour la réservation d’un vol. Le dialogue en cascade principal comporte une étape permettant de démarrer une action basée sur l’activité initiale reçue.

Il accepte également un module de reconnaissance LUIS. Si ce module de reconnaissance est initialisé, la boîte de dialogue l’utilise pour interpréter l’intention d’une de message initiale.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private readonly DialogSkillBotRecognizer _luisRecognizer;

public ActivityRouterDialog(DialogSkillBotRecognizer luisRecognizer)
    : base(nameof(ActivityRouterDialog))
{
    _luisRecognizer = luisRecognizer;

    AddDialog(new BookingDialog());
    AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[] { ProcessActivityAsync }));

    // The initial child Dialog to run.
    InitialDialogId = nameof(WaterfallDialog);
}

Traiter une activité initiale

Dans la première (et seule) étape du dialogue en cascade principal, la compétence vérifie le type d’activité entrante.

  • Les activités d’événements sont transférées à un gestionnaire sur activité d’événement qui démarre l’action appropriée en fonction du nom de l’événement.
  • Les activités de message sont transférées à un gestionnaire sur activité de message qui effectue un traitement supplémentaire avant de décider de la procédure à suivre.

Si la compétence ne reconnaît pas le type de l’activité entrante ou le nom de l’événement, elle envoie un message d’erreur et se termine.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private async Task<DialogTurnResult> ProcessActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // A skill can send trace activities, if needed.
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.ProcessActivityAsync()", label: $"Got ActivityType: {stepContext.Context.Activity.Type}", cancellationToken: cancellationToken);

    switch (stepContext.Context.Activity.Type)
    {
        case ActivityTypes.Event:
            return await OnEventActivityAsync(stepContext, cancellationToken);

        case ActivityTypes.Message:
            return await OnMessageActivityAsync(stepContext, cancellationToken);

        default:
            // We didn't get an activity type we can handle.
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Unrecognized ActivityType: \"{stepContext.Context.Activity.Type}\".", inputHint: InputHints.IgnoringInput), cancellationToken);
            return new DialogTurnResult(DialogTurnStatus.Complete);
    }
}
// This method performs different tasks based on the event name.
private async Task<DialogTurnResult> OnEventActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.OnEventActivityAsync()", label: $"Name: {activity.Name}. Value: {GetObjectAsJsonString(activity.Value)}", cancellationToken: cancellationToken);

    // Resolve what to execute based on the event name.
    switch (activity.Name)
    {
        case "BookFlight":
            return await BeginBookFlight(stepContext, cancellationToken);

        case "GetWeather":
            return await BeginGetWeather(stepContext, cancellationToken);

        default:
            // We didn't get an event name we can handle.
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Unrecognized EventName: \"{activity.Name}\".", inputHint: InputHints.IgnoringInput), cancellationToken);
            return new DialogTurnResult(DialogTurnStatus.Complete);
    }
}

Gérer des activités de messages

Si le module de reconnaissance LUIS est configuré, la compétence appelle LUIS, puis démarre une action en fonction de l’intention. Si le module de reconnaissance LUIS n'est pas configuré ou que l'intention n'est pas prise en charge, la compétence envoie un message d'erreur et se termine.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

// This method just gets a message activity and runs it through LUIS. 
private async Task<DialogTurnResult> OnMessageActivityAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    await stepContext.Context.TraceActivityAsync($"{GetType().Name}.OnMessageActivityAsync()", label: $"Text: \"{activity.Text}\". Value: {GetObjectAsJsonString(activity.Value)}", cancellationToken: cancellationToken);

    if (!_luisRecognizer.IsConfigured)
    {
        await stepContext.Context.SendActivityAsync(MessageFactory.Text("NOTE: LUIS is not configured. To enable all capabilities, add 'LuisAppId', 'LuisAPIKey' and 'LuisAPIHostName' to the appsettings.json file.", inputHint: InputHints.IgnoringInput), cancellationToken);
    }
    else
    {
        // Call LUIS with the utterance.
        var luisResult = await _luisRecognizer.RecognizeAsync<FlightBooking>(stepContext.Context, cancellationToken);

        // Create a message showing the LUIS results.
        var sb = new StringBuilder();
        sb.AppendLine($"LUIS results for \"{activity.Text}\":");
        var (intent, intentScore) = luisResult.Intents.FirstOrDefault(x => x.Value.Equals(luisResult.Intents.Values.Max()));
        sb.AppendLine($"Intent: \"{intent}\" Score: {intentScore.Score}");

        await stepContext.Context.SendActivityAsync(MessageFactory.Text(sb.ToString(), inputHint: InputHints.IgnoringInput), cancellationToken);

        // Start a dialog if we recognize the intent.
        switch (luisResult.TopIntent().intent)
        {
            case FlightBooking.Intent.BookFlight:
                return await BeginBookFlight(stepContext, cancellationToken);

            case FlightBooking.Intent.GetWeather:
                return await BeginGetWeather(stepContext, cancellationToken);

            default:
                // Catch all for unhandled intents.
                var didntUnderstandMessageText = $"Sorry, I didn't get that. Please try asking in a different way (intent was {luisResult.TopIntent().intent})";
                var didntUnderstandMessage = MessageFactory.Text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IgnoringInput);
                await stepContext.Context.SendActivityAsync(didntUnderstandMessage, cancellationToken);
                break;
        }
    }

    return new DialogTurnResult(DialogTurnStatus.Complete);
}

Commencer une action à plusieurs étapes

L’action book-flight démarre une boîte de dialogue à plusieurs étapes pour obtenir les détails de la réservation de la part de l’utilisateur.

L'action get-weather n'est pas implémentée. Actuellement, elle envoie un message d’espace réservé, puis se termine.

DialogSkillBot\Dialogs\ActivityRouterDialog.cs

private async Task<DialogTurnResult> BeginBookFlight(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    var bookingDetails = new BookingDetails();
    if (activity.Value != null)
    {
        bookingDetails = JsonConvert.DeserializeObject<BookingDetails>(JsonConvert.SerializeObject(activity.Value));
    }

    // Start the booking dialog.
    var bookingDialog = FindDialog(nameof(BookingDialog));
    return await stepContext.BeginDialogAsync(bookingDialog.Id, bookingDetails, cancellationToken);
}
private static async Task<DialogTurnResult> BeginGetWeather(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var activity = stepContext.Context.Activity;
    var location = new Location();
    if (activity.Value != null)
    {
        location = JsonConvert.DeserializeObject<Location>(JsonConvert.SerializeObject(activity.Value));
    }

    // We haven't implemented the GetWeatherDialog so we just display a TODO message.
    var getWeatherMessageText = $"TODO: get weather for here (lat: {location.Latitude}, long: {location.Longitude}";
    var getWeatherMessage = MessageFactory.Text(getWeatherMessageText, getWeatherMessageText, InputHints.IgnoringInput);
    await stepContext.Context.SendActivityAsync(getWeatherMessage, cancellationToken);
    return new DialogTurnResult(DialogTurnStatus.Complete);
}

Retourner un résultat

La compétence démarre un dialogue de réservation pour l’action book-flight. Dans la mesure où le dialogue activity-routing ne comporte qu’une étape, lorsque le dialogue de réservation se termine, le dialogue activity-routing se termine également, et le résultat du dialogue de réservation devient le résultat du dialogue activity-routing.

L’action get-weather se termine simplement sans définir de valeur de retour.

Annuler une action de plusieurs étapes

Le dialogue de réservation et son dialogue date-resolver enfant son tous deux dérivés de la boîte de dialogue de base d’annulation et d’aide, qui vérifie les messages de l’utilisateur.

  • Sur « Help » ou « ? », il affiche un message d’aide, puis continue le flux de conversation sur le tour suivant.
  • Sur « annuler » ou « quitter », il annule tous les dialogues, ce qui met fin à la compétence.

Pour plus d’informations, consultez comment gérer les interruptions de l’utilisateur.

Inscription du service

Les services nécessaires pour cette compétence sont les mêmes que ceux nécessaires pour un bot de compétences en général. Découvrez comment implémenter une compétence pour une discussion des services requis.

Manifeste de compétence

Un manifeste de compétence est un fichier JSON qui décrit les activités que la compétence peut effectuer, ses paramètres d’entrée et de sortie, ainsi que ses points de terminaison. Le manifeste contient les informations dont vous avez besoin pour accéder à la compétence d’un autre bot.

DialogSkillBot\wwwroot\manifest\dialogchildbot-manifest-1.0.json

{
  "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
  "$id": "DialogSkillBot",
  "name": "Skill bot with dialogs",
  "version": "1.0",
  "description": "This is a sample skill definition for multiple activity types.",
  "publisherName": "Microsoft",
  "privacyUrl": "https://dialogskillbot.contoso.com/privacy.html",
  "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
  "license": "",
  "iconUrl": "https://dialogskillbot.contoso.com/icon.png",
  "tags": [
    "sample",
    "travel",
    "weather",
    "luis"
  ],
  "endpoints": [
    {
      "name": "default",
      "protocol": "BotFrameworkV3",
      "description": "Default endpoint for the skill.",
      "endpointUrl": "https://dialogskillbot.contoso.com/api/messages",
      "msAppId": "00000000-0000-0000-0000-000000000000"
    }
  ],
  "activities": {
    "bookFlight": {
      "description": "Books a flight (multi turn).",
      "type": "event",
      "name": "BookFlight",
      "value": {
        "$ref": "#/definitions/bookingInfo"
      },
      "resultValue": {
        "$ref": "#/definitions/bookingInfo"
      }
    },
    "getWeather": {
      "description": "Retrieves and returns the weather for the user's location.",
      "type": "event",
      "name": "GetWeather",
      "value": {
        "$ref": "#/definitions/location"
      },
      "resultValue": {
        "$ref": "#/definitions/weatherReport"
      }
    },
    "passthroughMessage": {
      "type": "message",
      "description": "Receives the user's utterance and attempts to resolve it using the skill's LUIS models.",
      "value": {
        "type": "object"
      }
    }
  },
  "definitions": {
    "bookingInfo": {
      "type": "object",
      "required": [
        "origin"
      ],
      "properties": {
        "origin": {
          "type": "string",
          "description": "This is the origin city for the flight."
        },
        "destination": {
          "type": "string",
          "description": "This is the destination city for the flight."
        },
        "travelDate": {
          "type": "string",
          "description": "The date for the flight in YYYY-MM-DD format."
        }
      }
    },
    "weatherReport": {
      "type": "array",
      "description": "Array of forecasts for the next week.",
      "items": [
        {
          "type": "string"
        }
      ]
    },
    "location": {
      "type": "object",
      "description": "Location metadata.",
      "properties": {
        "latitude": {
          "type": "number",
          "title": "Latitude"
        },
        "longitude": {
          "type": "number",
          "title": "Longitude"
        },
        "postalCode": {
          "type": "string",
          "title": "Postal code"
        }
      }
    }
  }
}

Le schéma de manifeste de compétence est un fichier JSON qui décrit le schéma du manifeste de compétence. La dernière version du schéma est la v2.1.

Tester le bot de compétences

Vous pouvez tester la compétence dans l’émulateur avec le consommateur de compétences. Pour ce faire, vous devez exécuter simultanément la compétence et les bots du consommateur de compétences. Pour plus d’informations sur la configuration de la compétence, découvrez comment utiliser un dialogue pour consommer une compétence.

Téléchargez et installez la dernière version du Bot Framework Emulator.

  1. Exécutez le bot de compétences du dialogue et le bot racine du dialogue localement sur votre ordinateur. Si vous avez besoin d'instructions, reportez-vous au fichier README de l'échantillon pour C#, JavaScript, Java ou Python.
  2. Utiliser l’émulateur pour tester le bot.
    • Lorsque vous joignez la conversation pour la première fois, le bot affiche un message de bienvenue et vous demande quelles compétences vous souhaitez appeler. Le bot de compétences pour cet exemple n’a qu’une compétence.
    • Sélectionnez DialogSkillBot.
  3. Le bot vous demande ensuite de choisir une action pour la compétence. Choisissez « BookFlight ».
    1. La compétence commence son action book-flight ; répondez aux invites.
    2. Lorsque la compétence se termine, le bot racine affiche les détails de la réservation avant de vous demander à nouveau quelle compétence que vous souhaitez appeler.
  4. Sélectionnez de nouveau DialogSkillBot et « BookFlight ».
    1. Répondez à la première invite, puis entrez « annuler » pour annuler l’action.
    2. Le bot de compétences se termine sans terminer l’action, et le consommateur vous invite à entrer les compétences que vous souhaitez appeler.

Plus d'informations sur le débogage

Étant donné que le trafic entre les compétences et les consommateurs de compétences est authentifié, des étapes supplémentaires sont nécessaires pour déboguer ces bots.

Dans le cas contraire, vous pouvez déboguer un consommateur de compétences ou une compétence comme vous déboguez d'autres bots. Pour plus d'informations, consultez Débogage d'un bot et Débogage avec Bot Framework Emulator.

Informations supplémentaires