将提示保存到文件

已完成

在前一个单元中,你了解了如何通过调用 kernel.InvokePromptAsync 创建可重用的提示。 例如:

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

创建内联提示非常有用,但对于较大的项目,可能需要将提示组织到单独的文件中,并将它们导入内核。 这类似于使用内置插件的方式。 要创建自己的提示插件,最佳做法是为提示创建单独的文件夹。”

如何创建语义插件

语义内核 SDK 支持具有一些简单语法规则的提示模板化语言。 无需编写代码或导入任何外部库,只需使用大括号 {{...}} 以 在提示中嵌入表达式。

要创建语义插件,需要包含两个文件的文件夹:skprompt.txt文件和config.json文件。 skprompt.txt文件包含大型语言模型 (LLM) 的提示,这与到目前为止编写的所有提示类似。 config.json文件包含提示的配置详细信息。

config.json文件支持以下参数:

  • type:提示的类型。 通常使用聊天完成提示类型。
  • description:提示所执行操作的说明。 内核可使用此说明自动调用提示。
  • input_variables:定义提示内使用的变量。
  • execution_settings:完成模型的设置。 对于 OpenAI 模型,这些设置包括 max_tokenstemperature 属性。

例如,假设你想要创建音乐导师代理。 你可能想要支持一项功能,该功能建议将和弦添加到潜在的和弦进行中。 在这种情况下,用户提供起始和弦,插件推荐适合的和弦。

要创建此插件,你首先会在项目中创建“Prompts”文件夹,然后创建名为“SuggestChords”的子文件夹。 之后,将“skprompt.txt”和“config.json”文件添加到“SuggestChords”文件夹中。

“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>

“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
        },
    ]
}

在此示例中,temperature 是一个参数,用于控制如何随机化生成的文本。 值必须介于 0 和 2 之间。 更低的温度会导致更集中和精确的输出,更高的温度会导致更多样化和创造性的输出。

在当前模型中,请求最多可使用在提示和完成之间共享的 4,097 个令牌。 这意味着,如果提示为 4,000 个令牌,则聊天完成最多可以为 97 个令牌。 可在 LLM 的文档中找到有关微调参数的详细信息。

要使用自定义语义插件,请将提示目录导入内核,并按其文件夹名称调用插件。 例如:

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

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

Console.WriteLine(result);

在此示例中,CreatePluginFromPromptDirectory 返回 KernelPlugin 对象。 此对象表示函数的集合。 CreatePluginFromPromptDirectory接受指定插件目录的路径,并且每个子文件夹的名称都用作函数名称。

例如,如果将“SuggestChords”嵌套在名为“ChordProgressions”的文件夹内,你将使用提示目录“Prompts/ChordProgressions”,且函数名称将保持不变。 或者,可以使用“Prompt”目录并引用“ChordProgressions/SuggestChords”作为函数名称。

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

运行此代码应生成类似于以下输出的响应:

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

将提示保存到文件是组织代码并使其更易于维护的绝佳方法。 通过配置文件,还可进一步优化提示以获取更可预测的用户体验。