Semantic Kernel dotnet 1.0 每天一个RC 版,让人应接不暇。dotnet-1.0.0-rc3 刚刚发布,Semantic Kernel 团队貌似在全力准备 12月15日发布 1.0 正式版。
让我们看一下这个版本的主要变更吧:
重命名
- 将
Azure Cognitive
改名为Azure AI Search
KernelBuilder
的WithServices/WithPlugins
回调的方法,改为Services/Plugins
属性。这样做虽然降低了流畅性,但它使之与 ASP.NET 当前使用的最佳实践模式保持一致,减少了嵌套,避免了关于回调何时被调用的混淆,避免了与异步相关的问题,并且使得在构建之前向构建器添加插件的语法与构建之后向 Kernel 添加插件的语法非常接近。- 将
KernelBuilder
相关的With
前缀的方法重命名为Add
(例如,WithOpenAIChatCompletion
),以提高与当前 ASP.NET 实践的一致性,以及在使用 builder.AddXx 和 builder.Services.AddXx 时的一致性。 - 将
Kernel
和KernelPluginFactory
相关的AddPluginFromObject
方法 重命名为AddFromType
增强
- 修正了
AzureOpenAITextEmbeddingGeneration
的modelId
参数顺序 - 确保
KernelPromptTemplate
不会将已解析的提示变量重新添加回集合,以防止参数集合KernelArguments
发生变异。 - Kernel prompt template 开始初步支持处理字符串以外的类型,包括 int、decimal、bool、object 等,甚至于复杂类型。
限制: 鉴于 Kernel prompt template 正在修改以支持基元操作,目前可以合理地预期提示中会出现类似这样的表达方式:
{{p.f a=28}}
,其中数字28
没有使用单引号或双引号包围,并且最终作为整数参数传递给函数,避免了不必要的字符串到整数的转换。然而,支持这种表达式将需要对CodeTokenizer
类进行修改,这个部分 Semantic Kernel 团队将在后续PR中跟踪处理。
- Kernel prompt template 在缺少参数或具有 null 值的参数将作为 null 参数(而不是空字符串)传递给方法调用。常规提示变量,如 {{$foo}} 的行为保持不变,只是在提示中插入一个空字符串。此更改可确保 Kernel prompt template 与 handlebars prompt template 的行为一致。
- 为了支持泛行函数结果
FunctionResult<T>
的情况,为Kernel
和KernelFunction
增加了支持泛行结果的Task<TResult?> InvokeAsync<TResult>
扩展方法:
var result = await kernel.InvokeAsync(functions["Function1"]);
var customType = result.GetValue<MyCustomType>()!;
Console.WriteLine(customType.Number); // 2
Console.WriteLine(customType.Text); // From Function1 + From Function2
将可以变成:
var customType = await kernel.InvokeAsync<MyCustomType>(functions["Function1"]);
Console.WriteLine(customType.Number); // 2
Console.WriteLine(customType.Text); // From Function1 + From Function2
- 增加了
IKernelBuilder
接口。它由KernelBuilder
实现,并通过IServiceCollection
上的一个新的AddKernel
扩展方法返回,该方法向容器中添加了一个单例KernelPluginCollection
和一个瞬态Kernel
。IKernelBuilder
既有Services
属性也有Plugins
属性,并且还有Build
方法,但如果在从AddKernel
返回的实例上使用 Build 方法,它会抛出一个异常,因为这可能导致人们不小心多次构建容器。 - 将
KernelBuilder
上的所有扩展方法都更改为IKernelBuilder
。
重要行为变化
- 作为服务添加的插件现在会自动在
Kernel
构建过程中被解析。如果显式提供了集合,Kernel
会首先使用该集合;如果没有提供,它将尝试从服务中获取一个集合;如果还找不到,它将尝试从服务中获取所有的IKernelPlugins
。
其他
- 从
AddFromType
中移除new()
约束,改用ActivatorUtilities.CreateInstance
。KernelBuilder.Plugins
属性和builder
拥有相同的IServiceCollection
,因此AddFromType
可以利用它和CreateInstance
,从服务提供者中解析插件对象的构造函数参数。例如,HttpPlugin
有一个接受HttpClient
的构造函数,如此一来在Build
过程中的构建插件时,使用builder.Plugins.AddFromType()
就会在容器中找到HttpClient
并自动使用它。 - 移除了
WithLoggerFactory
和WithCulture
。后者基本上从未被使用,它更像是Kernel
上的Data
属性和事件处理程序,可以很容易地在Kernel
实例上进行修改,不需要任何构建器支持。WithLoggerFactory
虽然被频繁使用,但主要是因为测试中使用的模式,而且可以通过AddLogging
轻松替代。 - 增加了更多面对 Handlebars planner 的单元测试,将代码覆盖率提升到了71%以上
- 修复了
FunctionCallingStepwisePlanner
的计划生成的prompt - 修复了将
StandardizedPrompt
与 Kernel/Function 的InvokeAsync
结合使用时,ChatCompletions
未能正确解析的 bug - 删除了一些容易引起混淆的示例
- 其他的一些小 bug 的修复和代码优化
结语
最近 Semantic Kernel 团队非常拼命的努力推进 1.0 正式版的进程,虽然看起来发布版本的速度有点过于频繁,但是从每次的变更内容来看,整体都在为了让开发者更容易上手,更容易开发稳定高效的智能应用而奋进,且已经看到了明显的进步。
以目前的变更速度,我建议大家先不要过频跟进新版本,可以等待一下更稳定的1.0 RC或者正式版之后再整体升级,以避免一些工作的浪费。