Qu’est-ce qu’un planificateur ?
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 ultérieur. 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 la fonction appelante crée-t-elle 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 de « basculer » 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 | Basculez toutes les lumières |
🔴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 :
- Créer des schémas JSON pour chacune de vos fonctions
- Fournir le LLM avec l’historique de conversation et les schémas de fonction précédents
- Analyser la réponse du LLM pour déterminer s’il souhaite répondre avec un message ou appeler une fonction
- 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
- Appeler la fonction avec les paramètres appropriés
- Retourne les résultats de la fonction afin que le LLM puisse déterminer ce qu’il doit faire ensuite
- 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 :
- Inscrire le plug-in auprès du noyau
- Créer un objet de paramètres d’exécution qui indique à l’IA d’appeler automatiquement des fonctions
- Appeler le service d’achèvement de conversation avec l’historique des conversations et le noyau
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());
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’en est-il des planificateurs d’appels de fonction et de handlebars ?
Les planificateurs Stepwise et Handlebars sont toujours disponibles dans le noyau sémantique. Toutefois, nous vous recommandons d’utiliser l’appel de fonction pour la plupart des tâches, car il est plus puissant et plus facile à utiliser. Les planificateurs Stepwise et Handlebars seront déconseillés dans une prochaine version du noyau sémantique.
Découvrez comment migrer stepwise Planner vers l’appel automatique de fonction.
Attention
Si vous créez un nouvel agent IA, nous vous recommandons de ne pas utiliser les planificateurs Stepwise ou Handlebars. Au lieu de cela, utilisez l’appel de fonction, car il est plus puissant et plus facile à utiliser.
Étapes suivantes
Maintenant que vous comprenez le fonctionnement des planificateurs dans le noyau sémantique, vous pouvez en savoir plus sur l’influence de votre agent IA afin qu’il planifie et exécute les tâches au nom de vos utilisateurs.