news 2026/7/2 6:00:53

config.json 文件是固定名称,存储描述信息,比如需要的变量名称、描述等。下面是一个 completion 类型的插件配置文件示例,除了一些跟提示模板相关的配置,还有一些聊天的配置,如最大 t

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
config.json 文件是固定名称,存储描述信息,比如需要的变量名称、描述等。下面是一个 completion 类型的插件配置文件示例,除了一些跟提示模板相关的配置,还有一些聊天的配置,如最大 t
{ "schema": 1, "type": "completion", "description": "根据用户问题写一首简短而有趣的诗.", "completion": { "max_tokens": 200, "temperature": 0.5, "top_p": 0.0, "presence_penalty": 0.0, "frequency_penalty": 0.0 }, "input": { "parameters": [ { "name": "input", "description": "诗的主题", "defaultValue": "" } ] } }

创建插件目录和文件后,在代码中以提示模板的方式加载:

// 加载插件,表示该插件是提示模板 builder.Plugins.AddFromPromptDirectory("./plugins/WriterPlugin"); var kernel = builder.Build(); Console.WriteLine("输入诗的主题:"); var input = Console.ReadLine(); // WriterPlugin 插件名称,与插件目录一致,插件目录下可以有多个子模板目录。 FunctionResult result = await kernel.InvokeAsync("WriterPlugin", "ShortPoem", new() { { "input", input } }); Console.WriteLine(result.GetValue<string>());

输入问题以及 AI 回复:

输入诗的主题: 春天 春天,春天,你是生命的诗篇, 万物复苏,爱的季节。 郁郁葱葱的小草中, 是你轻响的诗人的脚步音。 春天,春天,你是花芯的深渊, 桃红柳绿,或妩媚或清纯。 在温暖的微风中, 是你舞动的裙摆。 春天,春天,你是蓝空的情儿, 百鸟鸣叫,放歌天际无边。 在你湛蓝的天幕下, 是你独角戏的绚烂瞬间。 春天,春天,你是河流的眼睛, 如阿瞒甘霖,滋养大地生灵。 你的涓涓细流, 是你悠悠的歌声。 春天,春天,你是生命的诗篇, 用温暖的手指,照亮这灰色的世间。 你的绽放,微笑与欢欣, 就是我心中永恒的春天。

插件文件的编写可参考官方文档:https://learn.microsoft.com/en-us/semantic-kernel/prompts/saving-prompts-as-files?tabs=Csharp

根据 AI 自动调用插件函数

使用 Semantic Kernel 加载插件类后,Semantic Kernel 可以自动根据 AI 对话调用这些插件类中的函数。

比如有一个插件类型,用于修改或获取灯的状态。

代码如下:

public class LightPlugin { public bool IsOn { get; set; } = false; [KernelFunction] [Description("获取灯的状态.")] public string GetState() => IsOn ? "亮" : "暗"; [KernelFunction] [Description("修改灯的状态.'")] public string ChangeState(bool newState) { this.IsOn = newState; var state = GetState(); Console.WriteLine($"[灯的状态是: {state}]"); return state; } }

每个函数都使用了[Description]特性设置了注释信息,这些注释信息非常重要,AI 靠这些注释理解函数的功能作用。

然后加载插件类,并在聊天中被 Semantic Kernel 调用:

// 加载插件类 builder.Plugins.AddFromType<LightPlugin>(); var kernel = builder.Build(); var history = new ChatHistory(); // 聊天服务 var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>(); while (true) { Console.Write("User > "); var userInput = Console.ReadLine(); // 添加到聊天记录中 history.AddUserMessage(userInput); // 开启函数调用 OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions }; // 获取函数 var result = await chatCompletionService.GetChatMessageContentAsync( history, executionSettings: openAIPromptExecutionSettings, kernel: kernel); Console.WriteLine("Assistant > " + result); // 添加到聊天记录中 history.AddMessage(result.Role, result.Content ?? string.Empty); }

可以先断点调试 LightPlugin 中的函数,然后在控制台输入问题让 AI 调用本地函数:

User > 灯的状态 Assistant > 当前灯的状态是暗的。 User > 开灯 [灯的状态是: 亮] Assistant > 灯已经开启,现在是亮的状态。 User > 关灯 [灯的状态是: 暗]

读者可以在官方文档了解更多:https://learn.microsoft.com/en-us/semantic-kernel/agents/plugins/using-the-kernelfunction-decorator?tabs=Csharp

由于几乎没有文档资料说明原理,因此建议读者去研究源码,这里就不再赘述了。

聊天中明确调用函数

我们可以在提示模板中明确调用一个函数。

定义一个插件类型 ConversationSummaryPlugin,其功能十分简单,将历史记录直接返回,input 参数表示历史记录。

public class ConversationSummaryPlugin { [KernelFunction, Description("给你一份很长的谈话记录,总结一下谈话内容.")] public async Task<string> SummarizeConversationAsync( [Description("长对话记录\r\n.")] string input, Kernel kernel) { await Task.CompletedTask; return input; } }

为了在聊天记录中使用该插件函数,我们需要在提示模板中使用{{ConversationSummaryPlugin.SummarizeConversation $history}},其中$history是自定义的变量名称,名称可以随意,只要是个字符串即可。

var chat = kernel.CreateFunctionFromPrompt( @"{{ConversationSummaryPlugin.SummarizeConversation $history}} User: {{$request}} Assistant: " );

完整代码如下:

// 加载总结插件 builder.Plugins.AddFromType<ConversationSummaryPlugin>(); var kernel = builder.Build(); var chat = kernel.CreateFunctionFromPrompt( @"{{ConversationSummaryPlugin.SummarizeConversation $history}} User: {{$request}} Assistant: " ); var history = new ChatHistory(); while (true) { Console.Write("User > "); var request = Console.ReadLine(); // 添加到聊天记录中 history.AddUserMessage(request); // 流式对话 var chatResult = kernel.InvokeStreamingAsync<StreamingChatMessageContent>( chat, new KernelArguments { { "request", request }, { "history", string.Join("\n", history.Select(x => x.Role + ": " + x.Content)) } }); string message = ""; await foreach (var chunk in chatResult) { if (chunk.Role.HasValue) { Console.Write(chunk.Role + " > "); } message += chunk; Console.Write(chunk); } Console.WriteLine(); history.AddAssistantMessage(message); }

由于模板的开头是{{ConversationSummaryPlugin.SummarizeConversation $history}},因此,每次聊天之前,都会先调用该函数。

比如输入吃饭睡觉打豆豆的时候,首先执行 ConversationSummaryPlugin.SummarizeConversation 函数,然后将返回结果存储到模板中。

最后生成的提示词对比如下:

@"{{ConversationSummaryPlugin.SummarizeConversation $history}} User: {{$request}} Assistant: "
user: 吃饭睡觉打豆豆 User: 吃饭睡觉打豆豆 Assistant:

可以看到,调用函数返回结果后,提示词字符串前面自动使用 User 角色。

实现总结

Semantic Kernel 中有很多文本处理工具,比如TextChunker类型,可以帮助我们提取文本中的行、段。设定场景如下,用户提问一大段文本,然后我们使用 AI 总结这段文本。

Semantic Kernel 有一些工具,但是不多,而且是针对英文开发的。

设定一个场景,用户可以每行输入一句话,当用户使用000结束输入后,每句话都推送给 AI 总结(不是全部放在一起总结)。

这个示例的代码比较长,建议读者在 vs 中调试代码,慢慢阅读。

// 总结内容的最大 token const int MaxTokens = 1024; // 提示模板 const string SummarizeConversationDefinition = @"开始内容总结: {{$request}} 最后对内容进行总结。 在“内容到总结”中总结对话,找出讨论的要点和得出的任何结论。 不要加入其他常识。 摘要是纯文本形式,在完整的句子中,没有标记或标记。 开始总结: "; // 配置 PromptExecutionSettings promptExecutionSettings = new() { ExtensionData = new Dictionary<string, object>() { { "Temperature", 0.1 }, { "TopP", 0.5 }, { "MaxTokens", MaxTokens } } }; // 这里不使用 kernel.CreateFunctionFromPrompt 了 // KernelFunctionFactory 可以帮助我们通过代码的方式配置提示词 var func = KernelFunctionFactory.CreateFromPrompt( SummarizeConversationDefinition, // 提示词 description: "给出一段对话记录,总结这部分对话.", // 描述 executionSettings: promptExecutionSettings); // 配置 #pragma warning disable SKEXP0055 // 类型仅用于评估,在将来的更新中可能会被更改或删除。取消此诊断以继续。 var request = ""; while (true) { Console.Write("User > "); var input = Console.ReadLine(); if (input == "000") { break; } request += Environment.NewLine; request += input; } // SK 提供的文本拆分器,将文本分成一行行的 List<string> lines = TextChunker.SplitPlainTextLines(request, MaxTokens); // 将文本拆成段落 List<string> paragraphs = TextChunker.SplitPlainTextParagraphs(lines, MaxTokens); string[] results = new string[paragraphs.Count]; for (int i = 0; i < results.Length; i++) { // 一段段地总结 results[i] = (await func.InvokeAsync(kernel, new() { ["request"] = paragraphs[i] }).ConfigureAwait(false)) .GetValue<string>() ?? string.Empty; } Console.WriteLine($""" 总结如下: {string.Join("\n", results)} """);

输入一堆内容后,新的一行使用000结束提问,让 AI 总结用户的话。

不过经过调试发现,TextChunker 对这段文本的处理似乎不佳,因为文本这么多行只识别为一行、一段。

可能跟 TextChunker 分隔符有关,SK 主要是面向英语的。

本小节的演示效果不佳,不过主要目的是,让用户了解KernelFunctionFactory.CreateFromPrompt可以更加方便创建提示模板、使用 PromptExecutionSettings 配置温度、使用 TextChunker 切割文本。

配置 PromptExecutionSettings 时,出现了三个参数,其中 MaxTokens 表示机器人回复最大的 tokens 数量,这样可以避免机器人废话太多。

其它两个参数的作用是:

Temperature:值范围在 0-2 之间,简单来说,temperature的参数值越小,模型就会返回越确定的一个结果。值越大,AI 的想象力越强,越可能偏离现实。一般诗歌、科幻这些可以设置大一些,让 AI 实现天马行空的回复。

TopP:与 Temperature 不同的另一种方法,称为核抽样,其中模型考虑了具有 TopP 概率质量的令牌的结果。因此,0.1 意味着只考虑构成前10% 概率质量的令牌的结果。

一般建议是改变其中一个参数就行,不用两个都调整。

更多相关的参数配置,请查看 https://learn.microsoft.com/en-us/azure/ai-services/openai/reference

配置提示词

前面提到了一个新的创建函数的用法:

var func = KernelFunctionFactory.CreateFromPrompt( SummarizeConversationDefinition, // 提示词 description: "给出一段对话记录,总结这部分对话.", // 描述 executionSettings: promptExecutionSettings); // 配置

创建提示模板时,可以使用 PromptTemplateConfig 类型 调整控制提示符行为的参数。

// 总结内容的最大 token const int MaxTokens = 1024; // 提示模板 const string SummarizeConversationDefinition = "..."; var func = kernel.CreateFunctionFromPrompt(new PromptTemplateConfig { // Name 不支持中文和特殊字符 Name = "chat", Description = "给出一段对话记录,总结这部分对话.", Template = SummarizeConversationDefinition, TemplateFormat = "semantic-kernel", InputVariables = new List<InputVariable> { new InputVariable{Name = "request", Description = "用户的问题", IsRequired = true } }, ExecutionSettings = new Dictionary<string, PromptExecutionSettings> { { "default", new OpenAIPromptExecutionSettings() { MaxTokens = MaxTokens, Temperature = 0 } }, } });

ExecutionSettings 部分的配置,可以针对使用的模型起效,这里的配置不会全部同时起效,会根据实际使用的模型起效。

ExecutionSettings = new Dictionary<string, PromptExecutionSettings> { { "default", new OpenAIPromptExecutionSettings() { MaxTokens = 1000, Temperature = 0 } }, { "gpt-3.5-turbo", new OpenAIPromptExecutionSettings() { ModelId = "gpt-3.5-turbo-0613", MaxTokens = 4000, Temperature = 0.2 } }, { "gpt-4", new OpenAIPromptExecutionSettings() { ModelId = "gpt-4-1106-preview", MaxTokens = 8000, Temperature = 0.3 } } }

聊到这里,重新说一下前面使用文件配置提示模板文件的,两者是相似的。

我们也可以使用文件的形式存储与代码一致的配置,其目录文件结构如下:

└─── chat | └─── config.json └─── skprompt.txt

模板文件由 config.json 和 skprompt.txt 组成,skprompt.txt 中配置提示词,跟 PromptTemplateConfig 的 Template 字段配置一致。

config.json 中涉及的内容比较多,你可以对照下面的 json 跟 实现总结 一节的代码,两者几乎是一模一样的。

{ "schema": 1, "type": "completion", "description": "给出一段对话记录,总结这部分对话", "execution_settings": { "default": { "max_tokens": 1000, "temperature": 0 }, "gpt-3.5-turbo": { "model_id": "gpt-3.5-turbo-0613", "max_tokens": 4000, "temperature": 0.1 }, "gpt-4": { "model_id": "gpt-4-1106-preview", "max_tokens": 8000, "temperature": 0.3 } }, "input_variables": [ { "name": "request", "description": "用户的问题.", "required": true }, { "name": "history", "description": "用户的问题.", "required": true } ] }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 6:00:43

云康e家最新消息,资金减损核定方案公布。

本文基于我个人作为云康e家平台参与者的亲身经历和真实情况记录。**本人非官方机构、非执法机关&#xff0c;不发布任何未经证实的消息&#xff0c;不提供任何投资建议。** 以下内容仅为个人经历陈述和基于公开信息的整理&#xff0c;目的在于提醒其他参与者认清现状、理性应对…

作者头像 李华
网站建设 2026/7/2 6:00:12

异步方法调用详解

文档说明本文主要针对同类&#xff0c;不同类方法之间的异步调用详解。本文基于Spring Async 异步调用四种场景教学文档。1.所有入口方法 testMain() 均添加 Transactional 事务&#xff1b; 2.区分&#xff1a;异步逻辑是否和主方法同一事务、是否跟随主方法回滚&#xff1b; …

作者头像 李华
网站建设 2026/7/2 5:59:06

零食生产线爬坡转弯输送系统(双爬坡机+转弯机)选型指南

零食生产线爬坡转弯输送系统选型指南&#xff1a;双爬坡机90度转弯机组合式草纹格挡皮带流水线技术解析 一、零食生产线的空间挑战与输送组合方案 休闲零食行业具有品种多、批次频、换线快的特点&#xff0c;生产线布局常面临空间受限、工序分散、高度落差大等挑战。单一方向的…

作者头像 李华
网站建设 2026/7/2 5:57:36

透明质酸敷料批发商实力之选:四川昂宇医疗器械有限公司深度解析

在透明质酸敷料领域&#xff0c;专业批发商的选择直接关系到产品品质与客户体验。四川昂宇医疗器械有限公司凭借深耕行业的积累与全链条服务能力&#xff0c;成为众多医疗机构与美容机构值得关注的合作伙伴。公司以“精准适配、合规交付”为核心&#xff0c;在供应链整合、方案…

作者头像 李华
网站建设 2026/7/2 5:57:22

WinBtrfs完全指南:在Windows系统上无缝访问Linux Btrfs文件系统

WinBtrfs完全指南&#xff1a;在Windows系统上无缝访问Linux Btrfs文件系统 【免费下载链接】btrfs WinBtrfs - an open-source btrfs driver for Windows 项目地址: https://gitcode.com/gh_mirrors/bt/btrfs 还在为Windows无法读取Linux Btrfs分区而烦恼吗&#xff1f…

作者头像 李华
网站建设 2026/7/2 5:56:24

九年深耕亚克力,以匠心方寸,承载世界赛事的荣光

在东莞的制造业沃土上&#xff0c;藏着很多不张扬、却有真本事的中小型工厂&#xff0c;东莞市吉昌亚克力制品有限公司便是其中之一。自2017年成立至今&#xff0c;九年时光沉淀&#xff0c;45人的精干团队、2750平米的标准化厂房、年均2500万的稳定产能&#xff0c;没有夸张的…

作者头像 李华