Delen via


Wat is een Planner?

Zodra u meerdere invoegtoepassingen hebt, hebt u een manier nodig voor uw AI-agent om deze samen te gebruiken om de behoeften van een gebruiker op te lossen. Dit is waar de planning binnenkomt.

Vroeg in de Semantische Kernel werd het concept van planners geïntroduceerd waarin prompts werden gebruikt om de AI aan te vragen om te kiezen welke functies moeten worden aangeroepen. Sinds Semantic Kernel is geïntroduceerd, heeft OpenAI echter een systeemeigen manier geïntroduceerd voor het model om een functie aan te roepen of aan te roepen: functieoproepen. Andere AI-modellen, zoals Gemini, Claude en Mistral, hebben sindsdien functie aanroepen als kernmogelijkheid aangenomen, waardoor het een functie die door meerdere modellen wordt ondersteund.

Vanwege deze ontwikkelingen is Semantische kernel ontwikkeld om functie-aanroepen te gebruiken als de primaire manier om taken te plannen en uit te voeren.

Belangrijk

Functie aanroepen is alleen beschikbaar in OpenAI-modellen die 0613 of hoger zijn. Als u een ouder model gebruikt (bijvoorbeeld 0314), retourneert deze functionaliteit een fout. U wordt aangeraden de nieuwste OpenAI-modellen te gebruiken om te profiteren van deze functie.

Hoe maakt functie-aanroepen een 'plan'?

Het eenvoudigst is het aanroepen van functies slechts een manier voor een AI om een functie aan te roepen met de juiste parameters. Neem bijvoorbeeld een gebruiker die een gloeilamp wil inschakelen. Ervan uitgaande dat de AI de juiste invoegtoepassing heeft, kan deze de functie aanroepen om het licht in te schakelen.

Role Bericht
🔵Gebruiker Schakel het licht in #1
🔴Assistent (functieoproep) Lights.change_state(1, { "isOn": true })
🟢Tool { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistent De lamp is nu ingeschakeld

Maar wat als de gebruiker de id van het licht niet weet? Of wat als de gebruiker alle lichten wil inschakelen? Dit is waar de planning binnenkomt. De LLM-modellen van vandaag kunnen iteratief functies aanroepen om de behoeften van een gebruiker op te lossen. Dit wordt bereikt door een feedbacklus te maken waarin de AI een functie kan aanroepen, het resultaat kan controleren en vervolgens bepaalt wat u vervolgens moet doen.

Een gebruiker kan bijvoorbeeld de AI vragen om een gloeilamp te "in- of uitschakelen". De AI moet eerst de status van de gloeilamp controleren voordat wordt bepaald of deze moet worden ingeschakeld of uitgeschakeld.

Role Bericht
🔵Gebruiker Schakel alle lichten in
🔴Assistent (functieoproep) Lights.get_lights()
🟢Tool { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] }
🔴Assistent (functieoproep) Lights.change_state(1, { "isOn": false }) Lights.change_state(2, { "isOn": true })
🟢Tool { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" }
🟢Tool { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴Assistent De lichten zijn in-/uitgeschakeld

Notitie

In dit voorbeeld hebt u ook parallelle functie aanroepen gezien. Hier kan de AI meerdere functies tegelijk aanroepen. Dit is een krachtige functie waarmee de AI complexe taken sneller kan oplossen. Het werd toegevoegd aan de OpenAI-modellen in 1106.

De automatische planningslus

Ondersteunende functie aanroepen zonder Semantische kernel is relatief complex. U moet een lus schrijven die het volgende zou bereiken:

  1. JSON-schema's maken voor elk van uw functies
  2. Geef de LLM op met de vorige chatgeschiedenis en functieschema's
  3. Parseert het antwoord van de LLM om te bepalen of deze een bericht wil beantwoorden of een functie wil aanroepen
  4. Als de LLM een functie wil aanroepen, moet u de functienaam en parameters parseren uit het antwoord van de LLM
  5. De functie aanroepen met de juiste parameters
  6. De resultaten van de functie retourneren, zodat de LLM kan bepalen wat er moet worden uitgevoerd
  7. Herhaal stap 2-6 totdat de LLM besluit dat deze de taak heeft voltooid of hulp nodig heeft van de gebruiker

In Semantic Kernel maken we het eenvoudig om functie-aanroepen te gebruiken door deze lus voor u te automatiseren. Hierdoor kunt u zich richten op het bouwen van de invoegtoepassingen die nodig zijn om de behoeften van uw gebruiker op te lossen.

Notitie

Begrijpen hoe de functie-aanroeplus werkt, is essentieel voor het bouwen van krachtige en betrouwbare AI-agents. Zie het artikel over het aanroepen van functies voor een uitgebreid overzicht van de werking van de lus.

Automatisch aanroepen van functies gebruiken

Als u automatische functie-aanroepen in Semantische kernel wilt gebruiken, moet u het volgende doen:

  1. De invoegtoepassing registreren bij de kernel
  2. Een object voor uitvoeringsinstellingen maken waarmee de AI automatisch functies moet aanroepen
  3. Roep de chatvoltooiingsservice aan met de chatgeschiedenis en de 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());

Wanneer u automatische functie-aanroepen gebruikt, worden alle stappen in de automatische planningslus voor u verwerkt en toegevoegd aan het ChatHistory object. Nadat de functieaanroeplus is voltooid, kunt u het ChatHistory object inspecteren om alle functieaanroepen te zien die zijn gemaakt en de resultaten die worden geleverd door Semantic Kernel.

Hoe zit het met de planners voor het aanroepen van stapsgewijze functies en handlebars?

De planners voor stapsgewijze en stuurgrepen zijn nog steeds beschikbaar in Semantische kernel. We raden u echter aan om functie-aanroepen te gebruiken voor de meeste taken omdat deze krachtiger en eenvoudiger te gebruiken is. Zowel de stepwise- als handlebars planners worden afgeschaft in een toekomstige release van Semantic Kernel.

Informatie over het migreren van stapsgewijze planner naar automatisch aanroepen van functies.

Let op

Als u een nieuwe AI-agent bouwt, wordt u aangeraden de planners voor stapsgewijze instructies of handgrepen niet te gebruiken. Gebruik in plaats daarvan functie aanroepen omdat het krachtiger en eenvoudiger te gebruiken is.

Volgende stappen

Nu u begrijpt hoe planners werken in Semantic Kernel, kunt u meer informatie krijgen over hoe invloed heeft op uw AI-agent, zodat ze het beste taken plannen en uitvoeren namens uw gebruikers.