8、Function Calling行为控制

8、Function Calling行为控制

在上一节中,我们介绍了可以通过设置PromptExecutionSetting中的ToolCallBehavior属性来控制工具调用的行为,有以下两种赋值,但二者都会将内核绑定的插件信息提供给模型,以供模型选择合适的函数进去调用,但区别在于是否自动完成函数调用:

  1. ToolCallBehavior.AutoInvokeKernelFunctions :自动调用内核函数
  2. ToolCallBehavior.EnableKernelFunctions :仅返回模型的函数调用请求,需要应用自行发起对函数的调用

但同时也可以通过 FunctionChoiceBehavior 来控制Function Calling的行为,达到更精细的控制,主要包括:

  1. 函数的广播:即哪些函数提供给AI模型。
  2. 函数的选择:即AI 模型如何选择使用哪些函数。
  3. 函数的调用:即选择的函数如何调用,是自动还是手动。

FunctionChoiceBehavior的取值有三种:

1
2
3
4
Auto(
IEnumerable<KernelFunction>? functions = null,
bool autoInvoke = true,
FunctionChoiceBehaviorOptions? options = null)
1
2
3
4
Required(
IEnumerable<KernelFunction>? functions = null,
bool autoInvoke = true,
FunctionChoiceBehaviorOptions? options = null)
1
2
3
None(
IEnumerable<KernelFunction>? functions = null,
FunctionChoiceBehaviorOptions? options = null)

ToolCallBehaviorFunctionChoiceBehavior 只可二选一。

准备工作:

1
2
//创建kernel后。。。
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

预定义插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kernel.Plugins.Clear();
kernel.ImportPluginFromFunctions("HelperFunctions",
[
kernel.CreateFunctionFromMethod(() => DateTime.UtcNow.ToString("R"), "GetCurrentDateTimeInUtc", "Retrieves the current date time in UTC."),
kernel.CreateFunctionFromMethod((string cityName, string currentDateTimeInUtc) =>
cityName switch
{
"Boston" => "61 and rainy",
"London" => "55 and cloudy",
"Miami" => "80 and sunny",
"Paris" => "60 and rainy",
"Tokyo" => "50 and sunny",
"Sydney" => "75 and sunny",
"Tel Aviv" => "80 and sunny",
_ => "31 and snowing",
}, "GetWeatherForCity", "Gets the current weather for the specified city and specified date time."),
]);

1. Auto

1.1 自动调用函数

1
2
3
4
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() };
var response =await kernel.InvokePromptAsync("What is the likely color of the sky in Boston today?", new(settings));

response.Display();

The likely color of the sky in Boston today is gray, due to the rain.

如果使用Yaml模板,可以如下配置:

1
2
3
4
5
6
7
8
9
10
11
  string promptTemplateConfig = """
template_format: semantic-kernel
template: What is the likely color of the sky in Boston today?
execution_settings:
default:
function_choice_behavior:
type: auto
""";

KernelFunction promptFunction = KernelFunctionYaml.FromPromptYaml(promptTemplateConfig);
Console.WriteLine(await kernel.InvokeAsync(promptFunction));

The likely color of the sky in Boston today is gray, due to the rainy weather.

1.2 被动调用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(autoInvoke: false) };

ChatHistory chatHistory = [];
chatHistory.AddUserMessage("What is the likely color of the sky in Boston today?");
while (true)
{
// Start or continue chat based on the chat history
ChatMessageContent result = await chatCompletionService.GetChatMessageContentAsync(chatHistory, settings, kernel);
if (result.Content is not null)
{
Console.Write(result.Content);
// Expected output: "The color of the sky in Boston is likely to be gray due to the rainy weather."
chatHistory.Add(result);
}
// Get function calls from the chat message content and quit the chat loop if no function calls are found.
IEnumerable<FunctionCallContent> functionCalls = FunctionCallContent.GetFunctionCalls(result);
if (!functionCalls.Any())
{
break;
}
// Preserving the original chat message content with function calls in the chat history.
chatHistory.Add(result);
// Iterating over the requested function calls and invoking them sequentially.
// The code can easily be modified to invoke functions in concurrently if needed.
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());
}
}
}
chatHistory.Display();

The sky in Boston today is likely to be gray due to the rainy weather.

2. Required

强制调用

1
2
3
4
5
6
KernelFunction getWeatherFunction = kernel.Plugins.GetFunction("HelperFunctions", "GetWeatherForCity");
//强制调用getWeatherFunction
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Required(functions: [getWeatherFunction]) };

Console.WriteLine(await kernel.InvokePromptAsync("Given that it is now the 9th of September 2024, 11:29 AM, what is the likely color of the sky in Boston?", new(settings)));

The sky in Boston is likely gray due to the rainy weather.

如果使用Yaml模板,可以如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
string promptTemplateConfig = """
template_format: semantic-kernel
template: Given that it is now the 9th of September 2024, 11:29 AM, what is the likely color of the sky in Boston?
execution_settings:
default:
function_choice_behavior:
type: auto
functions:
- HelperFunctions.GetWeatherForCity
""";

KernelFunction promptFunction = KernelFunctionYaml.FromPromptYaml(promptTemplateConfig);
Console.WriteLine(await kernel.InvokeAsync(promptFunction));
The sky in Boston is likely to be grey due to the rainy weather.

3. None

即仅向AI 广播函数,但不允许AI 使用函数。

1
2
3
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.None() };

Console.WriteLine(await kernel.InvokePromptAsync("告诉我我可以使用哪些方法来获得今天天空的颜色?", new(settings)));
To determine the color of the sky in Boston for today, you would need to follow these steps:

1. **HelperFunctions-GetCurrentDateTimeInUtc**: Call this function to get the current date and time in UTC. This will help you determine the current time to fetch the weather information accurately.

2. **HelperFunctions-GetWeatherForCity**: After obtaining the current UTC date and time, use this function with "Boston" as the city name and the current UTC date and time as parameters to get the weather information for Boston. The weather information will typically include aspects like cloud cover, which can help deduce the color of the sky.

By using both these functions together, you can get the necessary weather information to infer the sky's color.

如果不想向AI 广播函数,可直接用以下方式(直接清空functions列表,或者清空plugin列表):

1
2
3
4
OpenAIPromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(functions:[]) };
var response =await kernel.InvokePromptAsync("What is the likely color of the sky in Boston today?", new(settings));

response.Display();

如果在Yaml中配置,等同于:

1
2
3
4
5
6
7
8
9
10
11
12
string promptTemplateConfig = """
template_format: semantic-kernel
template: WWhat is the likely color of the sky in Boston?
execution_settings:
default:
function_choice_behavior:
type: auto
functions: []
""";

KernelFunction promptFunction = KernelFunctionYaml.FromPromptYaml(promptTemplateConfig);
Console.WriteLine(await kernel.InvokeAsync(promptFunction));
作者

步步为营

发布于

2025-03-21

更新于

2025-03-21

许可协议