Semantic Kernel:Function Calling
在上一篇的Function中,我们用混合方式来分别调用语义Function和本地Function,但调用顺序是开发者组织的。
其实SK是可以自组织的,下面定义了一个本地Function——GetChineseDay,用ImportPluginFromFunctions的方式添加到SK的插件库里。当在Call1中询问“现在离吃月饼还有多少天?”时,GetChineseDay就会被自动调用,但如果换一个问题:“1=1=?”,这个问题与日期没有关关系,则本地函数不会触发。注意这个配置var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };。
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; using Microsoft.SemanticKernel.Connectors.OpenAI; using System; using System.Globalization; using System.Text; #pragma warning disable SKEXP0001 var chatModelId = "gpt-4o"; var key = File.ReadAllText(@"C:\GPT\key.txt"); var builder = Kernel.CreateBuilder(); builder.AddOpenAIChatCompletion(chatModelId, key); Kernel kernel = builder.Build(); kernel.ImportPluginFromFunctions("HelperFunctions", [ kernel.CreateFunctionFromMethod(GetChineseDay, "GetChineseDay", "返回中国的农历") ]); await Call1(); async Task Call1() { Console.WriteLine("-----------------Call1 开始---------------------"); var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions }; await foreach (var content in kernel.InvokePromptStreamingAsync("现在离吃月饼还有多少天?", new(settings))) { Console.Write(content); } Console.WriteLine(); Console.WriteLine("-----------------Call1 结束---------------------"); } string GetChineseDay() { var chineseCalendar = new ChineseLunisolarCalendar(); var today = DateTime.Now; int lunarYear = chineseCalendar.GetYear(today); int lunarMonth = chineseCalendar.GetMonth(today); int lunarDay = chineseCalendar.GetDayOfMonth(today); bool isLeapMonth = chineseCalendar.IsLeapMonth(lunarYear, lunarMonth); Console.WriteLine("-------GetChineseDay--------"); return $"农历日期: {lunarYear}年 {(isLeapMonth ? "闰" : "")}{lunarMonth}月 {lunarDay}日"; } Console.WriteLine();
运行结果如下:
如果想在聊天中用到Function Calling怎么做呢?
await Call2(); async Task Call2() { Console.WriteLine("-----------------Call2 开始---------------------"); var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions }; var chat = kernel.GetRequiredService<IChatCompletionService>(); var chatHistory = new ChatHistory("中国农历的表示方式是:九月初三,十二月二十三,请用这种表示方式表示农历日期。"); chatHistory.AddUserMessage("现在离吃月饼还有多少天?"); var contentBuilder = new StringBuilder(); await foreach (var streamingContent in chat.GetStreamingChatMessageContentsAsync(chatHistory, settings, kernel)) { if (streamingContent.Content is not null) { Console.Write(streamingContent.Content); contentBuilder.Append(streamingContent.Content); } } chatHistory.AddAssistantMessage(contentBuilder.ToString()); Console.WriteLine(); Console.WriteLine("-----------------Call2 结束---------------------"); }
运行结果如下:
下面是通过FunctionCallContentBuilder,来查看被调用的本地Function有哪些:
await Call3(); async Task Call3() { Console.WriteLine("-----------------Call4 开始---------------------"); IChatCompletionService chat = kernel.GetRequiredService<IChatCompletionService>(); OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions }; ChatHistory chatHistory = new(); chatHistory.AddUserMessage("中秋节吃月饼,现在离吃月饼还有多少天?"); while (true) { AuthorRole? authorRole = null; var fccBuilder = new FunctionCallContentBuilder(); await foreach (var streamingContent in chat.GetStreamingChatMessageContentsAsync(chatHistory, settings, kernel)) { if (streamingContent.Content is not null) { Console.Write(streamingContent.Content); } authorRole ??= streamingContent.Role; fccBuilder.Append(streamingContent); } Console.WriteLine(); var functionCalls = fccBuilder.Build(); if (!functionCalls.Any()) { break; } var fcContent = new ChatMessageContent(role: authorRole ?? default, content: null); chatHistory.Add(fcContent); foreach (var functionCall in functionCalls) { fcContent.Items.Add(functionCall); var functionResult = await functionCall.InvokeAsync(kernel); Console.WriteLine($"FunctionName:{functionResult.FunctionName},Return:{functionResult.InnerContent}"); chatHistory.Add(functionResult.ToChatMessage()); } Console.WriteLine(); } Console.WriteLine(); Console.WriteLine("-----------------Call4 结束---------------------"); }
运行结果:
文章来源微信公众号
想要更快更方便的了解相关知识,可以关注微信公众号
****欢迎关注我的asp.net core系统课程****
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下