Režimy volání funkce

Když model AI obdrží výzvu obsahující seznam funkcí, může zvolit jeden nebo více z nich pro vyvolání výzvy k dokončení výzvy. Když model vybere funkci, musí ji vyvolat sémantické jádro.

Volání subsystému funkce v sémantickém jádru má dva režimy volání funkce: automatické a ruční.

V závislosti na režimu vyvolání Sémantické jádro buď provede kompletní vyvolání funkce od začátku do konce, nebo ponechá volajícímu kontrolu nad procesem vyvolání funkce.

Automatické vyvolání funkce

Automatické vyvolání funkce je výchozím režimem subsystému volání funkcí sémantického jádra. Když model AI zvolí jednu nebo více funkcí, sémantické jádro automaticky vyvolá zvolené funkce. Výsledky těchto volání funkce se přidají do historie chatu a automaticky se odešlou do modelu v následných požadavcích. Model pak zdůvodní historii chatu, v případě potřeby zvolí další funkce nebo vygeneruje konečnou odpověď. Tento přístup je plně automatizovaný a nevyžaduje žádný ruční zásah volajícího.

Tip

Automatické vyvolání funkce se liší od chování automatické volby funkce. První diktuje, jestli by funkce měly být vyvolány automaticky Sémantické jádro, zatímco druhý určuje, jestli by funkce měly být zvoleny automaticky modelem AI.

Tento příklad ukazuje, jak použít automatické vyvolání funkce v sémantickém jádru. Model AI rozhodne, které funkce má zavolat k dokončení zadání, a Sémantické jádro se postará o zbytek a automaticky je zavolá.

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

Další aktualizace Java SDK budou brzy k dispozici.

Některé modely AI podporují paralelní volání funkcí, kde model vybírá více funkcí pro vyvolání. To může být užitečné v případech, kdy vyvolání vybraných funkcí trvá dlouhou dobu. AI se například může rozhodnout, že současně načte nejnovější novinky a aktuální čas, místo aby pro každou funkci zvlášť prováděla samostatný požadavek a odpověď.

Sémantické jádro může tyto funkce vyvolat dvěma různými způsoby:

  • Postupně: Funkce jsou vyvolány jeden za druhým. Toto je výchozí chování.
  • Souběžně: Funkce jsou vyvolány současně. To lze povolit nastavením FunctionChoiceBehaviorOptions.AllowConcurrentInvocation vlastnosti na true, jak je znázorněno v příkladu níže.
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));

V některých případech může model zvolit více funkcí pro vyvolání. To se často označuje jako paralelní volání funkcí. Pokud model AI vybere více funkcí, Sémantické jádro je vyvolá souběžně.

Tip

Pomocí konektoru OpenAI nebo Azure OpenAI můžete paralelní volání funkcí zakázat následujícím způsobem:

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
)

Ruční vyvolání funkce

V případech, kdy volající chce mít větší kontrolu nad procesem volání funkce, je možné použít ruční vyvolání funkce.

Pokud je povolené ruční vyvolání funkce, sémantické jádro automaticky nevyvolá funkce vybrané modelem AI. Místo toho vrátí volajícímu seznam vybraných funkcí, který se pak může rozhodnout, které funkce se mají vyvolat, vyvolat je postupně nebo paralelně, zpracovávat výjimky atd. Výsledky vyvolání funkce je potřeba přidat do historie chatu a vrátit se do modelu, což zdůvodní a rozhodne, jestli zvolíte další funkce nebo vygenerujete konečnou odpověď.

Následující příklad ukazuje použití ručního vyvolání funkce.

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

Poznámka:

FunctionCallContent a FunctionResultContent třídy se používají k reprezentaci volání funkce modelu AI a výsledky vyvolání funkce sémantického jádra. Obsahují informace o zvolené funkci, jako je ID funkce, název a argumenty a výsledky volání funkce, například ID volání funkce a výsledek.

Následující příklad ukazuje, jak použít ruční volání funkce se streamovacím API pro dokončování chatu. Všimněte si použití FunctionCallContentBuilder třídy k sestavení volání funkcí ze streamovaného obsahu. Vzhledem k povaze streamování rozhraní API se také streamují volání funkcí. To znamená, že volající musí ze streamovaného obsahu sestavit volání funkcí před jejich voláním.

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

Poznámka:

FunctionCallContent a FunctionResultContent třídy se používají k reprezentaci volání funkce modelu AI a výsledky vyvolání funkce sémantického jádra. Obsahují informace o zvolené funkci, jako je ID funkce, název a argumenty a výsledky volání funkce, například ID volání funkce a výsledek.

Tip

Další aktualizace Java SDK budou brzy k dispozici.