Funktionsaufrufmodi

Wenn das KI-Modell eine Eingabeaufforderung mit einer Liste von Funktionen empfängt, kann es eine oder mehrere davon auswählen, um die Eingabeaufforderung abzuschließen. Wenn eine Funktion vom Modell ausgewählt wird, muss sie vom semantischen Kernel aufgerufen werden.

Das Funktionsaufrufsubsystem im semantischen Kernel verfügt über zwei Funktionsaufrufmodi: auto und manuell.

Abhängig vom Aufrufmodus führt der semantische Kernel entweder End-to-End-Funktionsaufrufe durch oder gibt dem Aufrufer die Steuerung des Funktionsaufrufs.

Automatischer Funktionsaufruf

Der automatische Funktionsaufruf ist der Standardmodus des Subsystems für Funktionsaufrufe von Semantischer Kernel. Wenn das KI-Modell eine oder mehrere Funktionen auswählt, ruft der semantische Kernel automatisch die ausgewählten Funktionen auf. Die Ergebnisse dieser Funktionsaufrufe werden dem Chatverlauf hinzugefügt und automatisch in nachfolgenden Anforderungen an das Modell gesendet. Das Modell hat dann Gründe für den Chatverlauf, wählt bei Bedarf zusätzliche Funktionen aus oder generiert die endgültige Antwort. Dieser Ansatz ist vollständig automatisiert und erfordert keinen manuellen Eingriff des Anrufers.

Tip

Der Aufruf der automatischen Funktion unterscheidet sich vom Wahlverhalten der automatischen Funktion. Ersteres gibt vor, ob Funktionen automatisch von Semantischer Kernel aufgerufen werden sollen, während Letzteres bestimmt, ob Funktionen automatisch durch das KI-Modell ausgewählt werden sollen.

In diesem Beispiel wird veranschaulicht, wie der Automatische Funktionsaufruf im semantischen Kernel verwendet wird. Das KI-Modell entscheidet, welche Funktionen aufgerufen werden sollen, um die Eingabeaufforderung abzuschließen, und der semantische Kernel erledigt den Rest und ruft sie automatisch auf.

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

Weitere Updates werden in Kürze im Java SDK verfügbar sein.

Einige KI-Modelle unterstützen parallele Funktionsaufrufe, bei denen das Modell mehrere Funktionen für den Aufruf auswählt. Dies kann in Fällen hilfreich sein, wenn das Aufrufen ausgewählter Funktionen eine lange Zeit in Anspruch nimmt. Beispielsweise kann die KI die neuesten Nachrichten und die aktuelle Zeit gleichzeitig abrufen, anstatt einen Roundtrip pro Funktion vorzunehmen.

Der semantische Kernel kann diese Funktionen auf zwei verschiedene Arten aufrufen:

  • Sequenziell: Die Funktionen werden nacheinander aufgerufen. Dies ist die Standardeinstellung.
  • Gleichzeitig: Die Funktionen werden gleichzeitig aufgerufen. Dies kann durch Festlegen der FunctionChoiceBehaviorOptions.AllowConcurrentInvocation Eigenschaft auf true, wie im folgenden Beispiel gezeigt, aktiviert werden.
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));

Manchmal kann ein Modell mehrere Funktionen für den Aufruf auswählen. Dies wird häufig als parallele Funktionsaufrufe bezeichnet. Wenn mehrere Funktionen vom KI-Modell ausgewählt werden, ruft Semantischer Kernel sie gleichzeitig auf.

Tip

Mit dem OpenAI- oder Azure OpenAI-Connector können Sie parallele Funktionsaufrufe deaktivieren, indem Sie die folgenden Schritte ausführen:

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
)

Manueller Funktionsaufruf

In Fällen, in denen der Aufrufer mehr Kontrolle über den Aufrufprozess der Funktion haben möchte, können manuelle Funktionsaufrufe verwendet werden.

Wenn der manuelle Funktionsaufruf aktiviert ist, ruft der semantische Kernel nicht automatisch die vom KI-Modell ausgewählten Funktionen auf. Stattdessen wird eine Liste ausgewählter Funktionen an den Aufrufer zurückgegeben, der dann entscheiden kann, welche Funktionen aufgerufen werden sollen, sie sequenziell oder parallel aufrufen, Ausnahmen behandeln usw. Die Ergebnisse des Funktionsaufrufs müssen dem Chatverlauf hinzugefügt und dem Modell zurückgegeben werden, das diese auswertet und entscheidet, ob weitere Funktionen ausgewählt oder eine endgültige Antwort generiert werden soll.

Das folgende Beispiel veranschaulicht, wie manuelle Funktionsaufrufe verwendet werden.

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());
        }
    }
}

Hinweis

Die Klassen FunctionCallContent und FunctionResultContent werden verwendet, um AI-Modellfunktionsaufrufe bzw. semantische Kernel-Funktionsaufrufe darzustellen. Sie enthalten Informationen über die ausgewählte Funktion, z. B. die Funktions-ID, den Namen und Argumente sowie Die Ergebnisse des Funktionsaufrufs, z. B. Funktionsaufruf-ID und Ergebnis.

Im folgenden Beispiel wird veranschaulicht, wie Manuelle Funktionsaufrufe mit der Api zum Abschluss des Streamingchats verwendet werden. Beachten Sie die Verwendung der FunctionCallContentBuilder Klasse zum Erstellen von Funktionsaufrufen aus dem Streaminginhalt. Aufgrund der Streaming-Natur der API werden auch Funktionsaufrufe gestreamt. Dies bedeutet, dass der Aufrufer die Funktionsaufrufe aus dem Streaminginhalt erstellen muss, bevor sie aufgerufen werden.

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].

Hinweis

Die Klassen FunctionCallContent und FunctionResultContent werden verwendet, um AI-Modellfunktionsaufrufe bzw. semantische Kernel-Funktionsaufrufe darzustellen. Sie enthalten Informationen über die ausgewählte Funktion, z. B. die Funktions-ID, den Namen und Argumente sowie Die Ergebnisse des Funktionsaufrufs, z. B. Funktionsaufruf-ID und Ergebnis.

Tip

Weitere Updates werden in Kürze im Java SDK verfügbar sein.