Funktionsanropslägen

När AI-modellen får en uppmaning som innehåller en lista över funktioner kan den välja en eller flera av dem för anrop för att slutföra prompten. När en funktion väljs av modellen måste den anropas av semantisk kernel.

Funktionen som anropar undersystemet i semantisk kernel har två funktionsanropslägen: automatiskt och manuellt.

Beroende på anropsläget utför semantisk kernel antingen funktionsanrop från slutpunkt till slutpunkt eller ger anroparen kontroll över funktionsanropsprocessen.

Anrop av automatisk funktion

Automatisk funktionsanrop är standardläget för undersystemet Semantic Kernel function-calling. När AI-modellen väljer en eller flera funktioner anropar Semantic Kernel automatiskt de valda funktionerna. Resultatet av dessa funktionsanrop läggs till i chatthistoriken och skickas automatiskt till modellen i efterföljande begäranden. Modellen resonerar sedan om chatthistoriken, väljer ytterligare funktioner om det behövs eller genererar det slutliga svaret. Den här metoden är helt automatiserad och kräver ingen manuell åtgärd från anroparen.

Tip

Automatisk funktionsanrop skiljer sig från beteendet för autofunktionsval. Den förstnämnda avgör om funktioner ska anropas automatiskt av Semantic Kernel, medan den senare avgör om funktioner ska väljas automatiskt av AI-modellen.

Det här exemplet visar hur du använder det automatiska funktionsanropet i semantisk kernel. AI-modellen bestämmer vilka funktioner som ska anropas för att slutföra prompten och semantisk kernel gör resten och anropar dem automatiskt.

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

Fler uppdateringar kommer snart till Java SDK.

Vissa AI-modeller stöder parallella funktionsanrop, där modellen väljer flera funktioner för anrop. Detta kan vara användbart i de fall då det tar lång tid att anropa valda funktioner. AI:n kan till exempel välja att hämta de senaste nyheterna och den aktuella tiden samtidigt, i stället för att göra en tur och retur-resa per funktion.

Semantisk kernel kan anropa dessa funktioner på två olika sätt:

  • Sekventiellt: Funktionerna anropas en efter en. Det här är standardbeteendet.
  • Samtidigt: Funktionerna anropas samtidigt. Detta kan aktiveras genom att ställa in egenskapen FunctionChoiceBehaviorOptions.AllowConcurrentInvocationtrue, som du ser i exemplet nedan.
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));

Ibland kan en modell välja flera funktioner för anrop. Detta kallas ofta parallell funktionsanrop . När flera funktioner väljs av AI-modellen anropar Semantic Kernel dem samtidigt.

Tip

Med OpenAI- eller Azure OpenAI-anslutningsappen kan du inaktivera parallella funktionsanrop genom att göra följande:

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
)

Manuell funktionsanrop

I de fall då anroparen vill ha mer kontroll över funktionsanropsprocessen kan manuell funktionsanrop användas.

När manuell funktionsanrop är aktiverat anropar semantisk kernel inte automatiskt de funktioner som väljs av AI-modellen. I stället returneras en lista över valda funktioner till anroparen, som sedan kan bestämma vilka funktioner som ska anropas, anropa dem sekventiellt eller parallellt, hantera undantag och så vidare. Resultaten från funktionsanropen måste läggas till i chatthistoriken och returneras till modellen, som kommer att resonera om dem och avgöra om den ska välja ytterligare funktioner eller generera ett slutgiltigt svar.

Exemplet nedan visar hur du använder manuell funktionsanrop.

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

Kommentar

Klasserna FunctionCallContent och FunctionResultContent används för att representera AI-modellfunktionsanrop respektive Semantic Kernel-funktionsanropsresultat. De innehåller information om vald funktion, till exempel funktions-ID, namn och argument samt funktionsanropsresultat, till exempel funktionsanrops-ID och resultat.

I följande exempel visas hur du använder manuell funktionsanrop med API:et för slutförande av direktuppspelningschatt. Observera användningen av FunctionCallContentBuilder klassen för att skapa funktionsanrop från strömmande innehåll. På grund av API:ets strömningstyp strömmas även funktionsanrop. Det innebär att anroparen måste skapa funktionsanropen från strömmande innehåll innan de anropas.

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

Kommentar

Klasserna FunctionCallContent och FunctionResultContent används för att representera AI-modellfunktionsanrop respektive Semantic Kernel-funktionsanropsresultat. De innehåller information om vald funktion, till exempel funktions-ID, namn och argument samt funktionsanropsresultat, till exempel funktionsanrops-ID och resultat.

Tip

Fler uppdateringar kommer snart till Java SDK.