Compartilhar via


Implementar um skill

APLICA-SE A: SDK v4

Você pode usar skills para estender outro bot. Um skill é um bot que pode executar um conjunto de tarefas para outro bot.

  • Um manifesto descreve a interface de uma habilidade. Os desenvolvedores que não têm acesso ao código-fonte do skill podem usar as informações do manifesto para criar um consumidor de skill.
  • Um skill pode usar a validação de declarações para gerenciar quais bots ou usuários podem acessá-lo.

Este artigo demonstra como implementar um skill que ecoa a entrada do usuário.

Alguns tipos de consumidores de habilidades não podem usar alguns tipos de bots de habilidades. A tabela a seguir descreve quais combinações são compatíveis.

  Habilidade de multilocatário Habilidade de locatário único Habilidade de identidade gerenciada atribuída pelo usuário
Consumidor de multilocatário Com suporte Sem suporte Sem suporte
Consumidor de locatário único Sem suporte Compatível se ambos os aplicativos pertencerem ao mesmo locatário Compatível se ambos os aplicativos pertencerem ao mesmo locatário
Consumidor de identidade gerenciada atribuída pelo usuário Sem suporte Compatível se ambos os aplicativos pertencerem ao mesmo locatário Compatível se ambos os aplicativos pertencerem ao mesmo locatário

Observação

Os SDKs JavaScript, C# e Python do Bot Framework continuarão a ser compatíveis. No entanto, o SDK Java está sendo desativado, com o suporte final de longo prazo terminando em novembro de 2023.

Os bots existentes criados com o SDK para Java continuarão a funcionar.

Para a criação de novos bots, considere usar o Microsoft Copilot Studio e leia sobre como escolher a solução de copiloto certa.

Para obter mais informações, confira O futuro da criação de bots.

Pré-requisitos

Observação

A partir da versão 4.11, você não precisa de um ID do aplicativo e senha para testar uma habilidade localmente no Bot Framework Emulator. Uma assinatura do Azure ainda é necessária para implantar sua habilidade no Azure.

Sobre este exemplo

O exemplo bot para bot de skills simples inclui projetos para dois bots:

  • O bot skill de eco, que implementa o skill.
  • O bot raiz simples, que implementa um bot raiz que consome o skill.

Este artigo se concentra no skill, que inclui a lógica de suporte em seu bot e adaptador.

Para obter informações sobre o bot raiz simples, consulte como Implementar um consumidor de skills.

Recursos

Para bots implantados, a autenticação de bot para bot exige que cada bot participante tenha informações de identidade válidas. No entanto, você pode testar habilidades multilocatários e consumidores de habilidades localmente com o Emulador sem uma ID de aplicativo e senha.

Para disponibilizar a habilidade para bots voltados para o usuário, registre a habilidade no Azure. Para obter mais informações, confira como registrar um bot no Serviço de Bot de IA do Azure.

Configuração de aplicativo

Opcionalmente, adicione as informações de identidade da habilidade ao seu arquivo de configuração. Se a habilidade ou o consumidor de habilidade fornecer informações de identidade, ambos deverão fazê-lo.

A matriz de chamadores permitidos pode restringir quais consumidores de skills podem acessar o skill. Para aceitar chamadas de qualquer consumidor de habilidade, adicione um elemento "*".

Observação

Se você estiver testando sua habilidade localmente sem informações de identidade do bot, nem a habilidade nem o consumidor da habilidade executarão o código para realizar a validação de declarações.

EchoSkillBot\appsettings.json

Opcionalmente, adicione as informações de identidade da habilidade ao arquivo 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": [ "*" ]
}

Lógica do manipulador de atividades

Para aceitar parâmetros de entrada

O consumidor de skills pode enviar informações para o skill. Uma maneira de aceitar essas informações é aceitá-las por meio da propriedade valor em mensagens de entrada. Outra maneira é manipular atividades de evento e invocação.

A habilidade neste exemplo não aceita parâmetros de entrada.

Para continuar ou concluir uma conversa

Quando o skill envia uma atividade, o consumidor de skills deve encaminhar a atividade para o usuário.

No entanto, você precisa enviar uma endOfConversation atividade quando a habilidade for concluída; caso contrário, o consumidor da habilidade continuará a encaminhar as atividades do usuário para a habilidade. Opcionalmente, use a propriedade valor da atividade para incluir um valor retornado e use a propriedade código da atividade para indicar por que o skill está terminando.

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);
    }
}

Para cancelar o skill

Para skills de vários ciclos, você também aceitará atividades endOfConversation de um consumidor de skills, para permitir que o consumidor cancele a conversa atual.

A lógica dessa habilidade não muda de turno para turno. Se você implementar um skill que aloque recursos de conversa, adicione o código de limpeza de recurso ao manipulador de fim de conversa.

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;
}

Validador de declarações

Este exemplo usa uma lista de chamadores permitidos para validação de declarações. O arquivo de configuração da habilidade define a lista. O objeto validador então lê a lista.

Você deve adicionar um validador de declarações à configuração de autenticação. As declarações são avaliadas após o cabeçalho de autenticação. O código de validação deve gerar um erro ou uma exceção para rejeitar a solicitação. Há muitos motivos pelos quais você pode querer rejeitar uma solicitação autenticada de outra forma. Por exemplo:

  • O skill faz parte de um serviço pago. Os usuários que não estão no banco de dados não devem ter acesso.
  • O skill é proprietário. Somente determinados consumidores de skills podem chamar o skill.

Importante

Se você não fornecer um validador de declarações, seu bot gerará um erro ou uma exceção ao receber uma atividade do consumidor de habilidade.

O SDK fornece uma classe AllowedCallersClaimsValidator que adiciona autorização em nível de aplicativo com base em uma lista simples de IDs dos aplicativos que têm permissão para chamar a habilidade. Se a lista contiver um asterisco (*), todos os chamadores serão permitidos. O validador de declarações é configurado em Startup.cs.

Adaptador de skill

Quando ocorre um erro, o adaptador do skill deve limpar o estado da conversa para o skill e também deve enviar uma atividade endOfConversation para o consumidor de skills. Para sinalizar que a habilidade foi encerrada devido a um erro, use a propriedade code da atividade.

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}");
    }
}

Registro do serviço

O adaptador do Bot Framework usa um objeto de configuração de autenticação (definido quando o adaptador é criado) para validar o cabeçalho de autenticação em solicitações de entrada.

Este exemplo adiciona validação de declarações à configuração de autenticação e usa o adaptador de habilidade com o manipulador de erros descrito na seção anterior.

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 de skills

Um manifesto de skill é um arquivo JSON que descreve as atividades que o skill pode executar, seus parâmetros de entrada e saída e os pontos de extremidade do skill. O manifesto contém as informações necessárias para acessar o skill por meio de outro bot. A versão mais recente do esquema é a 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"
    }
  ]
}

O esquema de manifesto do skill é um arquivo JSON que descreve o esquema do manifesto de skill. A versão atual do esquema é 2.1.0.

Testar o skill

Neste ponto, você pode testar o skill no Emulador como se fosse um bot normal. No entanto, para testá-lo como um skill, você precisaria implementar um consumidor de skills.

Baixe e instale o Bot Framework Emulator mais recente

  1. Execute o bot skill de eco localmente em seu computador. Se precisar de instruções, confira o arquivo README do exemplo em C#, JavaScript, Java ou Python.
  2. Use o Emulador para testar o bot. Quando você envia uma mensagem de "fim" ou "parada" para a habilidade, ela envia uma atividade endOfConversation além da mensagem de resposta. A habilidade envia a endOfConversation atividade para indicar que a habilidade foi concluída.

Exemplo de transcrição mostrando a atividade de fim de conversa.

Mais sobre depuração

Como o tráfego entre as habilidades e os consumidores de habilidades é autenticado, há etapas adicionais na depuração desses bots.

  • O consumidor de habilidades e todas as habilidades que ele consome, direta ou indiretamente, devem estar em execução.
  • Se os bots estiverem sendo executados localmente e se algum dos bots tiver um ID do aplicativo e uma senha, então todos os bots deverão ter IDs e senhas válidos.
  • Se todos os bots estiverem implantados, veja como depurar um bot de qualquer canal usando devtunnel.
  • Se alguns dos bots estiverem sendo executados localmente e alguns estiverem implantados, confira como Depurar uma habilidade ou um consumidor de habilidades.

Caso contrário, você poderá depurar um consumidor de habilidades ou uma habilidade da mesma forma como você depura outros bots. Para obter mais informações, confira Depurar um bot e Depurar com o Bot Framework Emulator.

Próximas etapas