Semantic Kernel dotnet 1.0 RC1 发布了,这是正式迈向 1.0 正式版的第一个候选版本。这个版本相对于1.0 Beta 8 变化非常的大。而且可能是因为发布的比较匆忙,Semantic Kernel 开发者的先行者们已经发现多个明显的 Bug。建议大家谨慎升级。
以下是部分我们认为比较重要的变更:
实现自动函数调用
实现自动 OpenAI(其他带函数调用的模型也可以)函数调用
自动调用行为是根据 autoInvoke 是否为 true 来处理的。通过在
PromptExecutionSettings基类的字典中设置命名属性,还可以以与服务无关的方式选择加入FunctionCallBehavior.AutoInvokeKernelFunctions; 如果未来的服务实现具有内置的函数调用概念(其他一些 LLM 也是如此),或者如果想使用嵌入到连接器实现中的规划器来模拟它,那么它们也可以尊从这个逻辑。
代码例子:
Kernel kernel = new KernelBuilder()
.WithOpenAIChatCompletion("gpt-3.5-turbo-1106", apiKey)
.ConfigurePlugins(plugins => plugins.AddPluginFromObject<TimePlugin>())
.Build();
OpenAIPromptExecutionSettings settings = new() { FunctionCallBehavior = FunctionCallBehavior.AutoInvokeKernelFunctions };
Console.WriteLine(await kernel.InvokePromptAsync("What is the current time?", settings));
这个部分的功能表现,简直太酷了。这是一个相当大的新变化,连接器可以自行触发功能,使 LLM 成为实际的计划执行者。
FunctionCallBehavior 中有几个选项可用:
FunctionCallBehavior.EnableKernelFunctions: 将发送所提供内核中的函数,但如果请求,不会自动调用;FunctionCallBehavior.AutoInvokeKernelFunctions: 将发送所提供内核中的函数,并在请求时自动调用;FunctionCallBehavior.EnableFunctions(functionsList, autoInvoke): 指定的函数将被发送,它们是否会被自动调用取决于autoInvoke参数以及它们在提供的内核中是否可用;FunctionCallBehavior.RequireFunction(function, autoInvoke): 指定的函数将作为函数调用请求发送到服务
流式/非流式处理的平等性
ChatCompletion
以前的
public interface IChatCompletion : IAIService
{
ChatHistory CreateNewChat(string? instructions = null);
Task<IReadOnlyList<IChatResult>> GetChatCompletionsAsync(ChatHistory chat, ...);
Task<IReadOnlyList<IChatResult>> GetChatCompletionsAsync(string prompt, ...);
IAsyncEnumerable<T> GetStreamingContentAsync<T>(ChatHistory chatHistory, ...);
}
public static class ChatCompletionExtensions
{
public static async Task<string> GenerateMessageAsync(ChatHistory chat, ...);
}
变更为
public interface IChatCompletionService : IAIService
{
Task<IReadOnlyList<ChatContent>> GetChatContentsAsync(ChatHistory chat, ..> tags)
IAsyncEnumerable<StreamingChatContent> GetStreamingChatContentsAsync(ChatHistory chatHistory, ...);
}
public static class ChatCompletionServiceExtensions
{
// v Single vv Standardized Prompt (Parse <message> tags)
public static async Task<ChatContent> GetChatContentAsync(string prompt, ...);
// v Single
public static async Task<ChatContent> GetChatContentAsync(ChatHistory chatHistory, ...);
public static IAsyncEnumerable<StreamingChatContent> GetStreamingChatContentsAsync(string prompt, ...);
}
TextCompletion
以前:
public interface ITextCompletion : IAIService
{
Task<IReadOnlyList<ITextResult>> GetCompletionsAsync(string prompt, ...);
IAsyncEnumerable<T> GetStreamingContentAsync<T>(string prompt, ...);
}
public static class TextCompletionExtensions
{
public static async Task<string> CompleteAsync(string text, ...);
public static IAsyncEnumerable<StreamingContent> GetStreamingContentAsync(string input, ...);
}
变更为:
public interface ITextCompletionService : IAIService
{
Task<IReadOnlyList<TextContent>> GetTextContentsAsync(string prompt, ...);
IAsyncEnumerable<StreamingTextContent> GetStreamingTextContentsAsync(string prompt, ...);
}
public static class TextCompletionServiceExtensions
{
public static async Task<TextContent> GetTextContentAsync(string prompt, ...);
}
函数调用 stepwise planner 改进
- 将
kernel参数从构造函数移动到ExecuteAsync中 - 使用语义函数生成初始计划,并从 YAML 加载提示和设置
- 根据为 planner 指定的最大令牌数检查估计的令牌计数
FunctionCallingStepwisePlannerConfig 增加了几个属性来支持这些改进:
/// <summary>
/// The ratio of tokens to allocate to the completion request. (prompt / (prompt + completion))
/// </summary>
public double MaxTokensRatio { get; set; } = 0.1;
internal int MaxCompletionTokens { get { return (int)(this.MaxTokens * this.MaxTokensRatio); } }
internal int MaxPromptTokens { get { return (int)(this.MaxTokens * (1 - this.MaxTokensRatio)); } }
HandleBars Planer 的遥测支持

重命名
Planners.Handlebars独立包形式存在,在 nuget 上的完整名是Microsoft.SemanticKernel.Planners.Handlebars将类、方法中的
SK前缀改为Kernel,
比如:
SKFunction改为KernelFunctionSKException改为KernelExceptionISKPlugin改为IKernelPlugin- 等等
AIRequestSettings改名为PromptExecutionSettings引入
KernelFunctionArguments作为Kernel.InvokeAsync和KernelFunction.InvokeAsync方法的参数。奇葩的是在之后的修改中又将KernelFunctionArguments重命名为KernelArguments了,以便额外支持KernelFunctions以外的其他组件(prompt template、planner 等);也因此相关的一些参数也从IDictionary<string, string>类型变更为KernelArguments。且KernelArguments开始支持非字符串参数:
InvokeAsync(Kernel kernel, SKContext context, AIRequestSettings? requestSettings, CancellationToken cancellationToken)变为InvokeAsync(Kernel kernel, KernelArguments arguments, CancellationToken cancellationToken)InvokeAsync(this Kernel kernel, KernelFunction function, ContextVariables variables, CancellationToken cancellationToken)变为InvokeAsync(this Kernel kernel, KernelFunction function, KernelArguments arguments, CancellationToken cancellationToken)
KernelFunction.GetMetadata从方法变为属性Function.Metadata重构了
PromptTemplateConfig:
requestSettings重命名为executionSettings- 合并了
PromptTemplateConfig和PromptFuncitonModel- prompt 函数的 config.json 中的
models改名为execution_settingsKernelFunctionFromPrompt的Create方法增加了promptTemplateFactory
AzureTextCompletion重名为AzureOpenAITextCompletionRunStreamingAsync更名为InvokeStreamingAsync,并连同InvokeAsync一起变为Kernel的自有方法,而不再是扩展方法。包
Microsoft.SemanticKernel.TemplateEngine.Handlebars改名为Microsoft.SemanticKernel.PromptTemplate.Handlebars将
ModelResult从Microsoft.SemanticKernel.Orchestration移动到Microsoft.SemanticKernel.AI将
KernelBuilder的方法重命名为With而不是Configure。为了保持一致性,还将参数的顺序更改为WithPlugins优先,以便所有重载都首先具有插件集合,并且将集合的类型更新为类型更强的KernelPluginCollection而不是ICollection<IKernelPlugin>命名空间中的
OpenAPI重命名为OpenApiIChatCompletion接口及其所有实现都重命名为具有Service后缀ITextCompletion重命名为ITextGenerationServiceImageGeneration重命名为TextToImage
有两个重要的称呼正式变更了
- 正式将
Semantic Function改称为Prompt Function。 - 正式将
Native Function改称为Method Function。
其他
- AIServices 将必须使用模型 ID 进行配置
- 修复了发出多个函数调用导致 OpenAI 返回 500 内部服务器错误的问题
- 更改事件处理程序取消的方式,并简化了
FunctionResult,开发者可以通过检查可为空字典来检查是否有元数据。 - 将
ExperimentalAttribute添加到 Semantic Kernel 的 .NET SDK 中的包和类,以标记Semantic Kernel v1.0.0 中尚未准备好的内容。 - Chat Completion API 的标准化提示输入支持(例如
<message>) - 提取了一个
TypeConverterFactory实用工具类,统一为FunctionResult和KernelFunctionFromMethod提供相同的类型转换功能。 - 移除了
KernelNameAttribute,并为KernelFunctionAttribute增加了一个 Name 属性。 原来需要在一个方法上加[KernelName("email_addresses")]和[KernelFunction]的合并为一个[KernelFunction("email_addresses")]即可 - 恢复了
ChatHistory流式消息输入的支持 - 修复 OpenAI JSON manifest 解析问题(下划线小写)
- 增加了一个用于使用
System.Text.Json的序列化方法序列化自定义类型的 ADR。旨在简化自定义类型的使用,允许开发者使用任何可以通过System.Text.Json进行序列化的类型。在 JSON 可序列化类型上进行标准化是必要的,以便使用 JSON 模式在 Planner 的函数手册中描述函数。使用 JSON 模式来描述函数的输入和输出类型将允许 Planner 验证函数的使用是否正确。 - 清理了旧的流式处理 API
- 删除了
SKContext类 - 新的 Planner 不再以来 Planner Core,以便可以独立发布
- Assistant Experimental 功能做了更新
- 清理一些扩展方法类
- 除了
Microsoft.SemanticKernel.Connectors.Memory.Postgres.PostgresMemoryEntry以外所有其他record都改回了class
有时开发者希望对可变数据或行为数据进行建模,这些数据具有复杂或自定义逻辑,用于更改其状态、验证其不变量或与其他对象交互。此类数据的示例包括 UI 控件、服务、存储库、工厂等。在这些情况下,类可以为数据及其行为的实现和封装提供更大的灵活性和控制。也希望避免创建和复制 record 实例的潜在性能开销,尤其是当它们具有许多或大型属性时,或者如果它们经常更新或传递。record 在后台作为引用类型实现,因此它们仍然会产生内存分配和垃圾回收的成本,并且在与表达式或解构一起使用时,它们还可能生成比类更多的中间对象和副本。此外,record 使用反射来实现其某些方法,例如 ToString 和 equality,这也可能会影响性能。亦或希望依赖基于类的语义的现有代码或框架进行互操作,例如序列化、反射、数据绑定、依赖关系注入等。其中一些方案可能不完全兼容或支持 record,或者可能需要额外的配置或自定义才能按预期工作。例如,某些库可能不容易序列化或反序列化记录,或者可能不支持某些数据绑定功能,如更改通知或验证。
结语
Semantic Kernel dotnet 的这个版本变更很大,也存在一些比较明显的 bug,在跟最新的 .NET 8 兼容上也存在一些潜在的问题,预计官方在本周内会发布一个新的修正版。建议大家先不要着急升级到这个版本,等待下个更稳定的版本发布后再跟进升级。当然了尝鲜研究者除外啊