Semantic Kernel 的一个核心能力就是实现“目标导向”的AI应用。
目标导向
“目标导向”听起来是一个比较高大的词,但是却是实际生活中我们处理问题的基本方法和原则。
顾名思义,这种方法的核心就是先确定目标,然后再寻找实现目标的方法和步骤。这对于人来说的是很自然的事情,但是对于机器则不然。一大堆的指令和控制逻辑其实都是在完成另外一种产出导向的结果。所有的流程和过程都需要提前预定义好,然后期待一个结果的产出。
如今,借助 LLM AI 的力量,我们可以轻松的实现目标导向的过程。
在 Semantic Kernel中,Planner就用于这项工作。
我们可以提前准备好所需的Skill,根据设定好的最终目标,通过Planner,可以将目标分解为需要执行的任务列表,并且可以指定好对应的参数传递,然后逐个任务执行,从而实现最终目标。
做好技能准备
为了让LLM AI更好的理解我们所提供的技能,需要明确地配置好每个技能本身的描述和参数描述。
对于的Semantic Function来说,可以在config.json中配置。以下是一个Translate的配置。
需要注意的就是 description
和 input
参数,最终会成为的LLM是否选择使用的判断标准。而这一切都是基于语义化的理解。
{ "schema": 1, "type": "completion", "description": "Translate the input into the specified language", "completion": { "max_tokens": 1024, "temperature": 0.0, "top_p": 0.9, "presence_penalty": 0.0, "frequency_penalty": 0.0 }, "input": { "parameters": [ { "name": "input", "description": "input text", "defaultValue": "" }, { "name":"language", "description":"the specified language", "defaultValue":"English" } ] } }
对于Native Function ,可以使用特性进行声明,其实 SKFunction
中用于添加Function的描述, SKFunctionContextParameter
用于添加参数的说明。
public class EmailSKill { [SKFunction("Send email conten to receiver")] [SKFunctionContextParameter(Name ="content", Description = "email content")] [SKFunctionContextParameter(Name ="receiver", Description = "the email address of receiver")] public void SendTo(SKContext context){ var email = context["content"]; var receiver = context["receiver"]; Console.WriteLine( $""" mail to: {receiver} {email} """); } }
准备好技能之后,就可以将这些技能导入到Kernel中,等待后续使用。
作为示例,这里导入了三个功能:
MySkill.WriteText
: 文案写作MySkill.Translate
:文本翻译email.SendTo
: 邮件发送
使用Planner
然后我们就可以开始使用 Planner了。
0.13之前版本
Planner本身也是 Semantic Kernel中的一个Skill,融合了Semantic Function 和 Native Function。和通常的Skill一样,导入 PlannerSkill 后即可使用。
var planner = kernel.ImportSkill(new PlannerSkill(kernel),"plan");
Planner作为一个核心组件,在0.13版本之后从Skill中提升了出来,目前(0.13版本)使用了独立的SequentialPlanner,直接创建即可使用。
var planner = new SequentialPlanner(kernel);
指定好任务目标。
var goal = "The PowerBlog is about to release a new product, please write a chinese press release about the new product and send it to mail@example.com";
0.13之前版本
然后就可以执行 `CreatePlan` 创建一个Plan。var plan = await kernel.RunAsync(goal,planner["CreatePlan"]);
此时可以使用Plan.PathString查看当前的任务编排。
Plan所有状态的结果都会保存在Context中,所以可以通过 context.Variables.ToPlan()
方法获取Plan对象。
plan.Variables.ToPlan().PlanString.Dump("Create Plan"); /* The PowerBlog is about to release a new product, please write a chinese press release about the new product and send it to mail@example.com */
然后就可以直接使用 SequentialPlanner 创建一个Plan了。
var plan = await planner.CreatePlanAsync(goal);
此时可以使用plan.ToJson(),查看任务编排的情况。
plan.ToJson().Dump("Create Plan");
0.13之前版本
创建好了 Plan 就可以使用 ExecutePlan
执行了。
由于每次只能执行一个Function,所以我们需要通过循环来执行所有Function。
同时根据Plan的状态,判断是否执行成功,是否执行完成。
Plan 有两种状态,一种是 IsSuccessful
,表示当前的Plan是否执行成功。
另一个是 IsComplete
,表示整个Plan是否执行完成。
async Task ExecutePlanAsync(IKernel kernel, SKContext plan) { var executionResults = plan; while (!executionResults.Variables.ToPlan().IsComplete) { var result = await kernel.RunAsync(executionResults.Variables, planner["ExecutePlan"]); var planResult = result.Variables.ToPlan(); if (planResult.IsSuccessful) { if (planResult.IsComplete) { break; } } else { break; } executionResults = result; } return executionResults; } var result = await ExecutePlanAsync(kernel,plan); // output: /* mail to: mail@example.com 介绍PowerBlog——专为企业和企业家设计的终极博客平台。我们的新产品旨在帮助您轻松创建、管理和优化博客内容。 PowerBlog是为想要创建与竞争对手不同的专业博客的企业和企业家完美的解决方案。通过我们的直观用户界面,您可以快速创建和管理博客文章,优化SEO内容,并跟踪博客的性能。 我们的新产品还包括强大的功能,如自动内容策划、社交媒体整合和分析工具。通过这些功能,您可以轻松监控博客的性能,并就内容策略做出明智的决定。 PowerBlog是为想要创建与竞争对手不同的专业博客的企业和企业家完美的解决方案。通过我们的直观用户界面,您可以快速创建和管理博客文章,优化SEO内容,并跟踪博客的性能。 我们很高兴向客户提供这款新产品,期待帮助您创建一个成功的博客。今天就注册,开始创建与竞争对手不同的内容吧。 */
最后根据状态判断Plan最后执行是否成功,并从plan.Result
中获取最后的输出结果。
if(!result.Variables.ToPlan().IsSuccessful) { result.Variables.ToPlan().Result.Dump("Complete!"); }else { result.Variables.ToPlan().Result.Dump("Error"); } /* :Complete!: 介绍PowerBlog——专为企业和企业家设计的终极博客平台。我们的新产品旨在帮助您轻松创建、管理和优化博客内容。 PowerBlog是为想要创建与竞争对手不同的专业博客的企业和企业家完美的解决方案。通过我们的直观用户界面,您可以快速创建和管理博客文章,优化SEO内容,并跟踪博客的性能。 我们的新产品还包括强大的功能,如自动内容策划、社交媒体整合和分析工具。通过这些功能,您可以轻松监控博客的性能,并就内容策略做出明智的决定。 PowerBlog是为想要创建与竞争对手不同的专业博客的企业和企业家完美的解决方案。通过我们的直观用户界面,您可以快速创建和管理博客文章,优化SEO内容,并跟踪博客的性能。 我们很高兴向客户提供这款新产品,期待帮助您创建一个成功的博客。今天就注册,开始创建与竞争对手不同的内容吧。 */
0.13 版本之后,任务执行方法更加简单。
由于Plan本身就是一组 ISKFunction,所以可以直接使用 Kernel.RunAsync执行
var result = await kernel.RunAsync(plan);
和通常的Skill执行一样,查看result.Result即可得到结果。
result.Result.Dump("RESULT");
如果需要逐步执行查看结果,或者进行干预的话,也可以手动的调用执行过程。执行的状态都由Plan本身来维护,使用 HasNextStep
可以查看当前所有任务是否执行完成,可以使用Plan 的 InvokeNextStepAsync
来执行下一步,也可以使用Kernel的StepAsync
逐步执行。
async Task ExecutePlanAsync(IKernel kernel, Plan plan,string input = "") { while(plan.HasNextStep){ if(string.IsNullOrWhiteSpace(input)){ await kernel.StepAsync(plan); }else { await kernel.StepAsync(input,plan); } plan.State.Dump(); if(!plan.HasNextStep){ break; } } return plan; } await ExecutePlanAsync(kernel,plan);
Plan执行完成的结果,可以直接使用Plan.State.ToString()
获取。
plan.State.ToString().Dump("RESULT"); // output /* PowerBlog很高兴地宣布即将推出我们的最新产品,这将彻底改变人们生活的方式。我们一直在不懈努力地开发一款产品,它将对我们的客户生活产生重大影响,我们相信我们已经做到了这一点。 我们的新产品旨在成为一款改变游戏规则的产品,为用户提供独特的体验,增强他们的日常生活。我们相信,这款产品将成为任何想要提高生产力、效率和整体生活质量的人必备的产品。 我们知道人们总是在寻找简化生活的方法,而这正是我们的新产品的目的。它将帮助用户更好地管理时间,保持组织,更有效地实现他们的目标。 我们很高兴能够向我们的客户提供这款产品,我们迫不及待地想看到它对他们生活的积极影响。请继续关注我们最新产品的发布,准备体验一种新的生活方式。 */
至此,我们就掌握了Semantic Kernel 当前所有的核心概念和基本使用方法。
TIPS: 由于模型的能力问题,目前推荐使用GPT4模型执行以上操作。
参考资料: