Comprendre les fonctions natives

Effectué

Les fonctions natives sont des fonctions écrites en code natif qui peuvent être appelées par le SDK de noyau sémantique de votre application. Elles sont utiles pour effectuer des tâches que les modèles de langage volumineux (LLM) ne peuvent pas effectuer d’eux-mêmes. Vous pouvez considérer une fonction native comme une compétence que votre application peut utiliser.

Dans les modules suivants, vous apprendrez à utiliser le noyau sémantique pour invoquer automatiquement les fonctions natives que vous créez, et à combiner votre logique avec les invites du LLM. En combinant les services de complétion de chat et les compétences fonctionnelles, vous pouvez créer un agent d’IA capable d’effectuer un large éventail de tâches. Mais pour l’instant, nous allons nous concentrer sur la conception de fonctions natives.

Les fonctions natives ont un certain format et une structure de fichiers recommandée à utiliser par le noyau. Les fonctions natives doivent utiliser KernelFunction l’élément décoratif dans leurs définitions. Elles utilisent également un Description champ pour les paramètres. Par exemple :

[KernelFunction, Description("Convert an amount of currency to USD")]
public static string ConvertCurrency(
  [Description("The currency")] string currency, 
  [Description("The amount")] double amount)
{
  // Code to convert currency
}

Vous pouvez importer vos fonctions natives dans le noyau comme plug-in. Les classes contenant des fonctions natives doivent être placées dans un répertoire « Plugins ». Les fonctions associées doivent être placées dans le même fichier pour conserver le code organisé. Vous pouvez également utiliser des sous-répertoires dans le répertoire « Plugins » pour organiser davantage votre code.

Par exemple, supposons que vous disposez d’une application de liste de tâches. Supposons que l’utilisateur souhaite terminer un élément sur sa liste de tâches. Le modèle de langage volumineux (LLM) ne peut pas accéder directement à sa liste de tâches, mais vous pouvez écrire une fonction native pour accéder à la liste et marquer un élément comme terminé. Par exemple, le fichier de liste de tâches peut contenir les éléments suivants :

{
  "todoList": [
    {
      "task": "Complete coding exercise",
      "completed": false
    },
    {
      "task": "Practice Mandarin",
      "completed": false
    },
    {
      "task": "Buy groceries",
      "completed": false
    }
  ]
}

Vous pouvez également créer un fichier TodoListPlugin.cs dans le répertoire « Plugins » avec un code pour marquer la tâche comme terminée :

using System.ComponentModel;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.SemanticKernel;

public class TodoListPlugin
{
    [KernelFunction, Description("Mark a todo list item as complete")]
    public static string CompleteTask([Description("The task to complete")] string task)
    {
        // Read the JSON file
        string jsonFilePath = $"{Directory.GetCurrentDirectory()}/todo.txt";
        string jsonContent = File.ReadAllText(jsonFilePath);

        // Parse the JSON content
        JsonNode todoData = JsonNode.Parse(jsonContent);

        // Find the task and mark it as complete
        JsonArray todoList = (JsonArray) todoData["todoList"];
        foreach (JsonNode taskNode in todoList)
        {
            if (taskNode["task"].ToString() == task)
            {
                taskNode["completed"] = true;
                break;
            }
        }

        // Save the modified JSON back to the file
        File.WriteAllText(jsonFilePath, JsonSerializer.Serialize(todoData));
        return $"Task '{task}' marked as complete.";
    }
}

Notez le décorateur KernelFunction sur la fonction CompleteTask. Ce décorateur indique au noyau que cette fonction est accessible. Le décorateur Description indique au noyau ce que fait la fonction. La fonction accepte task comme une chaîne. Les variables des fonctions de noyau doivent inclure une description qui explique ce que la variable est. Cette fonction retourne également une chaîne qui indique à l’utilisateur que la tâche a été marquée comme terminée.

Dans le fichier Program.cs, vous pouvez importer et appeler cette fonction native comme vous le feriez pour appeler un des plug-ins intégrés. Par exemple :

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.Core;

var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
  "your-deployment-name",
  "your-endpoint",
  "your-api-key",
  "deployment-model");
var kernel = builder.Build();
kernel.ImportPluginFromType<TodoListPlugin>();

var result = await kernel.InvokeAsync<string>(
  "TodoListPlugin", 
  "CompleteTask", 
  new() {{ "task", "Buy groceries" }}
);
Console.WriteLine(result);

Dans cet exemple, kernel.InvokeAsync est appelé avec le nom du plug-in, le nom de la fonction et les arguments. L’argument task est défini sur « Faire des courses ». La fonction marque la tâche comme terminée dans le fichier de liste de tâches et retourne un message à l’utilisateur.

À présent, votre agent IA peut aider l’utilisateur à effectuer des tâches sur sa liste de tâches. Si vous le souhaitez, vous pouvez choisir de désigner le type de retour de la fonction dans l’appel InvokeAsync. Sinon, un objet FunctionResult est retourné.

Dans l’exercice suivant, vous allez vous entraîner à créer vos propres plug-ins avec des fonctions natives.