Compartilhar via


O que é um planejador?

Depois de ter vários plug-ins, você precisa de uma maneira de seu agente de IA usá-los juntos para resolver a necessidade de um usuário. É aqui que entra o planejamento.

No início, o Semantic Kernel introduziu o conceito de planejadores que usavam prompts para solicitar que a IA escolhesse quais funções invocar. Desde que o Semantic Kernel foi introduzido, no entanto, a OpenAI introduziu uma maneira nativa para o modelo invocar ou "chamar" uma função: chamada de função. Outros modelos de IA, como Gemini, Claude e Mistral, adotaram a chamada de função como um recurso principal, tornando-o um recurso compatível com vários modelos.

Devido a esses avanços, o Semantic Kernel evoluiu para usar a chamada de função como a principal maneira de planejar e executar tarefas.

Importante

A chamada de função só está disponível em modelos OpenAI 0613 ou mais recentes. Se você usar um modelo mais antigo (por exemplo, 0314), essa funcionalidade retornará um erro. Recomendamos usar os modelos OpenAI mais recentes para aproveitar esse recurso.

Como a chamada de função cria um "plano"?

Em sua forma mais simples, a chamada de função é apenas uma maneira de uma IA invocar uma função com os parâmetros corretos. Tomemos, por exemplo, um usuário deseja acender uma lâmpada. Supondo que a IA tenha o plug-in correto, ela pode chamar a função para acender a luz.

Função Mensagem
🔵Usuário Por favor, acenda a luz #1
🔴Assistente (chamada de função) Lights.change_state(1, { "isOn": true })
🟢Ferramenta { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistente A lâmpada está acesa

Mas e se o usuário não souber o ID da luz? Ou se o usuário quiser acender todas as luzes? É aqui que entra o planejamento. Os modelos LLM de hoje são capazes de chamar funções iterativamente para resolver a necessidade de um usuário. Isso é feito criando um loop de feedback onde a IA pode chamar uma função, verificar o resultado e decidir o que fazer a seguir.

Por exemplo, um usuário pode pedir à IA para "alternar" uma lâmpada. A IA precisaria primeiro verificar o estado da lâmpada antes de decidir se deve ligá-la ou desligá-la.

Função Mensagem
🔵Usuário Por favor, alterne todas as luzes
🔴Assistente (chamada de função) Lights.get_lights()
🟢Ferramenta { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] }
🔴Assistente (chamada de função) Lights.change_state(1, { "isOn": false }) Lights.change_state(2, { "isOn": true })
🟢Ferramenta { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" }
🟢Ferramenta { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistente As luzes foram alternadas

Observação

Neste exemplo, você também viu a chamada de função paralela. É aqui que a IA pode chamar várias funções ao mesmo tempo. Este é um recurso poderoso que pode ajudar a IA a resolver tarefas complexas mais rapidamente. Foi adicionado aos modelos OpenAI em 1106.

O ciclo de planejamento automático

O suporte à chamada de função sem o Kernel Semântico é relativamente complexo. Você precisaria escrever um loop que realizaria o seguinte:

  1. Criar esquemas JSON para cada uma de suas funções
  2. Forneça ao LLM o histórico de bate-papo anterior e os esquemas de função
  3. Analise a resposta do LLM para determinar se ele deseja responder com uma mensagem ou chamar uma função
  4. Se o LLM quiser chamar uma função, você precisará analisar o nome da função e os parâmetros da resposta do LLM
  5. Invocar a função com os parâmetros corretos
  6. Retorne os resultados da função para que o LLM possa determinar o que deve fazer em seguida
  7. Repita as etapas 2 a 6 até que o LLM decida que concluiu a tarefa ou precisa de ajuda do usuário

No Semantic Kernel, facilitamos o uso da chamada de função automatizando esse loop para você. Isso permite que você se concentre na criação dos plug-ins necessários para resolver as necessidades do usuário.

Observação

Entender como funciona o loop de chamada de função é essencial para criar agentes de IA confiáveis e de alto desempenho. Para obter uma visão detalhada de como o loop funciona, consulte o artigo de chamada de função.

Usando a chamada automática de função

Para usar a chamada automática de função no Kernel Semântico, você precisa fazer o seguinte:

  1. Registre o plugin com o kernel
  2. Criar um objeto de configurações de execução que informa à IA para chamar funções automaticamente
  3. Invocar o serviço de conclusão de chat com o histórico de chat e o kernel
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.functions import kernel_function
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.functions.kernel_arguments import KernelArguments

from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (
    AzureChatPromptExecutionSettings,
)

async def main():
    # 1. Create the kernel with the Lights plugin
    kernel = Kernel()
    kernel.add_service(AzureChatCompletion(
        deployment_name="your_models_deployment_name",
        api_key="your_api_key",
        base_url="your_base_url",
    ))
    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_call_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_contents(
            chat_history=history,
            settings=execution_settings,
            kernel=kernel,
            arguments=KernelArguments(),
        ))[0]

        # 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());

Quando você usa a chamada automática de função, todas as etapas no loop de planejamento automático são tratadas para você e adicionadas ao ChatHistory objeto. Depois que o loop de chamada de função for concluído, você poderá inspecionar o ChatHistory objeto para ver todas as chamadas de função feitas e os resultados fornecidos pelo Kernel Semântico.

E os planejadores de Function Calling, Stepwise e Handlebars?

Os planejadores Stepwise e Handlebars ainda estão disponíveis no Kernel Semântico. No entanto, recomendamos o uso de chamada de função para a maioria das tarefas, pois é mais poderoso e fácil de usar. Os planejadores Stepwise e Handlebars serão preteridos em uma versão futura do Kernel Semântico.

Saiba como migrar o Stepwise Planner para a Chamada Automática de Funções.

Cuidado

Se você estiver criando um novo agente de IA, recomendamos que você não use os planejadores Stepwise ou Handlebars. Em vez disso, use a chamada de função, pois é mais poderosa e fácil de usar.

Próximas etapas

Agora que você entende como os planejadores trabalham no Kernel Semântico, pode aprender mais sobre como influenciar seu agente de IA para que ele planeje e execute melhor as tarefas em nome de seus usuários.