当前位置: 首页 > news >正文

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 } ] }
http://www.jsqmd.com/news/1107121/

相关文章:

  • 王中王指标中线和长线波段指标
  • 液压系统的溢流阀溢流导致能耗高解决方案
  • 元脉网络发布AIGC存储网络解决方案
  • WebPKI证书验证库:原理、选型与Python实战封装
  • 2026怎么选成都展厅设计公司?最新口碑实测推荐
  • 测试专用111
  • 2026年7月昆明装修品牌推荐甄选干货|避开装修套路,优质本土整装企业推荐
  • 没有海外信用卡怎么充值 ChatGPT?国内用户开通 Plus 的几种办法(2026 最新)
  • 揭秘光伏储能安全真相,哪些因素决定了安全性?
  • 东莞注塑厂选注塑机数据采集厂家怎么选的三个关键维度
  • 2026微商城做得比较好的商家,哪些行业和场景更容易跑出效果
  • 30天打造高效知识系统:Obsidian-Zettelkasten终极模板指南
  • 珠三角AI定制开发能力对比权威测评(2026.07)
  • Multiphase Buck Design From Start to Finish (Part 1)
  • 危废暂存间安全管理系统方案
  • AI算力基建动态简报(2026.07.01)
  • 收藏!6年大厂算法工程师总结的最少必会知识,助你快速入门大模型
  • 互联网企业降本实操:地图 API 年付从 5 万降到 3.5 万,选型经验全分享
  • Amazon S3 存储桶设置为公开读取(所有人可访问)
  • 实测对比!动态滚动字幕怎么无痕去除?主流视频去字幕工具深测评
  • 15.ai重生:从配音黑科技到AI传奇
  • 2026三天客户拜访,会议记录ai工具哪个最好用 整理了选型参考
  • 2026湾芯奖开放申报!快来参选中国半导体行业的至高荣誉吧!
  • 终极指南:如何用Obsidian Better Export PDF插件高效管理知识输出
  • 京东商品详情 API 完整调用实例
  • 【趣话计算机底层技术】调试器是个大骗子!
  • 合成数据驱动的RLHF:无需人工标注的对齐新路径
  • 做了20多年运维,我发现企业最容易忽视这一点
  • ASMR下载神器终极指南:如何快速高效获取asmr.one资源
  • DeepBump终极指南:3秒从单张图片生成专业法线贴图的AI神器