Salvar solicitações em arquivos

Concluído

Nas unidades anteriores, você aprendeu a criar prompts reutilizáveis chamando kernel.InvokePromptAsync. Por exemplo:

Console.WriteLine(
    await kernel.InvokePromptAsync(generateNamesOfPrompt, new() {{ "input", "fantasy characters" }})
);

Criar solicitações embutidas é útil, mas para projetos maiores, talvez você queira organizá-las em arquivos separados e importá-las para o kernel. Isso se assemelha à maneira como os plug-ins internos são usados. Para criar seus próprios plug-ins de solicitação, uma das melhores práticas é criar pastas separadas para as solicitações.

Como criar plug-ins semânticos

O SDK do Kernel Semântico dá suporte a uma linguagem de modelagem de solicitação com algumas regras de sintaxe simples. Você não precisa escrever código ou importar bibliotecas externas, basta usar chaves {{...}} para inserir expressões em suas solicitações.

Para criar um plug-in semântico, você precisa de uma pasta contendo dois arquivos: um arquivo skprompt.txt e um arquivo config.json. O arquivo skprompt.txt contém o prompt para o LLM (modelo de linguagem grande), semelhante a todos os prompts que você escreveu até agora. O arquivo config.json contém os detalhes de configuração do prompt.

O arquivo config.json dá suporte aos seguintes parâmetros:

  • type: O tipo da solicitação. Normalmente, você usa o tipo de prompt de conclusão de chat.
  • description: Uma descrição do que a solicitação faz. Essa descrição pode ser usada pelo kernel para invocar automaticamente a solicitação.
  • input_variables: Define as variáveis que são usadas dentro da solicitação.
  • execution_settings: As configurações dos modelos de conclusão. Para modelos do OpenAI, essas configurações incluem as propriedades max_tokens e temperature.

Por exemplo, suponha que você queira criar um agente tutor de música. Você pode querer oferecer suporte a uma funcionalidade que sugira acordes a serem adicionados a uma progressão de acordes potencial. Nesse caso, o usuário fornece os acordes iniciais e o plug-in recomenda os acordes que seriam adequados.

Para criar esse plug-in, primeiro você criaria uma pasta “Prompts” em seu projeto e, em seguida, uma subpasta chamada “SuggestChords”. Posteriormente, você adiciona os arquivos “skprompt.txt” e “config.json” à pasta “SuggestChords”.

Exemplo de arquivo “skprompt.txt”:

<message role="system">Instructions: You are a helpful music theory assistant. 
Provide the user with several chords that they could add to a chord progression 
based on some starting chords they provide</message>
<message role="user">Am Em</message>
<message role="assistant">
C major, F major, G major, D major, E major, B minor
</message>

<message role="user"> {{$startingChords}}</message>

Exemplo de arquivo “config.json”:

{
    "schema": 1,
    "type": "completion",
    "description": "Recommends chords to the user based on starting chords",
    "execution_settings": {
        "default": {
            "max_tokens": 1000,
            "temperature": 0
        }
    },
    "input_variables": [
        {
            "name": "startingChords",
            "description": "The starting chords provided by the user",
            "required": true
        },
    ]
}

Neste exemplo, o parâmetro temperature é um parâmetro que controla o quanto randomizar o texto gerado. Os valores devem estar entre 0 e 2. Uma temperatura mais baixa resulta em uma saída mais focada e precisa, enquanto uma temperatura mais alta resulta em uma saída mais diversa e criativa.

No modelo atual, as solicitações podem usar até 4.097 tokens compartilhados entre o envio da solicitação e a conclusão. Isso significa que se a solicitação for de 4.000 tokens, a conclusão do chat poderá ser de no máximo 97 tokens. Você pode encontrar mais informações sobre parâmetros de ajuste fino na documentação do seu LLM.

Para usar o plug-in semântico personalizado, importe o diretório de prompt para o kernel e chame o plug-in pelo nome da pasta. Por exemplo:

var plugins = kernel.CreatePluginFromPromptDirectory("Prompts");
string input = "G, C";

var result = await kernel.InvokeAsync(
    plugins["SuggestChords"],
    new() {{ "startingChords", input }});

Console.WriteLine(result);

Neste exemplo, CreatePluginFromPromptDirectory retorna um objeto KernelPlugin. Este objeto representa uma coleção de funções. CreatePluginFromPromptDirectory aceita o caminho do diretório do plug-in designado e o nome de cada subpasta é usado como um nome de função.

Por exemplo, se você aninhasse "SuggestChords" dentro de uma pasta chamada "ChordProgressions", você usaria o diretório de prompt "Prompts/ChordProgressions" e o nome da função permaneceria o mesmo. Como alternativa, você pode usar o diretório “Prompt” e fazer referência a “ChordProgressions/SuggestChords” como o nome da função.

// Example of nested prompt folders
var chordProgressionPlugin = kernel.CreatePluginFromPromptDirectory("Prompts/ChordProgressions");
string input = "G, C";

var result = await kernel.InvokeAsync(
    chordProgressionPlugin["SuggestChords"],
    new() {{ "startingChords", input }});

Console.WriteLine(result);

A execução desse código deve produzir uma resposta semelhante à seguinte saída:

D major, A minor, E minor, B minor, F major, G7

Salvar suas solicitações em arquivos é uma ótima maneira de organizar seu código e torná-lo mais fácil de manter. Os arquivos de configuração também permitem que você ajuste ainda mais suas solicitações para ter uma experiência de usuário mais previsível.