SementicKernelをDIで利用するためのサンプルコード自体はこちらで公開されています。secretを取得するときのセクション名の指定がそのままだと動かないっぽいのでこちらのIssueを参照してください。
これだけでほぼ終わりなのですが、IChatCompletionService をDIせずにKernelのみをDIする方法を載せておきます。次のコードのようにKernelインスタンスを生成する際にAddAzureOpenAIChatCompletionメソッドで必要なパラメーターを与えておきます。この例では元のサンプル同様にAddOptionsメソッドを使ってsecretに設定した値を取得していますが、AddAzureOpenAIChatCompletion内に直接指定する場合はそれも不要になります。
builder.Services.AddOptions<AzureOpenAIOptions>()
.Bind(builder.Configuration.GetSection(AzureOpenAIOptions.SectionName))
.ValidateDataAnnotations()
.ValidateOnStart();
builder.Services.AddKeyedTransient("LabKernel", (sp, key) =>
{
var options = sp.GetRequiredService<IOptions<AzureOpenAIOptions>>().Value;
var kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddAzureOpenAIChatCompletion(
deploymentName: options.ChatDeploymentName,
endpoint: options.Endpoint,
apiKey: options.ApiKey
);
return kernelBuilder.Build();
});
public class AzureOpenAIOptions
{
public const string SectionName = "AzureOpenAI";
public required string ChatDeploymentName { get; set; }
public required string Endpoint { get; set; }
public required string ApiKey { get; set; }
public bool IsValid =>
!string.IsNullOrWhiteSpace(ChatDeploymentName) &&
!string.IsNullOrWhiteSpace(Endpoint) &&
!string.IsNullOrWhiteSpace(ApiKey);
}
Controllerなり、RazorのModelクラスではこんな感じに利用します。
public class IndexModel : PageModel { private readonly ILogger<IndexModel> _logger; private readonly Kernel _kernel; public IndexModel(ILogger<IndexModel> logger, [FromKeyedServices("LabKernel")] Kernel kernel) { _logger = logger; _kernel = kernel; } public void OnGet() { } public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } var answer = await _kernel.InvokePromptAsync( "Why is the sky blue in one sentence?" ); //answerを使って何かする return RedirectToPage("./Index"); } }