Compartilhar via


Implementar uma habilidade

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 da habilidade podem usar as informações do manifesto para criar um consumidor da habilidade.
  • 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 usuários de habilidades não podem usar alguns tipos de robôs de habilidade. 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 multilocatário Compatível 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

Para criar agentes com sua escolha de serviços de IA, orquestração e conhecimento, considere usar o SDK do Microsoft 365 Agents. O SDK de Agentes tem suporte para C#, JavaScript ou Python. Você pode saber mais sobre o SDK de Agentes em aka.ms/agents. Se você estiver procurando uma plataforma de agente baseada em SaaS, considere o Microsoft Copilot Studio. Se você tiver um bot existente criado com o SDK do Bot Framework, poderá atualizar o bot para o SDK de Agentes. Você pode examinar as principais alterações e atualizações nas orientações de migração do SDK do Bot Framework para o SDK do Agents. Os tíquetes de suporte para o SDK do Bot Framework não serão mais atendidos a partir de 31 de dezembro de 2025.

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 as habilidades de multilocatários e os consumidores de habilidades localmente com o Emulator sem um ID do 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 usuário 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.jsligado

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 atividade endOfConversation 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 usuário da 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 coce 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 Habilidades

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.jsligado

{
  "$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 do manifesto da habilidade é um arquivo JSON que descreve o esquema do manifesto da habilidade. A versão atual do esquema é 2.1.0.

Testar a habilidade

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

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 atividade endOfConversation 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.
  • Depois que todos os bots estiverem implantados, saiba 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