Condividi tramite


Che cos'è un Planner?

Dopo aver creato più plug-in, è necessario un modo per consentire all'agente di intelligenza artificiale di usarli insieme per risolvere le esigenze di un utente. È qui che entra in gioco la pianificazione.

Nelle prime fasi, il kernel semantico ha introdotto il concetto di planner che usava richieste di richiedere all'intelligenza artificiale di scegliere le funzioni da richiamare. Poiché il kernel semantico è stato introdotto, Tuttavia, OpenAI ha introdotto un modo nativo per il modello di richiamare o "chiamare" una funzione: chiamata di funzione. Altri modelli di intelligenza artificiale come Gemini, Claude e Mistral hanno adottato la chiamata di funzione come funzionalità di base, rendendola una funzionalità supportata tra modelli.

A causa di questi progressi, il kernel semantico si è evoluto per usare la chiamata di funzione come metodo principale per pianificare ed eseguire attività.

Importante

La chiamata a funzioni è disponibile solo nei modelli OpenAI 0613 o versioni successive. Se si usa un modello meno recente ,ad esempio 0314, questa funzionalità restituirà un errore. È consigliabile usare i modelli OpenAI più recenti per sfruttare questa funzionalità.

Come funziona la chiamata a creare un "piano"?

Al suo modo più semplice, la chiamata di funzione è semplicemente un modo per richiamare una funzione con i parametri corretti. Si supponga, ad esempio, che un utente voglia attivare una lampadina. Supponendo che l'intelligenza artificiale abbia il plug-in corretto, può chiamare la funzione per accendere la luce.

Ruolo Message
🔵Utente Attivare la luce n. 1
🔴Assistente (chiamata di funzione) Lights.change_state(1, { "isOn": true })
🟢Strumento { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistente La lampada è ora attiva

Ma cosa succede se l'utente non conosce l'ID della luce? O se l'utente vuole accendere tutte le luci? È qui che entra in gioco la pianificazione. I modelli LLM di oggi sono in grado di chiamare in modo iterativo le funzioni per risolvere le esigenze di un utente. Questa operazione viene eseguita creando un ciclo di feedback in cui l'intelligenza artificiale può chiamare una funzione, controllare il risultato e quindi decidere cosa fare successivamente.

Ad esempio, un utente può chiedere all'intelligenza artificiale di attivare o disattivare una lampadina. L'intelligenza artificiale deve prima controllare lo stato della lampadina prima di decidere se attivarla o disattivarla.

Ruolo Message
🔵Utente Per favore, attiva/disattiva tutte le luci
🔴Assistente (chiamata di funzione) Lights.get_lights()
🟢Strumento { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] }
🔴Assistente (chiamata di funzione) Lights.change_state(1, { "isOn": false }) Lights.change_state(2, { "isOn": true })
🟢Strumento { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" }
🟢Strumento { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistente Le luci sono state attivate

Nota

In questo esempio è stata visualizzata anche la chiamata di funzioni parallele. Questo è il punto in cui l'intelligenza artificiale può chiamare più funzioni contemporaneamente. Si tratta di una funzionalità potente che può aiutare l'IA a risolvere più rapidamente attività complesse. È stato aggiunto ai modelli OpenAI nel 1106.

Ciclo di pianificazione automatica

Il supporto della chiamata di funzione senza semantic kernel è relativamente complesso. È necessario scrivere un ciclo che consenta di eseguire le operazioni seguenti:

  1. Creare schemi JSON per ognuna delle funzioni
  2. Specificare l'LLM con la cronologia delle chat e gli schemi di funzione precedenti
  3. Analizzare la risposta dell'LLM per determinare se vuole rispondere con un messaggio o chiamare una funzione
  4. Se l'LLM vuole chiamare una funzione, è necessario analizzare il nome e i parametri della funzione dalla risposta LLM
  5. Richiamare la funzione con i parametri corretti
  6. Restituire i risultati della funzione in modo che l'LLM possa determinare le operazioni da eseguire successivamente
  7. Ripetere i passaggi da 2 a 6 fino a quando l'LLM non decide di aver completato l'attività o ha bisogno di assistenza da parte dell'utente

Nel kernel semantico, è facile usare la chiamata di funzione automatizzando automaticamente questo ciclo. In questo modo è possibile concentrarsi sulla creazione dei plug-in necessari per risolvere le esigenze dell'utente.

Nota

Comprendere il funzionamento del ciclo di chiamata delle funzioni è essenziale per la creazione di agenti di intelligenza artificiale efficienti e affidabili. Per un'analisi approfondita del funzionamento del ciclo, vedere l'articolo sulle chiamate di funzione.

Uso della chiamata automatica delle funzioni

Per usare la chiamata automatica della funzione in Semantic Kernel, è necessario eseguire le operazioni seguenti:

  1. Registrare il plug-in con il kernel
  2. Creare un oggetto impostazioni di esecuzione che indica all'intelligenza artificiale di chiamare automaticamente le funzioni
  3. Richiamare il servizio di completamento della chat con la cronologia delle chat e il 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 si usa la chiamata automatica delle funzioni, tutti i passaggi del ciclo di pianificazione automatica vengono gestiti automaticamente e aggiunti all'oggetto ChatHistory . Al termine del ciclo di chiamata della funzione, è possibile esaminare l'oggetto ChatHistory per visualizzare tutte le chiamate di funzione effettuate e i risultati forniti dal kernel semantico.

Che cos'è la funzione che chiama stepwise e handlebars planner?

I planner stepwise e handlebars sono ancora disponibili nel kernel semantico. Tuttavia, è consigliabile usare la chiamata di funzione per la maggior parte delle attività perché è più potente e più facile da usare. Gli planner Stepwise e Handlebars saranno deprecati in una versione futura del kernel semantico.

Informazioni su come eseguire la migrazione di Stepwise Planner alla chiamata automatica delle funzioni.

Attenzione

Se si sta creando un nuovo agente di intelligenza artificiale, è consigliabile non usare gli planner Stepwise o Handlebars. Usare invece una funzione che chiama così come è più potente e più facile da usare.

Passaggi successivi

Ora che si comprende come funzionano i planner nel kernel semantico, è possibile ottenere altre informazioni sull'influenza dell'agente di intelligenza artificiale in modo che pianino e eseseguono attività per conto degli utenti.