Partager via


Planification

Une fois que vous avez plusieurs plug-ins, vous avez besoin d’un moyen pour que votre agent IA les utilise ensemble pour résoudre les besoins d’un utilisateur. C’est là que se trouve la planification.

Dès le début, le noyau sémantique a introduit le concept de planificateurs qui utilisaient des invites pour demander à l’IA de choisir les fonctions à appeler. Depuis l’introduction du noyau sémantique, cependant, OpenAI a introduit une méthode native pour que le modèle appelle ou « appelle » une fonction : appel de fonction. D’autres modèles IA tels que Gemini, Claude et Mistral ont depuis adopté l’appel de fonction comme fonctionnalité de base, ce qui en fait une fonctionnalité prise en charge par plusieurs modèles.

En raison de ces avancées, le noyau sémantique a évolué pour utiliser l’appel de fonction comme moyen principal de planifier et d’exécuter des tâches.

Important

L’appel de fonction est disponible uniquement dans les modèles OpenAI 0613 ou plus récents. Si vous utilisez un modèle plus ancien (par exemple, 0314), cette fonctionnalité retourne une erreur. Nous vous recommandons d’utiliser les derniers modèles OpenAI pour tirer parti de cette fonctionnalité.

Comment l'appel de fonction crée-t-il un « plan » ?

À son plus simple, l’appel de fonction est simplement un moyen pour une IA d’appeler une fonction avec les paramètres appropriés. Prenons l’exemple d’un utilisateur qui souhaite activer une ampoule. En supposant que l’IA dispose du plug-in approprié, elle peut appeler la fonction pour activer la lumière.

Rôle Message
🔵 utilisateur Activez la lumière #1
🔴 Assistant (appel de fonction) Lights.change_state(1, { "isOn": true })
🟢 outil { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴 Assistant La lampe est maintenant allumée

Mais que se passe-t-il si l’utilisateur ne connaît pas l’ID de la lumière ? Ou que se passe-t-il si l’utilisateur veut activer toutes les lumières ? C’est là que se trouve la planification. Les modèles LLM d’aujourd’hui sont capables d’appeler de manière itérative des fonctions pour résoudre les besoins d’un utilisateur. Pour ce faire, créez une boucle de commentaires dans laquelle l’IA peut appeler une fonction, vérifier le résultat, puis décider de ce qu’il faut faire ensuite.

Par exemple, un utilisateur peut demander à l’IA d'« activer ou désactiver » une ampoule. L’IA doit d’abord vérifier l’état de l’ampoule avant de décider s’il faut l’activer ou le désactiver.

Rôle Message
🔵 utilisateur Allumez et éteignez toutes les lampes
🔴 Assistant (appel de fonction) Lights.get_lights()
🟢 outil { "lights": [ { "id": 1, "name": "Table Lamp", "isOn": true, "brightness": 100, "hex": "FF0000" }, { "id": 2, "name": "Ceiling Light", "isOn": false, "brightness": 0, "hex": "FFFFFF" } ] }
🔴 Assistant (appel de fonction) Lights.change_state(1, { "isOn": false }) Lights.change_state(2, { "isOn": true })
🟢 outil { "id": 1, "name": "Table Lamp", "isOn": false, "brightness": 0, "hex": "FFFFFF" }
🟢 outil { "id": 2, "name": "Ceiling Light", "isOn": true, "brightness": 100, "hex": "FF0000" }
🔴 Assistant Les lumières ont été allumées

Remarque

Dans cet exemple, vous avez également vu l’appel de fonction parallèle. C’est là que l’IA peut appeler plusieurs fonctions en même temps. Il s’agit d’une fonctionnalité puissante qui peut aider l’IA à résoudre les tâches complexes plus rapidement. Elle a été ajoutée aux modèles OpenAI en 1106.

Boucle de planification automatique

La prise en charge des appels de fonction sans noyau sémantique est relativement complexe. Vous devez écrire une boucle qui effectuerait les opérations suivantes :

  1. Créer des schémas JSON pour chacune de vos fonctions
  2. Transmettre au LLM l'historique de conversation et les schémas fonctionnels.
  3. Analyser la réponse du LLM pour déterminer s’il souhaite répondre avec un message ou appeler une fonction
  4. Si le LLM souhaite appeler une fonction, vous devez analyser le nom et les paramètres de la fonction à partir de la réponse de LLM
  5. Appeler la fonction avec les paramètres appropriés
  6. Retourne les résultats de la fonction afin que le LLM puisse déterminer ce qu’il doit faire ensuite
  7. Répétez les étapes 2 à 6 jusqu’à ce que le LLM décide qu’il a terminé la tâche ou a besoin d’aide de l’utilisateur

Dans le noyau sémantique, nous allons facilement utiliser les appels de fonction en automatisant cette boucle pour vous. Cela vous permet de vous concentrer sur la création des plug-ins nécessaires pour répondre aux besoins de votre utilisateur.

Remarque

Comprendre le fonctionnement de la boucle d’appel de fonction est essentiel pour la création d’agents IA performants et fiables. Pour obtenir un aperçu détaillé du fonctionnement de la boucle, consultez l’article d’appel de fonction .

Utilisation de l’appel automatique de fonction

Pour utiliser l’appel automatique de fonction dans le noyau sémantique, vous devez effectuer les opérations suivantes :

  1. Inscrire le module complémentaire avec le noyau
  2. Créer un objet de paramètres d’exécution qui indique à l’IA d’appeler automatiquement des fonctions
  3. Appeler le service d’achèvement de conversation avec l’historique des conversations et le noyau

Conseil / Astuce

L’exemple de code suivant utilise le LightsPlugin défini ici.

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

Lorsque vous utilisez l’appel automatique de fonction, toutes les étapes de la boucle de planification automatique sont gérées pour vous et ajoutées à l’objet ChatHistory . Une fois la boucle d’appel de fonction terminée, vous pouvez inspecter l’objet ChatHistory pour afficher tous les appels de fonction effectués et les résultats fournis par le noyau sémantique.

Qu’est-il arrivé aux planificateurs Stepwise et Handlebars ?

Les planificateurs Stepwise et Handlebars ont été déconseillés et supprimés du package de noyau sémantique. Ces planificateurs ne sont plus pris en charge dans Python, .NET ou Java.

Nous vous recommandons d’utiliser l’appel de fonction, qui est à la fois plus puissant et plus facile à utiliser pour la plupart des scénarios.

Pour mettre à jour des solutions existantes, suivez notre Guide de migration du planificateur Stepwise.

Conseil / Astuce

Pour les nouveaux agents IA, utilisez l’appel de fonction au lieu des planificateurs déconseillés. Il offre une meilleure flexibilité, une prise en charge intégrée des outils et une expérience de développement plus simple.

Étapes suivantes

Maintenant que vous comprenez le fonctionnement des planificateurs dans le noyau sémantique, vous pouvez en savoir plus sur comment influencer votre agent IA pour qu’il puisse planifier et exécuter les tâches au nom de vos utilisateurs.