Compreender as funções nativas
Funções nativas são funções escritas em código nativo que podem ser chamadas pelo SDK do Kernel Semântico em seu aplicativo. Eles são úteis para executar tarefas que grandes modelos de linguagem (LLM) não podem fazer por conta própria. Você pode pensar em uma função nativa como uma habilidade que seu aplicativo pode executar.
Em módulos posteriores, você aprenderá a usar o Kernel Semântico para invocar automaticamente as funções nativas criadas e combinar sua lógica com prompts para o LLM. A combinação de serviços de conclusão de bate-papo com habilidades funcionais permite que você crie um agente de IA que possa executar uma ampla gama de tarefas. Mas, por enquanto, vamos nos concentrar em projetar funções nativas.
As funções nativas têm um determinado formato e uma estrutura de arquivo recomendada para ser usada pelo kernel. As funções nativas devem usar o KernelFunction
decorador em suas definições. Eles também usam um Description
campo para parâmetros. Por exemplo:
[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
}
Você pode importar suas funções nativas para o kernel como um plugin. As classes que contêm funções nativas devem ser colocadas em um diretório "Plugins". As funções relacionadas devem ser colocadas no mesmo arquivo para manter o código organizado. Você também pode utilizar subdiretórios dentro do diretório "Plugins" para organizar ainda mais seu código.
Por exemplo, suponha que você tenha um aplicativo de lista todo. Um usuário deseja concluir um item em sua lista todo. O modelo de linguagem grande (LLM) não pode acessar a lista todo do usuário diretamente, mas você pode escrever uma função nativa para acessar a lista e marcar um item como completo. Por exemplo, o arquivo de lista todo pode conter o seguinte:
{
"todoList": [
{
"task": "Complete coding exercise",
"completed": false
},
{
"task": "Practice Mandarin",
"completed": false
},
{
"task": "Buy groceries",
"completed": false
}
]
}
Você pode criar um arquivo TodoListPlugin.cs
no diretório 'Plugins' com algum código para marcar a tarefa concluída:
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.";
}
}
Observe o KernelFunction
decorador na CompleteTask
função. Este decorador diz ao kernel que esta função pode ser acessada. O Description
decorador diz ao kernel o que a função faz. A função aceita o task
como uma cadeia de caracteres. As variáveis das funções do kernel devem incluir uma descrição que explique o que é a variável. Essa função também retorna uma cadeia de caracteres informando ao usuário que a tarefa foi marcada como concluída.
Program.cs
No arquivo, você pode importar e chamar essa função nativa semelhante a como você chamaria um dos plug-ins internos. Por exemplo:
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);
Neste exemplo, kernel.InvokeAsync
é chamado com o nome do plugin, nome da função e argumentos. O task
argumento é "Comprar mantimentos". A função marcará a tarefa como concluída no arquivo de lista todo e retornará uma mensagem para o usuário.
Agora, seu agente de IA pode ajudar o usuário a concluir tarefas em sua lista de tarefas. Opcionalmente, você pode optar por indicar o tipo de retorno da função na InvokeAsync
chamada. Caso contrário, um FunctionResult
objeto será retornado.
No próximo exercício, você praticará a criação de seus próprios plugins com funções nativas.