更新事項
2023/11/08
.NET 版の Semantic Kernel の v1.0.0-beta5 に対応した書き方に変更しました。
やってみたこと
Semantic Kernel をアプリに組み込むために、Azure Functions に Semantic Kernel を組み込んで API を作成してみました。
デモとして、文章を要約させる機能を作りました。
ローカルで、Postman で API 実行してみると、要約された文章が返ってきます。
Azure Functions の設定
実装
DIの設定
- Semantic Kernel
- Azure OpenAI
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureAppConfiguration(config =>
{
config
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
})
.ConfigureServices((context, services) =>
{
var configuration = context.Configuration;
services.AddSingleton<IKernel>(serviceProvider => Kernel.Builder.WithAzureChatCompletionService(
configuration.GetSection("AzureOpenAI").GetValue<string>("ModelName"),
configuration.GetSection("AzureOpenAI").GetValue<string>("Endpoint"),
configuration.GetSection("AzureOpenAI").GetValue<string>("APIKey")
).Build());
services.AddAzureClients(builder =>
{
builder.AddOpenAIClient(
new Uri(configuration.GetSection("AzureOpenAI").GetValue<string>("Endpoint")),
new AzureKeyCredential(configuration.GetSection("AzureOpenAI").GetValue<string>("APIKey"))
);
});
})
.Build();
host.Run();
ポイントは以下になります。
- 今回は簡単のためネイティブ関数(コードでプラグインを作成)は使わず、セマンティック関数(要約するプラグイン)のみを使用
- パスの指定を書いて、Skills フォルダを指定してあげる(※注意点後述)
namespace SKDemo
{
public class SKFunction
{
private readonly ILogger _logger;
private readonly IKernel kernel;
public SKFunction(ILoggerFactory loggerFactory, IKernel kernel)
{
_logger = loggerFactory.CreateLogger<SKFunction>();
this.kernel = kernel;
}
[Function("SummarizeFunction")]
public async Task<SKResponseModel> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req)
{
var input = await req.ReadFromJsonAsync<SKRequestModel>();
string exePath = AppDomain.CurrentDomain.BaseDirectory;
string parentDirectory = Directory.GetParent(exePath).Parent.Parent.Parent.FullName;
string skillsDirectory = Path.Combine(parentDirectory, "Skills");
IDictionary<string, ISKFunction>? semanticPlugins = kernel.ImportSemanticSkillFromDirectory(skillsDirectory, "Plugins");
SKContext context = kernel.CreateNewContext();
context.Variables["INPUT"] = input.Text;
SKContext answer = await semanticPlugins["SummarizeFunction"].InvokeAsync(context);
context["answer"] = answer.ToString();
var result = new SKResponseModel
{
Answer = answer.ToString()
};
return result;
}
}
}
public class SKRequestModel
{
[JsonPropertyName("text")]
public string? Text { get; set; }
}
public class SKResponseModel
{
[JsonPropertyName("answer")]
public string? Answer { get; set; }
}
{
"schema": 1,
"type": "completion",
"description": "文章(ユーザーの入力値)を要約する",
"completion": {
"max_tokens": 4000,
"temperature": 0.0,
"top_p": 1.0,
"presence_penalty": 0.0,
"frequency_penalty": 0.0
},
"input": {
"parameters": [
{
"name": "INPUT",
"description": "ユーザーの入力値",
"defaultValue": ""
}
]
}
}
以下の文章を要約してください。以下の条件に従ってください。
・日本語で回答してください
・文章の長さは、200文字以内にしてください
文章:
{{$INPUT}}
注意点
Skills フォルダについて以下 2 つ注意点があります。
-
フォルダ構造
Skills フォルダ内に Plugins フォルダを作成しており、その中に各種セマンティック関数を置いています。今回は要約するために使う SummarizeFunction というセマンティック関数を作って置いてあります。コード内でフォルダ指定するので、フォルダ名は何でもいいです。
(ネイティブ関数を使う場合は、この場合 Skills フォルダ配下に置きます)
-
プロパティ設定
ローカルで実行する場合は気にしなくてよいのですが、Azure リソースへデプロイして使う場合に必要な設定があります。以下の項目をプロジェクトファイルに追加してください。この設定をしないと Azure 上で動きません。
<ItemGroup>
<Content Include="Skills\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>