Implementare una competenza

SI APPLICA A: SDK v4

È possibile usare le competenze per estendere un altro bot. Una competenza è un bot che può eseguire un set di attività per un altro bot.

  • L'interfaccia di una competenza è descritta da un manifesto. Gli sviluppatori che non hanno accesso al codice sorgente della competenza possono usare le informazioni nel manifesto per progettare il proprio consumer di competenze.
  • Una competenza può usare la convalida delle attestazioni per i bot o gli utenti autorizzati ad accedervi.

Questo articolo illustra come implementare una competenza che restituisce l'input dell'utente.

Alcuni tipi di consumer di competenze non sono in grado di usare alcuni tipi di bot di competenza. Nella tabella seguente vengono descritte le combinazioni supportate.

  Competenza multi-tenant Competenza a tenant singolo Competenza identità gestita assegnata dall'utente
Consumer multi-tenant Supportato Non supportato Non supportato
Consumer a tenant singolo Non supportato Supportato se entrambe le app appartengono allo stesso tenant Supportato se entrambe le app appartengono allo stesso tenant
Consumer dell'identità gestita assegnata dall'utente Non supportato Supportato se entrambe le app appartengono allo stesso tenant Supportato se entrambe le app appartengono allo stesso tenant

Nota

Gli SDK JavaScript, C# e Python di Bot Framework continueranno a essere supportati, ma Java SDK verrà ritirato con il supporto finale a lungo termine che termina a novembre 2023.

I bot esistenti creati con Java SDK continueranno a funzionare.

Per la creazione di nuovi bot, prendere in considerazione l'uso di Power Virtual Agents e leggere la scelta della soluzione chatbot appropriata.

Per altre informazioni, vedere Il futuro della compilazione di bot.

Prerequisiti

Nota

A partire dalla versione 4.11, non è necessario un ID app e una password per testare una competenza in locale in Bot Framework Emulator. Per distribuire la competenza in Azure, è comunque necessaria una sottoscrizione di Azure.

Informazioni sull'esempio

L'esempio di competenza semplice da bot a bot include i progetti per due bot:

  • Il bot di competenza echo, che implementa la competenza.
  • Il bot radice semplice, che implementa un bot radice che utilizza la competenza.

Questo articolo è incentrato sulla competenza, che include la logica di supporto nei relativi bot ed adapter.

Per informazioni sul bot radice semplice, vedere Implementare un consumer di competenze.

Risorse

Per i bot distribuiti, l'autenticazione da bot a bot richiede che ogni bot partecipante disponga di informazioni di identità valide. Tuttavia, è possibile testare le competenze e i consumer di competenze multi-tenant in locale con l'emulatore senza un ID app e una password.

Per rendere disponibile la competenza per i bot rivolti agli utenti, registrare la competenza con Azure. Per altre informazioni, vedere come registrare un bot con Azure AI servizio Bot.

Configurazione dell'applicazione

Facoltativamente, aggiungere le informazioni sull'identità della competenza al file di configurazione. Se la competenza o il consumer di competenze fornisce informazioni sull'identità, entrambe devono.

La matrice di chiamanti consentiti consente di limitare il numero di consumer che possono accedere alle competenze. Aggiungere un elemento "*" per accettare chiamate da qualsiasi consumer di competenze.

Nota

Se si sta testando la competenza in locale senza informazioni sull'identità del bot, né la competenza né il consumer di competenze eseguono il codice per eseguire la convalida delle attestazioni.

EchoSkillBot\appsettings.json

Facoltativamente, aggiungere le informazioni sull'identità della competenza al file di appsettings.json.

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

  // 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": [ "*" ]
}

Logica del gestore di attività

Per accettare parametri di input

Il consumer di competenze può inviare informazioni alla competenza. Un modo per accettare tali informazioni consiste nell'usare la proprietà value impostata per i messaggi in arrivo. Un altro modo consiste nel gestire l'evento e richiamare le attività.

La competenza in questo esempio non accetta parametri di input.

Per continuare o completare una conversazione

Quando la competenza invia un'attività, il consumer di competenze deve inoltrare l'attività all'utente.

È tuttavia necessario inviare un'attività endOfConversation quando la competenza non viene più usata; in caso contrario, il consumer di competenze continuerà a trasmettere le attività dell'utente alla competenza. Facoltativamente, usare la proprietà value dell'attività per includere un valore restituito e la proprietà code dell'attività per indicare il motivo per cui la competenza verrà terminata.

EchoSkillBot\Bots\EchoBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    if (turnContext.Activity.Text.Contains("end") || turnContext.Activity.Text.Contains("stop"))
    {
        // Send End of conversation at the end.
        var messageText = $"ending conversation from the skill...";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
        var endOfConversation = Activity.CreateEndOfConversationActivity();
        endOfConversation.Code = EndOfConversationCodes.CompletedSuccessfully;
        await turnContext.SendActivityAsync(endOfConversation, cancellationToken);
    }
    else
    {
        var messageText = $"Echo: {turnContext.Activity.Text}";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
        messageText = "Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
        await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput), cancellationToken);
    }
}

Per annullare la competenza

Per le competenze a più turni, sono accettabili anche le attività endOfConversation inviate da un consumer di competenze, per consentire al consumer di annullare la conversazione corrente.

La logica per questa competenza non cambia da turno a turno. Se si implementa una competenza che alloca le risorse della conversazione, aggiungere il codice di pulitura delle risorse al gestore di fine conversazione.

EchoSkillBot\Bots\EchoBot.cs

protected override Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
    // This will be called if the root bot is ending the conversation.  Sending additional messages should be
    // avoided as the conversation may have been deleted.
    // Perform cleanup of resources if needed.
    return Task.CompletedTask;
}

Validator di attestazioni

Questo esempio usa un elenco di chiamanti consentiti per la convalida delle attestazioni. L'elenco è definito nel file di configurazione della competenza e viene letto nell'oggetto validator durante la creazione.

È necessario aggiungere un validator di attestazioni alla configurazione di autenticazione. Le attestazioni vengono valutate dopo l'intestazione di autenticazione. Il codice di convalida deve generare un errore o un'eccezione per rifiutare la richiesta. Sono numerosi i motivi per cui è consigliabile rifiutare una richiesta che diversamente verrebbe autenticata. Ad esempio:

  • La competenza è inclusa in un servizio a pagamento. L'utente non si trova nel database non deve avere accesso.
  • La competenza è proprietaria. Solo alcuni consumer di competenze possono chiamare la competenza.

Importante

Se non si fornisce un validator di attestazioni, il bot genererà un errore o un'eccezione quando si riceve un'attività dal consumer di competenze.

L'SDK fornisce una classe che aggiunge l'autorizzazione AllowedCallersClaimsValidator a livello di applicazione in base a un semplice elenco di ID delle applicazioni autorizzate a chiamare la competenza. Se l'elenco contiene un asterisco (*), tutti i chiamanti sono consentiti. Il validator di attestazioni è configurato in Startup.cs.

Adapter della competenza

Quando si verifica un errore, l'adapter della competenza deve cancellare lo stato della conversazione per la competenza, nonché inviare un'attività endOfConversation al consumer di competenze. Usare la proprietà code dell'attività per segnalare che la competenza è stata terminata a causa di un errore.

EchoSkillBot\SkillAdapterWithErrorHandler.cs

private async Task HandleTurnError(ITurnContext turnContext, Exception exception)
{
    // Log any leaked exception from the application.
    _logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

    await SendErrorMessageAsync(turnContext, exception);
    await SendEoCToParentAsync(turnContext, exception);
}

private async Task SendErrorMessageAsync(ITurnContext turnContext, Exception exception)
{
    try
    {
        // Send a message to the user.
        var errorMessageText = "The skill encountered an error or bug.";
        var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
        await turnContext.SendActivityAsync(errorMessage);

        errorMessageText = "To continue to run this bot, please fix the bot source code.";
        errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
        await turnContext.SendActivityAsync(errorMessage);

        // Send a trace activity, which will be displayed in the Bot Framework Emulator.
        // Note: we return the entire exception in the value property to help the developer;
        // this should not be done in production.
        await turnContext.TraceActivityAsync("OnTurnError Trace", exception.ToString(), "https://www.botframework.com/schemas/error", "TurnError");
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught in SendErrorMessageAsync : {ex}");
    }
}

private async Task SendEoCToParentAsync(ITurnContext turnContext, Exception exception)
{
    try
    {
        // Send an EndOfConversation activity to the skill caller with the error to end the conversation,
        // and let the caller decide what to do.
        var endOfConversation = Activity.CreateEndOfConversationActivity();
        endOfConversation.Code = "SkillError";
        endOfConversation.Text = exception.Message;
        await turnContext.SendActivityAsync(endOfConversation);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, $"Exception caught in SendEoCToParentAsync : {ex}");
    }
}

Registrazione del servizio

Per la convalida dell'intestazione di autenticazione nelle richieste in arrivo, l'adapter Bot Framework usa un oggetto configurazione dell'autenticazione impostato durante la creazione dell'adapter.

In questo esempio la convalida delle attestazioni viene aggiunta alla configurazione di autenticazione e viene usato l'adapter della competenza con il gestore di errori descritto nella sezione precedente.

EchoSkillBot\Startup.cs

    options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
});

// Register AuthConfiguration to enable custom claim validation.
services.AddSingleton(sp =>
{
    var allowedCallers = new List<string>(sp.GetService<IConfiguration>().GetSection("AllowedCallers").Get<string[]>());

    var claimsValidator = new AllowedCallersClaimsValidator(allowedCallers);

    // If TenantId is specified in config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
    // The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
    var validTokenIssuers = new List<string>();
    var tenantId = sp.GetService<IConfiguration>().GetSection(MicrosoftAppCredentials.MicrosoftAppTenantIdKey)?.Value;

    if (!string.IsNullOrWhiteSpace(tenantId))
    {
        // For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
        // Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1, tenantId));
        validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2, tenantId));
    }

    return new AuthenticationConfiguration
    {
        ClaimsValidator = claimsValidator,
        ValidTokenIssuers = validTokenIssuers
    };
});

// Create the Bot Framework Authentication to be used with the Bot Adapter.
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

Manifesto della competenza

Un manifesto della competenza è un file JSON che descrive le attività eseguibili con la competenza, i relativi parametri di input e output e gli endpoint della competenza. Il manifesto contiene le informazioni necessarie per accedere alla competenza da un altro bot. La versione più recente dello schema è v2.1.

EchoSkillBot\wwwroot\manifest\echoskillbot-manifest-1.0.json

{
  "$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
  "$id": "EchoSkillBot",
  "name": "Echo Skill bot",
  "version": "1.0",
  "description": "This is a sample echo skill",
  "publisherName": "Microsoft",
  "privacyUrl": "https://echoskillbot.contoso.com/privacy.html",
  "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
  "license": "",
  "iconUrl": "https://echoskillbot.contoso.com/icon.png",
  "tags": [
    "sample",
    "echo"
  ],
  "endpoints": [
    {
      "name": "default",
      "protocol": "BotFrameworkV3",
      "description": "Default endpoint for the skill",
      "endpointUrl": "http://echoskillbot.contoso.com/api/messages",
      "msAppId": "00000000-0000-0000-0000-000000000000"
    }
  ]
}

Lo schema del manifesto della competenza è un file JSON che descrive lo schema del manifesto della competenza. La versione corrente dello schema è 2.1.0.

Testare la competenza

A questo punto è possibile testare la competenza in Emulator come se si trattasse di un normale bot. Per testarlo come una competenza, è necessario implementare un consumer di competenze.

Scaricare e installare l'ultima versione di Bot Framework Emulator

  1. Eseguire il bot della competenza echo in locale nel computer. Se sono necessarie istruzioni, vedere il file per l'esempio C#, JavaScript, Java o Python.README
  2. Usare Emulator per testare il bot come illustrato di seguito. Quando si invia un messaggio "end" o "stop" alla competenza, invia un'attività endOfConversation oltre al messaggio di risposta. La competenza invia l'attività endOfConversation per indicare che è stata terminata.

Trascrizione di esempio che mostra l'attività di fine conversazione.

Altre informazioni sul debug

Poiché il traffico tra competenze e consumer di competenze viene autenticato, è necessario eseguire passaggi aggiuntivi durante il debug di tali bot.

  • Il consumer di competenze e tutte le competenze utilizzate, direttamente o indirettamente, devono essere in esecuzione.
  • Se i bot vengono eseguiti localmente e se uno dei bot ha un ID app e una password, tutti i bot devono avere ID e password validi.
  • Se tutti i bot vengono distribuiti, vedere come eseguire il debug di un bot da qualsiasi canale usando ngrok.
  • Se alcuni bot sono in esecuzione in locale e alcuni vengono distribuiti, vedere come eseguire il debug di una competenza o di un consumer di competenze.

In caso contrario, è possibile eseguire il debug di un consumer di competenze o di una competenza in modo molto simile al debug di altri bot. Per altre informazioni, vedere Debug di un bot e Debug con Bot Framework Emulator.

Passaggi successivi