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


Планирование

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

На ранних этапах семантическое ядро представило концепцию планировщиков, которые использовали подсказки, чтобы попросить ИИ выбрать, какие функции следует вызывать. С тех пор как было введено семантическое ядро, OpenAI, однако, представил собственный способ для модели вызывать или "вызова" функции: вызов функции. Другие модели искусственного интеллекта, такие как Gemini, Claude и Mistral, с тех пор приняли вызов функций в качестве основной функции, что делает её функцией, поддерживаемой различными моделями.

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

Это важно

Вызов функций доступен только в моделях OpenAI версии 0613 или более поздней. Если вы используете старую модель (например, 0314), эта функция вернет ошибку. Мы рекомендуем использовать последние модели OpenAI, чтобы воспользоваться этой функцией.

Как вызов функции создает «план»?

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

Должность Сообщение
🔵 пользователя Включите свет #1
🔴 помощник (вызов функции) Lights.change_state(1, { "isOn": true })
🟢 средство { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴 помощник Лампа в настоящее время включена

Но что делать, если пользователь не знает идентификатор света? Или что делать, если пользователь хочет включить все световые индикаторы? Вот здесь и требуется планирование. Современные модели LLM способны итеративно вызывать функции для решения необходимости пользователя. Это достигается путем создания цикла обратной связи, в котором ИИ может вызывать функцию, проверять результат, а затем решать, что делать дальше.

Например, пользователь может попросить ИИ переключить лампочку. ИИ сначала потребуется проверить состояние лампочки, прежде чем решить, следует ли включить или отключить его.

Должность Сообщение
🔵 пользователя Переключите все световые индикаторы
🔴 помощник (вызов функции) Lights.get_lights()
🟢 средство { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] }
🔴 помощник (вызов функции) Lights.change_state(1, { "isOn": false }) Lights.change_state(2, { "isOn": true })
🟢 средство { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" }
🟢 средство { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴 помощник Свет был переключлен

Замечание

В этом примере вы также увидели параллельные вызовы функций. В этом случае ИИ может одновременно вызывать несколько функций. Это мощная функция, которая помогает ИИ решать сложные задачи быстрее. Он был добавлен в модели OpenAI в 1106 году.

Цикл автоматического планирования

Поддержка вызова функций без семантического ядра является относительно сложным. Необходимо написать цикл, который будет выполнять следующие действия:

  1. Создание схем JSON для каждой функции
  2. Предоставьте LLM предыдущую историю чата и схемы функций.
  3. Выполните анализ ответа LLM, чтобы определить, хочет ли он предоставить сообщение или вызвать функцию
  4. Если LLM хочет вызвать функцию, необходимо проанализировать имя функции и параметры из ответа LLM.
  5. Вызов функции с правильными параметрами
  6. Возвращает результаты функции, чтобы LLM смог определить, что он должен делать дальше.
  7. Повторите шаги 2-6, пока LLM не решит, что она завершит задачу или нуждается в помощи от пользователя

В семантическом ядре мы упрощаем вызов функции, автоматизовав этот цикл для вас. Это позволяет сосредоточиться на создании подключаемых модулей, необходимых для решения потребностей пользователя.

Замечание

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

Использование автоматического вызова функции

Чтобы использовать автоматический вызов функции в семантической ядре, необходимо выполнить следующее:

  1. Регистрация подключаемого модуля в ядре
  2. Создание объекта параметров выполнения, который сообщает ИИ автоматически вызывать функции
  3. Вызовите службу завершения чата, используя журнал чата и ядро.

Подсказка

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

using System.ComponentModel;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;

// 1. Create the kernel with the Lights plugin
var builder = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion(modelId, endpoint, apiKey);
builder.Plugins.AddFromType<LightsPlugin>("Lights");
Kernel kernel = builder.Build();

var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

// 2. Enable automatic function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new() 
{
    FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};

var history = new ChatHistory();

string? userInput;
do {
    // Collect user input
    Console.Write("User > ");
    userInput = Console.ReadLine();

    // Add user input
    history.AddUserMessage(userInput);

    // 3. Get the response from the AI with automatic function calling
    var result = await chatCompletionService.GetChatMessageContentAsync(
        history,
        executionSettings: openAIPromptExecutionSettings,
        kernel: kernel);

    // Print the results
    Console.WriteLine("Assistant > " + result);

    // Add the message from the agent to the chat history
    history.AddMessage(result.Role, result.Content ?? string.Empty);
} while (userInput is not null)
import asyncio

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.connectors.ai.open_ai import (
    AzureChatCompletion,
    AzureChatPromptExecutionSettings,
)
from semantic_kernel.contents import ChatHistory
from semantic_kernel.functions import kernel_function

async def main():
    # 1. Create the kernel with the Lights plugin
    kernel = Kernel()
    kernel.add_service(AzureChatCompletion())
    kernel.add_plugin(
        LightsPlugin(),
        plugin_name="Lights",
    )

    chat_completion: AzureChatCompletion = kernel.get_service(type=ChatCompletionClientBase)

    # 2. Enable automatic function calling
    execution_settings = AzureChatPromptExecutionSettings()
    execution_settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

    # Create a history of the conversation
    history = ChatHistory()

    userInput = None
    while True:
        # Collect user input
        userInput = input("User > ")

        # Terminate the loop if the user says "exit"
        if userInput == "exit":
            break

        # Add user input to the history
        history.add_user_message(userInput)

        # 3. Get the response from the AI with automatic function calling
        result = await chat_completion.get_chat_message_content(
            chat_history=history,
            settings=execution_settings,
            kernel=kernel,
        )

        # Print the results
        print("Assistant > " + str(result))

        # Add the message from the agent to the chat history
        history.add_message(result)

# Run the main function
if __name__ == "__main__":
    asyncio.run(main())

    OpenAIAsyncClient client = new OpenAIClientBuilder()
        .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
        .endpoint(CLIENT_ENDPOINT)
        .buildAsyncClient();

    // Import the LightsPlugin
    KernelPlugin lightPlugin = KernelPluginFactory.createFromObject(new LightsPlugin(),
        "LightsPlugin");

    // Create your AI service client
    ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder()
        .withModelId(MODEL_ID)
        .withOpenAIAsyncClient(client)
        .build();

    // Create a kernel with Azure OpenAI chat completion and plugin
    Kernel kernel = Kernel.builder()
        .withAIService(ChatCompletionService.class, chatCompletionService)
        .withPlugin(lightPlugin)
        .build();

    // Add a converter to the kernel to show it how to serialise LightModel objects into a prompt
    ContextVariableTypes
        .addGlobalConverter(
            ContextVariableTypeConverter.builder(LightModel.class)
                .toPromptString(new Gson()::toJson)
                .build());

    // Enable planning
    InvocationContext invocationContext = new InvocationContext.Builder()
        .withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY)
        .withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
        .build();

    // Create a history to store the conversation
    ChatHistory history = new ChatHistory();

    // Initiate a back-and-forth chat
    Scanner scanner = new Scanner(System.in);
    String userInput;
    do {
      // Collect user input
      System.out.print("User > ");

      userInput = scanner.nextLine();
      // Add user input
      history.addUserMessage(userInput);

      // Prompt AI for response to users input
      List<ChatMessageContent<?>> results = chatCompletionService
          .getChatMessageContentsAsync(history, kernel, invocationContext)
          .block();

      for (ChatMessageContent<?> result : results) {
        // Print the results
        if (result.getAuthorRole() == AuthorRole.ASSISTANT && result.getContent() != null) {
          System.out.println("Assistant > " + result);
        }
        // Add the message from the agent to the chat history
        history.addMessage(result);
      }
    } while (userInput != null && !userInput.isEmpty());

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

Что случилось с планировщиками Stepwise и Handlebars?

Планировщики stepwise и Handlebars устарели и удалены из пакета семантического ядра. Эти планировщики больше не поддерживаются в Python, .NET или Java.

Мы рекомендуем использовать вызов функции, который является более мощным и удобным для большинства сценариев.

Чтобы обновить существующие решения, следуйте нашему руководству по пошаговой миграции планировщика.

Подсказка

Для новых агентов ИИ используйте вызов функции вместо устаревших планировщиков. Он обеспечивает более высокую гибкость, поддержку встроенных средств и более простой возможности разработки.

Дальнейшие шаги

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