Omówienie funkcji natywnych

Ukończone

Funkcje natywne to funkcje napisane w kodzie natywnym, które mogą być wywoływane przez zestaw SDK jądra semantycznego w aplikacji. Są one przydatne do wykonywania zadań, których duże modele językowe (LLM) nie mogą wykonywać samodzielnie. Możesz myśleć o funkcji natywnej, takiej jak umiejętność, którą aplikacja może wykonać.

W kolejnych modułach dowiesz się, jak używać jądra semantycznego do automatycznego wywoływania tworzonych funkcji natywnych i łączyć logikę z monitami do usługi LLM. Połączenie usług uzupełniania czatów z umiejętnościami funkcjonalnymi umożliwia utworzenie agenta sztucznej inteligencji, który może wykonywać szeroką gamę zadań. Jednak na razie skoncentrujmy się na projektowaniu funkcji natywnych.

Funkcje natywne mają określony format i zalecaną strukturę plików, która ma być używana przez jądro. Funkcje natywne powinny używać dekoratora KernelFunction w swoich definicjach. Używają również Description pola dla parametrów. Na przykład:

[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
}

Funkcje natywne można zaimportować do jądra jako wtyczkę. Klasy zawierające funkcje natywne powinny być umieszczane w katalogu "Plugins". Powiązane funkcje powinny być umieszczane w tym samym pliku, aby zachować uporządkowany kod. Możesz również użyć podkatalogów w katalogu "Plugins", aby dodatkowo zorganizować kod.

Załóżmy na przykład, że masz aplikację listy zadań do wykonania. Użytkownik chce ukończyć element na liście zadań do wykonania. Duży model językowy (LLM) nie może bezpośrednio uzyskać dostępu do listy zadań do wykonania użytkownika, ale możesz napisać funkcję natywną, aby uzyskać dostęp do listy i oznaczyć element jako ukończony. Na przykład plik listy zadań do wykonania może zawierać następujące elementy:

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

Możesz utworzyć plik TodoListPlugin.cs w katalogu "Plugins" z kodem, aby oznaczyć zadanie ukończone:

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.";
    }
}

Zwróć uwagę na KernelFunction dekorator funkcji CompleteTask . Ten dekorator informuje jądro, że można uzyskać dostęp do tej funkcji. Dekorator Description informuje jądro o tym, co robi funkcja. Funkcja akceptuje task element jako ciąg. Zmienne funkcji jądra powinny zawierać opis wyjaśniający, czym jest zmienna. Ta funkcja zwraca również ciąg informujący użytkownika, że zadanie zostało oznaczone jako ukończone.

Program.cs W pliku można zaimportować i wywołać tę funkcję natywną podobną do sposobu wywoływania jednej z wbudowanych wtyczek. Na przykład:

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

W tym przykładzie kernel.InvokeAsync wywoływana jest nazwa wtyczki, nazwa funkcji i argumenty. Argument task jest ustawiony na wartość "Kup artykuły spożywcze". Funkcja oznaczy zadanie jako ukończone w pliku listy zadań do wykonania i zwróci użytkownikowi komunikat.

Teraz agent sztucznej inteligencji może ułatwić użytkownikowi wykonywanie zadań na liście zadań do wykonania. Opcjonalnie możesz określić zwracany typ funkcji w wywołaniu InvokeAsync . FunctionResult W przeciwnym razie zwracany jest obiekt.

W następnym ćwiczeniu przećwiczyć będziesz tworzenie własnych wtyczek za pomocą funkcji natywnych.