引言
上一章我們熟悉了一下 Semantic Kernel
的理論知識,Kernel
建立以及簡單的Sample
熟悉了一下 SK
的基本使用。在Semantic Kernel
中的 kernel functions
由兩部分組成第一部分是prompts functions
(提示函式),第二部分Native function
(原生函式), kernel functions
是構成外掛(Plugins
)的核心,一個外掛代表一個或者多個的kernel functions
,今天我們重點了解一下第一部分prompts functions
(提示函式)。
kernel functions
基礎
我們知道跟大語言模型(
LLM
)互動靠的是提示(prompts
),有效的提示設計對於使用LLM AI
模型實現預期結果至關重要。提示工程,也稱為提示設計,是一個新興領域,需要創造力和對細節的關注。它涉及選擇正確的單詞、短語、符號和格式,以指導模型生成高質量和相關的文字。
提示工程的深入學習是用好大語言模型的關鍵。
建立提示函式
在Semantic Kernel
中提供了多種透過Prompts
建立KernelFunction
的擴充套件方法,底層本質上都是呼叫KernelFunctionFromPrompt
的Create
方法來完成提示函式的建立。
public static KernelFunction Create(
IPromptTemplate promptTemplate,
PromptTemplateConfig promptConfig,
ILoggerFactory? loggerFactory = null)
{
Verify.NotNull(promptTemplate);
Verify.NotNull(promptConfig);
return new KernelFunctionFromPrompt(
template: promptTemplate,
promptConfig: promptConfig,
logger: loggerFactory?.CreateLogger(typeof(KernelFunctionFactory)) ?? NullLogger.Instance);
}
這裡面其實只有第二個引數PromptTemplateConfig
是我們需要關心的,第一個引數promptTemplate
是根據第二個引數 promptConfig
的Template
屬性來構造的,接下來我們重點了解一下PromptTemplateConfig
的配置。
PromptTemplateConfig
的屬性
public sealed class PromptTemplateConfig
{
private string? _templateFormat;
private string _template = string.Empty;
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
public static string SemanticKernelTemplateFormat => "semantic-kernel";
[JsonPropertyName("template_format")]
[AllowNull]
public string TemplateFormat
{
get => this._templateFormat ?? SemanticKernelTemplateFormat;
set => this._templateFormat = value;
}
[JsonPropertyName("template")]
public string Template
{
get => this._template;
set
{
Verify.NotNull(value);
this._template = value;
}
}
[JsonPropertyName("input_variables")]
public List<InputVariable> InputVariables
{
get => this._inputVariables ??= [];
set
{
Verify.NotNull(value);
this._inputVariables = value;
}
}
[JsonPropertyName("output_variable")]
public OutputVariable? OutputVariable { get; set; }
[JsonPropertyName("execution_settings")]
public Dictionary<string, PromptExecutionSettings> ExecutionSettings
{
get => this._executionSettings ??= [];
set
{
Verify.NotNull(value);
this._executionSettings = value;
}
}
[Experimental("SKEXP0001")]
[JsonPropertyName("allow_unsafe_content")]
public bool AllowUnsafeContent { get; set; } = false;
}
為了方便展示我們只保留PromptTemplateConfig
的核心屬性,這個類非常的重要,包括我們要定義配置模版也是基於此類的欄位來配置。
下面我們對PromptTemplateConfig
的屬性進行簡單的講解
我們可以把PromptTemplateConfig
可以看做是對一個函式的表述,帶著這個理解來解讀這個配置類更容易理解,如用 C#定義一個函式
[Description("無參無返回值的靜態函式")]
static void SampleFunction()
{
Console.Write("無參無返回值函式");
}
Name
屬性
Name
屬性是在PromptTemplateConfig
中用來獲取或設定在使用此配置建立提示函式(Prompts functions
)時使用的預設函式名稱。
型別可空,如果不設定建立函式時將動態生成一個隨機名稱。命名規則:利用 GUID
生成一個不含連字元的隨機字串,並將其格式化為以"func"
為字首的函式名稱
private static string CreateRandomFunctionName() => $"func{Guid.NewGuid():N}";
Name
類似與我們在 C#
中的函式名
Description
屬性
Description
屬性是用於表示一個函式的描述資訊,如果在建立prompts functions
時候沒有顯示指定函式描述資訊,那會採用Description
屬性的描述。
結合我們定義的 C#
自定義函式中Description
來理解這個屬性,其實就是給方法配置一個描述資訊,提示方法也是一種特殊的方法。
TemplateFormat
屬性
TemplateFormat
屬性用於對prompts
提示模板的格式配置,預設值為 "semantic-kernel"
對於prompts
的模版格式化引擎 用的有兩種,第一種就是 Semantic Kernel
自帶的處理格式"semantic-kernel"
;第二種則是handlebars
。
Template
屬性
Template
屬性用於儲存和管理用於定義prompts
模板字串。在設定模板字串時,會進行空值驗證,以確保模板字串不為 null
,從而保證在生成prompts
提示時模板內容有有效可用。
InputVariables
屬性
InputVariables
屬性用於prompts
提示模板中使用的輸入變數集合。
InputVariable
物件包含的屬性:
Name
:變數的名稱,用於標識輸入變數。Description
:變數的描述,提供關於輸入變數的說明。Default
:變數的預設值。IsRequired
:指示變數是否為必需的,預設為 true。JsonSchema
:描述變數的 JSON 模式。AllowUnsafeContent
:指示是否允許不安全內容,預設為 false。
OutputVariable
屬性
OutputVariable
屬性用於定義和管理prompts
提示模板中的輸出變數。
參考我們c#
定義函式 這個我理解的就是對我們函式返回值引數的一個描述
ExecutionSettings
屬性
ExecutionSettings
屬性用於獲取或設定提示模板使用的執行設定集合;型別為Dictionary<string, PromptExecutionSettings>
,表示一個鍵值對集合,其中鍵為服務 ID
,值為執行設定。
ExecutionSettings =
{
{
OpenAIPromptExecutionSettings.DefaultServiceId,
new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
Temperature = 0
}
},
{
"gpt-3.5-turbo", new OpenAIPromptExecutionSettings()
{
ModelId = "gpt-3.5-turbo-0613",
MaxTokens = 4000,
Temperature = 0.2
}
}
}
執行的配置為 PromptExecutionSettings.DefaultServiceId
預設值是"default"
,因為Semantic Kernel
都是基於.Net 8 的鍵值依賴注入Keyed
,所以 default
就是獲取的上面預設的執行配置,
kernel.GetRequiredService<ITextGenerationService>();
kernel.GetRequiredService<ITextGenerationService>("gpt-3.5-turbo");
從程式碼處理解就容易多了,可以透過ServiceKey
去獲取不同大模型的例項。
OpenAIPromptExecutionSettings 配置
這個配置是大模型的進行請求時的引數配置,是PromptExecutionSettings
提示執行設定的子類,OpenAI 的配置就是OpenAIPromptExecutionSettings
,Google
的大模型有自己的實現比如GeminiPromptExecutionSettings
核心引數其實都差不多,現在我們用OpenAI
的提示詞執行設定熟悉下配置的引數。
MaxTokens
:指定在生成文字或完成請求時允許生成的最大標記數,大多數模型的上下文長度為 2048 個標記(支援 4096 的 davinci-codex 除外)。
-
Temperature
: 控制完成結果的隨機性。預設是1.0
,通常取值範圍在0-1.0
之間。較高的溫度會增加生成文字的隨機性,使得生成的文字更加多樣化和創新性,而較低的溫度則會減少隨機性,使得生成的文字更加穩定和可預測。對於更具創意的應用程式,請嘗試
0.9
,對於具有明確答案的應用程式,請嘗試0
(argmax 取樣)。 -
TopP
: 用於控制完成結果的多樣性。預設是1.0
。透過設定不同的值可以調整生成文字的多樣性程度。較高的TopP
值會導致生成的文字更加多樣化,而較低的值則可能使生成的文字更加穩定和集中。使用溫度進行取樣的替代方法,稱為核取樣,其中模型考慮具有
top_p
機率質量的標記的結果。因此,0.1
表示僅考慮包含前10%
機率質量的代幣。我們通常建議改變這個或溫度,但不要同時改變兩者。 -
PresencePenalty
: 屬性接受介於-2.0和2.0
之間的數字。預設是0
。正值將根據新標記是否在文字中出現來對其進行懲罰,從而增加模型談論新主題的可能性。新標記:模型嘗試引入新的內容或概念,以增加生成文字的多樣性和創新性
-
FrequencyPenalty
:屬性用於控制模型生成文字時對重複內容的處理方式。預設是0
。它接受介於-2.0 和 2.0
之間的數字,其中正值表示根據標記在文字中的現有頻率對其進行懲罰,以降低模型直接重複相同內容的可能性。透過設定較高的FrequencyPenalty
值,模型更有可能避免直接重複相同內容,從而降低生成文字中重複內容的頻率. -
StopSequences
:屬性用於指定一個字串列表,其中包含模型在生成文字時遇到指定序列時應停止生成進一步標記。例如,如果設定 StopSequences 為["
"],則當模型生成文字時遇到 "<END>"
序列時,生成過程將停止。 -
ChatSystemPrompt
:屬性用於指定在使用聊天模型生成文字時要使用的系統提示。預設值是:"Assistant is a large language model."
。這個系統提示可以影響生成文字的方向和內容,幫助模型更好地理解生成任務的背景和要求。透過合理設定 ChatSystemPrompt 屬性,可以定製生成文字時使用的系統提示,以獲得符合預期的生成結果。 -
ToolCallBehavior
:屬性用於獲取或設定如何處理工具呼叫的行為。// Enable auto function calling OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
1.
EnableKernelFunctions
:會向模型提供核心的外掛函式資訊,但不會自動處理函式呼叫請求。模型需要顯式發起函式呼叫請求,並系統會傳播這些請求給適當的處理程式來執行。OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions }; var chatHistory = new ChatHistory(); ChatMessageContent result = await chat.GetChatMessageContentAsync(chatHistory, settings, kernel); //手動呼叫 IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
EnableKernelFunctions:需要透過 FunctionCallContent 手動呼叫
2.
AutoInvokeKernelFunctions
:除了向模型提供核心的外掛函式資訊外,還會嘗試自動處理任何函式呼叫請求。模型發起函式呼叫請求後,系統會自動執行相應的操作,並將結果返回給模型,而無需模型顯式處理函式呼叫的過程。
ResponseFormat
屬性
ResponseFormat
的屬性,用於獲取或設定用於完成操作的響應格式。可選值包括:"json_object"
、"text"
,以及 ChatCompletionsResponseFormat
物件,可以選擇不同的值來指定響應的格式型別,例如使用 JSON
物件、純文字等不同的響應格式
ResultsPerPrompt
屬性
ResultsPerPrompt
屬性用於確定每個提示生成的完成次數。預設值:預設為 1
,即每個提示只生成一個完成結果。在自然語言處理中,一個提示(prompt
)是輸入給模型的文字或問題,而完成(completion
)是模型生成的對應輸出。透過設定 ResultsPerPrompt
屬性,您可以指定每個提示應該生成多少個完成結果。
Seed
屬性
Seed
屬性的作用是為了控制取樣的確定性,透過指定種子值,可以在一定程度上確保相同種子和引數下的重複請求返回相同的結果。然而,由於確定性並不是完全保證的,結果仍可能有一定程度的變化
User
屬性
透過為每個終端使用者分配一個唯一的識別符號,OpenAI
可以更好地跟蹤和管理使用者的行為,同時也可以更有效地監控系統是否受到濫用。
prompts functions
實戰
Semantic Kernel
有幾個 Kernel
物件的擴充套件方法用於prompts
提示詞模版來建立KernelFunction
,總的來說可以有三類:
我們繼續用我們上一章的
OneApi
代理星火訊飛V3.5
方式來對接Semantic Kernel
具體配置可以找我上一篇文章
基於 String
字串建立 prompts functions
實戰
//基於String模版建立kernel functions
Console.WriteLine("====>基於String模版建立kernel functions<=====");
{
string prompt = "What is the intent of this request? {{$request}}";
var kernel = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: config.ModelId,
apiKey: config.ApiKey,
httpClient: client).Build();
var kernelFunction = kernel.CreateFunctionFromPrompt(prompt);
string request = "I want to send an email to the marketing team celebrating their recent milestone.";
// Create a kernel arguments object and add the request
var kernelArguments = new KernelArguments
{
{ "request", request }
};
var functionResult = await kernelFunction.InvokeAsync(kernel, kernelArguments);
Console.WriteLine(functionResult?.ToString() ?? string.Empty);
}
當然 SK 也提供了更加簡單的方法,直接傳
prompts string
模版
var functionResult = await kernel.InvokePromptAsync(prompt, kernelArguments);
這個方法內部實際上就是呼叫了CreateFunctionFromPrompt
建立了kernel functions
,目的是簡化提示函式建立的過程
基於PromptTemplateConfig
物件建立 prompts functions
經過上面的介紹我們已經對PromptTemplateConfig
的引數設定已經有了一個大致的認識,要實現這個要求需要藉助到我們的 kernel.CreateFunctionFromPrompt
這個擴充套件方法,下面我們來實操一下:
實戰
string request = "I want to send an email to the marketing team celebrating their recent milestone.";
{
var kernel = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: config.ModelId,
apiKey: config.ApiKey,
httpClient: client).Build();
var kernelFunctions = kernel.CreateFunctionFromPrompt(new PromptTemplateConfig()
{
Name = "intent",
Description = "use assistant to understand user input intent.",
TemplateFormat = PromptTemplateConfig.SemanticKernelTemplateFormat,//此處可以省略預設就是"semantic-kernel"
Template = "What is the intent of this request? {{$request}}",
InputVariables = [new() { Name = "request", Description = "The user's request.", IsRequired = true }],
ExecutionSettings = new Dictionary<string, PromptExecutionSettings>() {
{
OpenAIPromptExecutionSettings.DefaultServiceId ,//"default"
new OpenAIPromptExecutionSettings()
{
MaxTokens = 1024,
Temperature = 0
}
},
}
});
var kernelArguments = new KernelArguments
{
{ "request", request }
};
var functionResult = await kernelFunctions.InvokeAsync(kernel, kernelArguments);
Console.WriteLine(functionResult?.ToString() ?? string.Empty);
}
執行效果
基於pluginDirectory
從指定的外掛目錄中建立外掛
此方法是建立外掛的方法之一,之前有介紹過外掛就是一組kernel functions
的集合,透過定義資料夾模版可以生成prompts functions
,這部分內容等學習到Semantic Kernel
的 Plugins
在著重講解吧。
最後
在本章中,我們深入探討了 Semantic Kernel
中的 kernel functions
,重點關注了第一部分的 prompts functions(提示函式)
。我們學習瞭如何基於不同方法建立這些提示函式,包括基於字串模板和 PromptTemplateConfig
物件的建立方式,以及如何從指定的外掛目錄中建立外掛。
透過詳細講解 PromptTemplateConfig
的屬性,我們理解了如何配置和管理提示模板,以及如何調整執行設定來影響提示函式的生成結果。我們還實際操作了建立 kernel functions
的過程,加深了對提示工程的實際運用。
最後,我們展望了未來的學習方向,即 Semantic Kernel
的 Plugins
部分,這將為我們提供更多關於外掛的建立和應用方法,進一步擴充套件我們的知識和應用領域。
透過本章的學習,相信您對 prompts functions
的建立和配置有了更深入的瞭解,為進一步探索和應用 Semantic Kernel
打下了堅實的基礎。如果您有任何疑問或需要進一步幫助,請隨時向我提問。感謝閱讀!🚀
參考資料
configure-prompts
本文示例原始碼
本文原始碼
😄歡迎關注筆者公眾號一起學習交流,獲取更多有用的知識~