ネイティブ関数について

完了

ネイティブ関数とは、アプリケーションで Semantic Kernel SDK によって呼び出すことができるネイティブ コードで記述された関数です。 大規模言語モデル (LLM) 自体では実行できないタスクを実行する場合に便利です。 ネイティブ関数は、アプリケーションが実行できるスキルのようなものと考えることができます。

この後のモジュールでは、Semantic Kernel を使用して、作成したネイティブ関数を自動的に呼び出し、ロジックと LLM へのプロンプトを組み合わせる方法について説明します。 チャット完了サービスと関数スキルを組み合わせることで、広範なタスクを実行できる AI エージェントを作成できます。 しかし、ここではネイティブ関数の設計に焦点を当ててみましょう。

ネイティブ関数には、特定の形式と、カーネルでの使用に推奨されるファイル構造があります。 ネイティブ関数では、KernelFunction デコレーターを定義で使用する必要があります。 また、パラメーターには Description フィールドが使用されます。 次に例を示します。

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

カーネルにネイティブ関数をプラグインとしてインポートできます。 ネイティブ関数を含むクラスは、"Plugins" ディレクトリに配置する必要があります。 関連する関数は、コードを整理された状態に保つよう、同じファイルに配置する必要があります。 "Plugins" ディレクトリ内のサブディレクトリを利用して、コードをさらに整理することもできます。

たとえば、todo リスト アプリケーションがあるとします。 ユーザーが ToDo リスト上のある項目の完了を希望しています。 大規模言語モデル (LLM) ではユーザーの ToDo リストに直接アクセスできませんが、このリストにアクセスして項目に完了のマークを付けるネイティブ関数を記述することができます。 たとえば、todo リスト ファイルには次のものが含まれているとします。

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

"Plugins" ディレクトリ内に、タスクに完了のマークを付けるコードを記述したファイル TodoListPlugin.cs を作成することができます。

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

KernelFunction 関数の CompleteTask デコレーターに注目してください。 このデコレーターは、この関数にアクセスできることをカーネルに伝えます。 Description デコレーターは、関数が何を行うかをカーネルに伝えます。 この関数は task を文字列として受け入れます。 カーネル関数の変数には、その変数の内容を説明する記述を含める必要があります。 また、この関数はタスクに完了のマークが付けられたことをユーザーに知らせる文字列を返します。

Program.cs ファイルで、いずれかの組み込みのプラグインを呼び出すのと同様の方法で、このネイティブ関数をインポートして呼び出すことができます。 次に例を示します。

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

この例では、プラグイン名、関数名、および引数を指定して kernel.InvokeAsync が呼び出されます。 task 引数は "Buy groceries" に設定されています。 この関数は、todo リスト ファイルのタスクを完了としてマークし、ユーザーにメッセージを返します。

これで、AI エージェントが、ユーザーによる ToDo リストのタスク完了を支援できるようになりました。 必要に応じて、InvokeAsync 呼び出しで関数の戻り値の型を指定できます。 それ以外の場合は、FunctionResult オブジェクトが返されます。

次の演習では、ネイティブ関数を使用して独自のプラグインを作成する方法についての演習を行います。