前回のFunctionにおいて、開発者が構成した順番で、セマンティックFunctionとローカルFunctionをそれぞれ呼び出す混合方式を使用しました。
実際には、Semantic Kernel(SK)は自動で組織化できます。以下で定義されているローカルFunction「GetChineseDay」を「ImportPluginFromFunctions」方式でSKのプラグインライブラリに追加します。「Call1」で「今月餅を食べるのまで何日ありますか?」と質問されると、GetChineseDayが自動的に呼び出されます。しかし、質問が「1=1=?」のように日付と無関係な場合、ローカルFunctionはトリガーされません。注意すべき設定は「var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };」です。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System;
using System.Globalization;
using System.Text;
#pragma warning disable SKEXP0001
var chatModelId = "gpt-4o";
var key = File.ReadAllText(@"C:\GPT\key.txt");
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(chatModelId, key);
Kernel kernel = builder.Build();
kernel.ImportPluginFromFunctions("HelperFunctions",
[
kernel.CreateFunctionFromMethod(GetChineseDay, "GetChineseDay", "返回中国的农历")
]);
await Call1();
async Task Call1()
{
Console.WriteLine("-----------------Call1 開始---------------------");
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
await foreach (var content in kernel.InvokePromptStreamingAsync("现在离吃月饼还有多少天?", new(settings)))
{
Console.Write(content);
}
Console.WriteLine();
Console.WriteLine("-----------------Call1 終了---------------------");
}
string GetChineseDay()
{
var chineseCalendar = new ChineseLunisolarCalendar();
var today = DateTime.Now;
int lunarYear = chineseCalendar.GetYear(today);
int lunarMonth = chineseCalendar.GetMonth(today);
int lunarDay = chineseCalendar.GetDayOfMonth(today);
bool isLeapMonth = chineseCalendar.IsLeapMonth(lunarYear, lunarMonth);
Console.WriteLine("-------GetChineseDay--------");
return $"农历日期: {lunarYear}年 {(isLeapMonth ? "闰" : "")}{lunarMonth}月 {lunarDay}日";
}
Console.WriteLine();
実行結果は次のとおり:
チャットでFunction Callingを使用するには?
await Call2();
async Task Call2()
{
Console.WriteLine("-----------------Call2 開始---------------------");
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
var chat = kernel.GetRequiredService<IChatCompletionService>();
var chatHistory = new ChatHistory("中国农历的表示方式是:九月初三,十二月二十三,请用这种表示方式表示农历日期。");
chatHistory.AddUserMessage("现在离吃月饼还有多少天?");
var contentBuilder = new StringBuilder();
await foreach (var streamingContent in chat.GetStreamingChatMessageContentsAsync(chatHistory, settings, kernel))
{
if (streamingContent.Content is not null)
{
Console.Write(streamingContent.Content);
contentBuilder.Append(streamingContent.Content);
}
}
chatHistory.AddAssistantMessage(contentBuilder.ToString());
Console.WriteLine();
Console.WriteLine("-----------------Call2 終了---------------------");
}
実行結果は次のとおり:
FunctionCallContentBuilderを用いて、呼び出されたローカルFunctionを確認するには?
await Call3();
async Task Call3()
{
Console.WriteLine("-----------------Call4 開始---------------------");
IChatCompletionService chat = kernel.GetRequiredService<IChatCompletionService>();
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions };
ChatHistory chatHistory = new();
chatHistory.AddUserMessage("中秋节吃月饼,现在离吃月饼还有多少天?");
while (true)
{
AuthorRole? authorRole = null;
var fccBuilder = new FunctionCallContentBuilder();
await foreach (var streamingContent in chat.GetStreamingChatMessageContentsAsync(chatHistory, settings, kernel))
{
if (streamingContent.Content is not null)
{
Console.Write(streamingContent.Content);
}
authorRole ??= streamingContent.Role;
fccBuilder.Append(streamingContent);
}
Console.WriteLine();
var functionCalls = fccBuilder.Build();
if (!functionCalls.Any())
{
break;
}
var fcContent = new ChatMessageContent(role: authorRole ?? default, content: null);
chatHistory.Add(fcContent);
foreach (var functionCall in functionCalls)
{
fcContent.Items.Add(functionCall);
var functionResult = await functionCall.InvokeAsync(kernel);
Console.WriteLine($"FunctionName:{functionResult.FunctionName},Return:{functionResult.InnerContent}");
chatHistory.Add(functionResult.ToChatMessage());
}
Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("-----------------Call4 終了---------------------");
}
実行結果:
(Translated by GPT)