Поделиться через


Возможности библиотеки ИИ Teams

Библиотека ИИ Teams поддерживает JavaScript и предназначена для упрощения процесса создания ботов, которые могут взаимодействовать с Microsoft Teams, и упрощает миграцию существующих ботов. Библиотека ИИ поддерживает перенос возможностей обмена сообщениями, возможностей расширения сообщений (ME) и адаптивных карточек в новый формат. С помощью этих функций можно также обновить существующие приложения Teams.

Ранее вы использовали пакет SDK BotBuilder непосредственно для создания ботов для Microsoft Teams. Библиотека ИИ Teams предназначена для упрощения создания ботов, которые могут взаимодействовать с Microsoft Teams. Хотя одной из ключевых функций библиотеки ИИ Teams является поддержка ИИ, которую клиенты могут использовать, начальной целью может быть обновление текущего бота без ИИ. После обновления бот может подключаться к ИИ или крупным языковым моделям (LLM), доступным в библиотеке ИИ.

Библиотека ИИ Teams поддерживает следующие возможности:

Необходимо использовать библиотеку ИИ для формирования шаблонов бота и обработчиков адаптивных карточек в исходный файл.

В следующем разделе мы использовали примеры из библиотеки ИИ , чтобы объяснить каждую возможность и путь к миграции:

Отправка или получение сообщения

Вы можете отправлять и получать сообщения с помощью Bot Framework. Приложение прослушивает отправку пользователем сообщения, а при получении этого сообщения удаляет состояние беседы и отправляет сообщение обратно пользователю. Приложение также отслеживает количество сообщений, полученных в беседе, и повторяет сообщение пользователя с количеством полученных сообщений.

 // Listen for user to say "/reset" and then delete conversation state
    app.OnMessage("/reset", ActivityHandlers.ResetMessageHandler);

    // Listen for ANY message to be received. MUST BE AFTER ANY OTHER MESSAGE HANDLERS
    app.OnActivity(ActivityTypes.Message, ActivityHandlers.MessageHandler);

    return app;

Расширения для обмена сообщениями

В пакете SDK TeamsActivityHandlerBot Framework необходимо настроить обработчик запросов расширений сообщений, расширив методы обработчика. Приложение прослушивает действия поиска и касания элементов и форматирует результаты поиска в виде списка HeroCards, отображающих сведения о пакете. Результат используется для отображения результатов поиска в расширении обмена сообщениями.

// Listen for search actions
    app.MessageExtensions.OnQuery("searchCmd", activityHandlers.QueryHandler);
    // Listen for item tap
    app.MessageExtensions.OnSelectItem(activityHandlers.SelectItemHandler);

    return app;

 // Format search results in ActivityHandlers.cs

            List<MessagingExtensionAttachment> attachments = packages.Select(package => new MessagingExtensionAttachment
            {
                ContentType = HeroCard.ContentType,
                Content = new HeroCard
                {
                    Title = package.Id,
                    Text = package.Description
                },
                Preview = new HeroCard
                {
                    Title = package.Id,
                    Text = package.Description,
                    Tap = new CardAction
                    {
                        Type = "invoke",
                        Value = package
                    }
                }.ToAttachment()
            }).ToList();

            // Return results as a list

            return new MessagingExtensionResult
            {
                Type = "result",
                AttachmentLayout = "list",
                Attachments = attachments
            };

Возможности адаптивных карточек

Обработчики действий адаптивной карточки app.adaptiveCards можно зарегистрировать с помощью свойства . Приложение прослушивает сообщения с ключевыми словами static или dynamic и возвращает адаптивную карточку StaticMessageHandler с помощью методов или DynamicMessageHandler . Приложение также прослушивает запросы из динамического карта поиска, кнопки отправки на адаптивных карточках.

// Listen for messages that trigger returning an adaptive card
    app.OnMessage(new Regex(@"static", RegexOptions.IgnoreCase), activityHandlers.StaticMessageHandler);
    app.OnMessage(new Regex(@"dynamic", RegexOptions.IgnoreCase), activityHandlers.DynamicMessageHandler);

    // Listen for query from dynamic search card
    app.AdaptiveCards.OnSearch("nugetpackages", activityHandlers.SearchHandler);
    // Listen for submit buttons
    app.AdaptiveCards.OnActionSubmit("StaticSubmit", activityHandlers.StaticSubmitHandler);
    app.AdaptiveCards.OnActionSubmit("DynamicSubmit", activityHandlers.DynamicSubmitHandler);

    // Listen for ANY message to be received. MUST BE AFTER ANY OTHER HANDLERS
    app.OnActivity(ActivityTypes.Message, activityHandlers.MessageHandler);

    return app;

Основные возможности

Логика бота для обработки действия

Бот реагирует на входные данные пользователя действием LightsOn по включению света.

В следующем примере показано, как библиотека ИИ Teams позволяет управлять логикой бота для обработки действия LightsOn или LightsOff подключать ее к запросу, используемому с OpenAI:

/ Create AI Model
if (!string.IsNullOrEmpty(config.OpenAI?.ApiKey))
{
    builder.Services.AddSingleton<OpenAIModel>(sp => new(
        new OpenAIModelOptions(config.OpenAI.ApiKey, "gpt-3.5-turbo")
        {
            LogRequests = true
        },
        sp.GetService<ILoggerFactory>()
    ));
}
else if (!string.IsNullOrEmpty(config.Azure?.OpenAIApiKey) && !string.IsNullOrEmpty(config.Azure.OpenAIEndpoint))
{
    builder.Services.AddSingleton<OpenAIModel>(sp => new(
        new AzureOpenAIModelOptions(
            config.Azure.OpenAIApiKey,
            "gpt-35-turbo",
            config.Azure.OpenAIEndpoint
        )
        {
            LogRequests = true
        },
        sp.GetService<ILoggerFactory>()
    ));
}
else
{
    throw new Exception("please configure settings for either OpenAI or Azure");
}

// Create the bot as transient. In this case the ASP Controller is expecting an IBot.
builder.Services.AddTransient<IBot>(sp =>
{
    // Create loggers
    ILoggerFactory loggerFactory = sp.GetService<ILoggerFactory>()!;

    // Create Prompt Manager
    PromptManager prompts = new(new()
    {
        PromptFolder = "./Prompts"
    });

    // Adds function to be referenced in the prompt template
    prompts.AddFunction("getLightStatus", async (context, memory, functions, tokenizer, args) =>
    {
        bool lightsOn = (bool)(memory.GetValue("conversation.lightsOn") ?? false);
        return await Task.FromResult(lightsOn ? "on" : "off");
    });

    // Create ActionPlanner
    ActionPlanner<AppState> planner = new(
        options: new(
            model: sp.GetService<OpenAIModel>()!,
            prompts: prompts,
            defaultPrompt: async (context, state, planner) =>
            {
                PromptTemplate template = prompts.GetPrompt("sequence");
                return await Task.FromResult(template);
            }
        )
        { LogRepairs = true },
        loggerFactory: loggerFactory
    );

    return new TeamsLightBot(new()
    {
        Storage = sp.GetService<IStorage>(),
        AI = new(planner),
        LoggerFactory = loggerFactory,
        TurnStateFactory = () =>
        {
            return new AppState();
        }
    });
});

// LightBotActions defined in LightBotActions.cs
    
[Action("LightsOn")]
        public async Task<string> LightsOn([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState)
        {
            turnState.Conversation.LightsOn = true;
            await turnContext.SendActivityAsync(MessageFactory.Text("[lights on]"));
            return "the lights are now on";
        }

        [Action("LightsOff")]
        public async Task<string> LightsOff([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState)
        {
            turnState.Conversation.LightsOn = false;
            await turnContext.SendActivityAsync(MessageFactory.Text("[lights off]"));
            return "the lights are now off";
        }

        [Action("Pause")]
        public async Task<string> LightsOff([ActionTurnContext] ITurnContext turnContext, [ActionParameters] Dictionary<string, object> args)
        {
            // Try to parse entities returned by the model.
            // Expecting "time" to be a number of milliseconds to pause.
            if (args.TryGetValue("time", out object? time))
            {
                if (time != null && time is string timeString)
                {
                    if (int.TryParse(timeString, out int timeInt))
                    {
                        await turnContext.SendActivityAsync(MessageFactory.Text($"[pausing for {timeInt / 1000} seconds]"));
                        await Task.Delay(timeInt);
                    }
                }
            }

            return "done pausing";
        }

Запрос расширения сообщений

Библиотека ИИ Teams предлагает более интуитивно понятный подход к созданию обработчиков для различных команд запросов расширения сообщений по сравнению с предыдущими итерациями пакета SDK Для Teams Bot Framework. Новый пакет SDK работает вместе с существующим пакетом SDK Для Teams Bot Framework.

Ниже приведен пример того, как можно структурировать код для обработки запроса расширения сообщений для searchCmd команды .

// Listen for search actions
    app.MessageExtensions.OnQuery("searchCmd", activityHandlers.QueryHandler);
    // Listen for item tap
    app.MessageExtensions.OnSelectItem(activityHandlers.SelectItemHandler);

    return app;

 // Format search results
            List<MessagingExtensionAttachment> attachments = packages.Select(package => new MessagingExtensionAttachment
            {
                ContentType = HeroCard.ContentType,
                Content = new HeroCard
                {
                    Title = package.Id,
                    Text = package.Description
                },
                Preview = new HeroCard
                {
                    Title = package.Id,
                    Text = package.Description,
                    Tap = new CardAction
                    {
                        Type = "invoke",
                        Value = package
                    }
                }.ToAttachment()
            }).ToList();

            return new MessagingExtensionResult
            {
                Type = "result",
                AttachmentLayout = "list",
                Attachments = attachments
            };

Намерения действий

Простой интерфейс для действий и прогнозов позволяет ботам реагировать, когда они имеют высокую уверенность в принятии действий. Внешнее присутствие позволяет ботам изучать намерения, использовать запросы на основе бизнес-логики и генерировать ответы.

Благодаря нашей библиотеке ИИ в запросе нужно только очертить действия, поддерживаемые ботом, и предоставить несколько примеров использования этих действий. Журнал бесед помогает в естественном диалоге между пользователем и ботом, например добавить хлопья в список продуктов, а затем добавить кофе, который должен указывать, что кофе должен быть добавлен в список продуктов.

Ниже приведен диалог с помощник ИИ. Помощник ИИ может управлять списками и распознает следующие команды:

  • ДЕЛАТЬ <action> <optional entities>
  • СКАЗАТЬ <response>

Поддерживаются следующие действия:

  • addItem list="<list name>" item="<text>"
  • removeItem list="<list name>" item="<text>"
  • summarizeLists

Все сущности являются обязательными параметрами для действий.

  • Имена текущих списков:

    {{conversation.listNames}} 
    
    
    Examples:  
    
    Human: remind me to buy milk
    AI: DO addItem list="groceries" item="milk" THEN SAY Ok I added milk to your groceries list
    Human: we already have milk
    AI: DO removeItem list="groceries" item="milk" THEN SAY Ok I removed milk from your groceries list
    Human: buy ingredients to make margaritas
    AI: DO addItem list="groceries" item="tequila" THEN DO addItem list="groceries" item="orange liqueur" THEN DO addItem list="groceries" item="lime juice" THEN SAY Ok I added tequila, orange liqueur, and lime juice to your groceries list
    Human: do we have have milk
    AI: DO findItem list="groceries" item="milk"
    Human: what's in my grocery list
    AI: DO summarizeLists  
    Human: what's the contents of all my lists?
    AI: DO summarizeLists
    Human: show me all lists but change the title to Beach Party
    AI: DO summarizeLists
    Human: show me all lists as a card and sort the lists alphabetically
    AI: DO summarizeLists
    
    
  • Журнал бесед:

    {{conversation.(history}} 
    
  • Текущий запрос:

    Human: {{activity.text}} 
    
  • Имена текущих списков:

    {{conversation.listNames}}
    
  • ИИ. Логика бота оптимизирована для включения обработчиков для таких действий, как addItem и removeItem. Это четкое разделение между действиями и запросами, помогающее ИИ выполнять действия и запросы, служит мощным инструментом.

        [Action("AddItem")]
        public string AddItem([ActionTurnState] ListState turnState, [ActionParameters] Dictionary<string, object> parameters)
        {
            ArgumentNullException.ThrowIfNull(turnState);
            ArgumentNullException.ThrowIfNull(parameters);

            string listName = GetParameterString(parameters, "list");
            string item = GetParameterString(parameters, "item");

            IList<string> items = GetItems(turnState, listName);
            items.Add(item);
            SetItems(turnState, listName, items);

            return "item added. think about your next action";
        }

        [Action("RemoveItem")]
        public async Task<string> RemoveItem([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] ListState turnState, [ActionParameters] Dictionary<string, object> parameters)
        {
            ArgumentNullException.ThrowIfNull(turnContext);
            ArgumentNullException.ThrowIfNull(turnState);
            ArgumentNullException.ThrowIfNull(parameters);

            string listName = GetParameterString(parameters, "list");
            string item = GetParameterString(parameters, "item");

            IList<string> items = GetItems(turnState, listName);

            if (!items.Contains(item))
            {
                await turnContext.SendActivityAsync(ResponseBuilder.ItemNotFound(listName, item)).ConfigureAwait(false);
                return "item not found. think about your next action";
            }

            items.Remove(item);
            SetItems(turnState, listName, items);
            return "item removed. think about your next action";
        }

Следующее действие