関数呼び出しモード

AI モデルは、関数の一覧を含むプロンプトを受け取ると、1 つ以上の関数を選択して呼び出しを完了できます。 モデルによって関数を選択する場合は、セマンティック カーネルによって invoked する必要があります。

セマンティック カーネルの関数呼び出しサブシステムには、 automanual の 2 つのモードがあります。

呼び出しモードに応じて、セマンティック カーネルはエンドツーエンドの関数呼び出しを行うか、呼び出し元に関数呼び出しプロセスを制御します。

関数の自動呼び出し

自動関数呼び出しは、セマンティック カーネル関数呼び出しサブシステムの既定のモードです。 AI モデルが 1 つ以上の関数を選択すると、セマンティック カーネルは選択した関数を自動的に呼び出します。 これらの関数呼び出しの結果はチャット履歴に追加され、後続の要求でモデルに自動的に送信されます。 その後、モデルはチャット履歴に関する理由を示し、必要に応じて追加の関数を選択するか、最終的な応答を生成します。 この方法は完全に自動化されており、呼び出し元による手動による介入は必要ありません。

Tip

自動関数呼び出しは、 自動関数の選択動作とは異なります。 前者はSemantic Kernelによって関数を自動的に呼び出す必要があるかどうかを決定し、後者は AI モデルによって関数を自動的に選択するかどうかを決定します。

この例では、セマンティック カーネルで自動関数呼び出しを使用する方法を示します。 AI モデルは、プロンプトを完了するために呼び出す関数を決定し、セマンティック カーネルは残りの部分を実行して自動的に呼び出します。

using Microsoft.SemanticKernel;

IKernelBuilder builder = Kernel.CreateBuilder(); 
builder.AddOpenAIChatCompletion("<model-id>", "<api-key>");
builder.Plugins.AddFromType<WeatherForecastUtils>();
builder.Plugins.AddFromType<DateTimeUtils>(); 

Kernel kernel = builder.Build();

// By default, functions are set to be automatically invoked.  
// If you want to explicitly enable this behavior, you can do so with the following code:  
// PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: true) };  
PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }; 

await kernel.InvokePromptAsync("Given the current time of day and weather, what is the likely color of the sky in Boston?", new(settings));
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
from semantic_kernel.functions.kernel_arguments import KernelArguments
from semantic_kernel.kernel import Kernel

kernel = Kernel()
kernel.add_service(OpenAIChatCompletion())

# Assuming that WeatherPlugin and DateTimePlugin are already implemented
kernel.add_plugin(WeatherPlugin(), "WeatherPlugin")
kernel.add_plugin(DateTimePlugin(), "DateTimePlugin")

query = "What is the weather in Seattle today?"
arguments = KernelArguments(
    settings=PromptExecutionSettings(
        # By default, functions are set to be automatically invoked.
        # If you want to explicitly enable this behavior, you can do so with the following code:
        # function_choice_behavior=FunctionChoiceBehavior.Auto(auto_invoke=True),
        function_choice_behavior=FunctionChoiceBehavior.Auto(),
    )
)

response = await kernel.invoke_prompt(query, arguments=arguments)

Tip

その他の更新プログラムは、Java SDK に近日公開予定です。

一部の AI モデルでは、並列関数呼び出しがサポートされています。この場合、モデルは複数の関数を呼び出し用に選択します。 これは、選択した関数の呼び出しに時間がかかる場合に便利です。 たとえば、AI は、関数ごとにラウンド トリップするのではなく、最新のニュースと現在の時刻を同時に取得することを選択できます。

セマンティック カーネルは、次の 2 つの異なる方法でこれらの関数を呼び出すことができます。

  • 順次: 関数が順番に呼び出されます。 これが既定の動作です。
  • 同時に: 関数は同時に呼び出されます。 これを有効にするには、次の例に示すように、 FunctionChoiceBehaviorOptions.AllowConcurrentInvocation プロパティを true に設定します。
using Microsoft.SemanticKernel;

IKernelBuilder builder = Kernel.CreateBuilder(); 
builder.AddOpenAIChatCompletion("<model-id>", "<api-key>");
builder.Plugins.AddFromType<NewsUtils>();
builder.Plugins.AddFromType<DateTimeUtils>(); 

Kernel kernel = builder.Build();

// Enable concurrent invocation of functions to get the latest news and the current time.
FunctionChoiceBehaviorOptions options = new() { AllowConcurrentInvocation = true };

PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(options: options) }; 

await kernel.InvokePromptAsync("Good morning! What is the current time and latest news headlines?", new(settings));

モデルが呼び出しに複数の関数を選択する場合があります。 これは、多くの場合、 並列 関数呼び出しと呼ばれます。 AI モデルによって複数の関数が選択されると、Semantic Kernelはそれらを同時に呼び出します。

Tip

OpenAI コネクタまたは Azure OpenAI コネクタを使用すると、次の操作を行って並列関数呼び出しを無効にすることができます。

from semantic_kernel.connectors.ai.open_ai import OpenAIChatPromptExecutionSettings
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior

settings = OpenAIChatPromptExecutionSettings(
    function_choice_behavior=FunctionChoiceBehavior.Auto(),
    parallel_tool_calls=False
)

手動関数呼び出し

呼び出し元が関数呼び出しプロセスをより詳細に制御したい場合は、手動関数呼び出しを使用できます。

手動関数呼び出しが有効になっている場合、セマンティック カーネルは、AI モデルによって選択された関数を自動的に呼び出しません。 代わりに、選択した関数の一覧が呼び出し元に返されます。呼び出す関数を決定し、それらを順番または並列で呼び出し、例外を処理することができます。 関数呼び出しの結果をチャット履歴に追加し、モデルに返す必要があります。これは、その結果を理由にして、追加の関数を選択するか、最終的な応答を生成するかを決定します。

次の例は、手動関数呼び出しを使用する方法を示しています。

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;

IKernelBuilder builder = Kernel.CreateBuilder(); 
builder.AddOpenAIChatCompletion("<model-id>", "<api-key>");
builder.Plugins.AddFromType<WeatherForecastUtils>();
builder.Plugins.AddFromType<DateTimeUtils>(); 

Kernel kernel = builder.Build();

IChatCompletionService chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

// Manual function invocation needs to be enabled explicitly by setting autoInvoke to false.
PromptExecutionSettings settings = new() { FunctionChoiceBehavior = Microsoft.SemanticKernel.FunctionChoiceBehavior.Auto(autoInvoke: false) };

ChatHistory chatHistory = [];
chatHistory.AddUserMessage("Given the current time of day and weather, what is the likely color of the sky in Boston?");

while (true)
{
    ChatMessageContent result = await chatCompletionService.GetChatMessageContentAsync(chatHistory, settings, kernel);

    // Check if the AI model has generated a response.
    if (result.Content is not null)
    {
        Console.Write(result.Content);
        // Sample output: "Considering the current weather conditions in Boston with a tornado watch in effect resulting in potential severe thunderstorms,
        // the sky color is likely unusual such as green, yellow, or dark gray. Please stay safe and follow instructions from local authorities."
        break;
    }

    // Adding AI model response containing chosen functions to chat history as it's required by the models to preserve the context.
    chatHistory.Add(result); 

    // Check if the AI model has chosen any function for invocation.
    IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
    if (!functionCalls.Any())
    {
        break;
    }

    // Sequentially iterating over each chosen function, invoke it, and add the result to the chat history.
    foreach (FunctionCallContent functionCall in functionCalls)
    {
        try
        {
            // Invoking the function
            FunctionResultContent resultContent = await functionCall.InvokeAsync(kernel);

            // Adding the function result to the chat history
            chatHistory.Add(resultContent.ToChatMessage());
        }
        catch (Exception ex)
        {
            // Adding function exception to the chat history.
            chatHistory.Add(new FunctionResultContent(functionCall, ex).ToChatMessage());
            // or
            //chatHistory.Add(new FunctionResultContent(functionCall, "Error details that the AI model can reason about.").ToChatMessage());
        }
    }
}

FunctionCallContent クラスと FunctionResultContent クラスは、それぞれ AI モデル関数呼び出しとセマンティック カーネル関数呼び出しの結果を表すために使用されます。 関数 ID、名前、引数、関数呼び出しの結果 (関数呼び出し ID や結果など) など、選択した関数に関する情報が含まれます。

次の例では、ストリーミング チャット完了 API で手動関数呼び出しを使用する方法を示します。 ストリーミング コンテンツから関数呼び出しをビルドするために、 FunctionCallContentBuilder クラスを使用することに注意してください。 API のストリーミングの性質により、関数呼び出しもストリーミングされます。 つまり、呼び出し元は、ストリーミング コンテンツから関数呼び出しをビルドしてから呼び出す必要があります。

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;

IKernelBuilder builder = Kernel.CreateBuilder(); 
builder.AddOpenAIChatCompletion("<model-id>", "<api-key>");
builder.Plugins.AddFromType<WeatherForecastUtils>();
builder.Plugins.AddFromType<DateTimeUtils>(); 

Kernel kernel = builder.Build();

IChatCompletionService chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

// Manual function invocation needs to be enabled explicitly by setting autoInvoke to false.
PromptExecutionSettings settings = new() { FunctionChoiceBehavior = Microsoft.SemanticKernel.FunctionChoiceBehavior.Auto(autoInvoke: false) };

ChatHistory chatHistory = [];
chatHistory.AddUserMessage("Given the current time of day and weather, what is the likely color of the sky in Boston?");

while (true)
{
    AuthorRole? authorRole = null;
    FunctionCallContentBuilder fccBuilder = new ();

    // Start or continue streaming chat based on the chat history
    await foreach (StreamingChatMessageContent streamingContent in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, settings, kernel))
    {
        // Check if the AI model has generated a response.
        if (streamingContent.Content is not null)
        {
            Console.Write(streamingContent.Content);
            // Sample streamed output: "The color of the sky in Boston is likely to be gray due to the rainy weather."
        }
        authorRole ??= streamingContent.Role;

        // Collect function calls details from the streaming content
        fccBuilder.Append(streamingContent);
    }

    // Build the function calls from the streaming content and quit the chat loop if no function calls are found
    IReadOnlyList<FunctionCallContent> functionCalls = fccBuilder.Build();
    if (!functionCalls.Any())
    {
        break;
    }

    // Creating and adding chat message content to preserve the original function calls in the chat history.
    // The function calls are added to the chat message a few lines below.
    ChatMessageContent fcContent = new ChatMessageContent(role: authorRole ?? default, content: null);
    chatHistory.Add(fcContent);

    // Iterating over the requested function calls and invoking them.
    // The code can easily be modified to invoke functions concurrently if needed.
    foreach (FunctionCallContent functionCall in functionCalls)
    {
        // Adding the original function call to the chat message content
        fcContent.Items.Add(functionCall);

        // Invoking the function
        FunctionResultContent functionResult = await functionCall.InvokeAsync(kernel);

        // Adding the function result to the chat history
        chatHistory.Add(functionResult.ToChatMessage());
    }
}
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.contents.function_call_content import FunctionCallContent
from semantic_kernel.contents.function_result_content import FunctionResultContent
from semantic_kernel.kernel import Kernel

kernel = Kernel()
chat_completion_service = OpenAIChatCompletion()

# Assuming that WeatherPlugin is already implemented
kernel.add_plugin(WeatherPlugin(), "WeatherPlugin")

settings = PromptExecutionSettings(
    function_choice_behavior=FunctionChoiceBehavior.Auto(auto_invoke=False),
)

chat_history = ChatHistory()
chat_history.add_user_message("What is the weather in Seattle on 10th of September 2024 at 11:29 AM?")

response = await chat_completion_service.get_chat_message_content(chat_history, settings, kernel=kernel)
function_call_content = response.items[0]
assert isinstance(function_call_content, FunctionCallContent)

# Need to add the response to the chat history to preserve the context
chat_history.add_message(response)

function = kernel.get_function(function_call_content.plugin_name, function_call_content.function_name)
function_result = await function(kernel, function_call_content.to_kernel_arguments())

function_result_content = FunctionResultContent.from_function_call_content_and_result(
    function_call_content, function_result
)

# Adding the function result to the chat history
chat_history.add_message(function_result_content.to_chat_message_content())

# Invoke the model again with the function result
response = await chat_completion_service.get_chat_message_content(chat_history, settings, kernel=kernel)
print(response)
# The weather in Seattle on September 10th, 2024, is expected to be [weather condition].

FunctionCallContent クラスと FunctionResultContent クラスは、それぞれ AI モデル関数呼び出しとセマンティック カーネル関数呼び出しの結果を表すために使用されます。 関数 ID、名前、引数、関数呼び出しの結果 (関数呼び出し ID や結果など) など、選択した関数に関する情報が含まれます。

Tip

その他の更新プログラムは、Java SDK に近日公開予定です。