当 AI 模型收到包含函数列表的提示时,可以选择其中一个或多个用于调用以完成提示。 模型选择函数时,需要 由语义内核调用 它。
语义内核中的函数调用子系统有两种函数调用模式: 自动 和 手动。
根据调用模式,语义内核要么执行端到端函数调用,要么为调用方提供对函数调用进程的控制。
自动函数调用
自动函数调用是语义内核函数调用子系统的默认模式。 当 AI 模型选择一个或多个函数时,语义内核会自动调用所选函数。 这些函数调用的结果将添加到聊天历史记录,并在后续请求中自动发送到模型。 然后,模型会根据聊天历史记录的原因,根据需要选择其他函数,或生成最终响应。 此方法是完全自动化的,无需调用方进行手动干预。
Tip
自动函数调用不同于 自动函数选择行为。 前者指示是否应通过语义内核自动调用函数,而后者确定是否应由 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 可以选择同时获取最新新闻和当前时间,而不是每调用一个函数都单独往返一次。
语义内核可以通过两种不同的方式调用这些函数:
- 顺序:函数逐个调用。 这是默认行为。
-
并发:这些函数会同时被调用。 可以通过将
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 模型选择多个函数时,语义内核将同时调用它们。
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 即将推出更多更新。