明志唯新

Semantic Kernel dotnet 1.0 RC1 发布

发表于
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 的遥测支持

image

重命名

  • Planners.Handlebars 独立包形式存在,在 nuget 上的完整名是 Microsoft.SemanticKernel.Planners.Handlebars

  • 将类、方法中的SK前缀改为Kernel

比如:

  • SKFunction改为KernelFunction
  • SKException改为KernelException
  • ISKPlugin改为IKernelPlugin
  • 等等
  • AIRequestSettings 改名为 PromptExecutionSettings

  • 引入 KernelFunctionArguments 作为 Kernel.InvokeAsyncKernelFunction.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
  • 合并了 PromptTemplateConfigPromptFuncitonModel
  • prompt 函数的 config.json 中的 models 改名为 execution_settings
  • KernelFunctionFromPromptCreate 方法增加了 promptTemplateFactory
  • AzureTextCompletion 重名为 AzureOpenAITextCompletion

  • RunStreamingAsync 更名为 InvokeStreamingAsync,并连同 InvokeAsync 一起变为 Kernel 的自有方法,而不再是扩展方法。

  • Microsoft.SemanticKernel.TemplateEngine.Handlebars 改名为 Microsoft.SemanticKernel.PromptTemplate.Handlebars

  • ModelResultMicrosoft.SemanticKernel.Orchestration 移动到 Microsoft.SemanticKernel.AI

  • KernelBuilder 的方法重命名为 With 而不是 Configure。为了保持一致性,还将参数的顺序更改为 WithPlugins 优先,以便所有重载都首先具有插件集合,并且将集合的类型更新为类型更强的 KernelPluginCollection 而不是ICollection<IKernelPlugin>

  • 命名空间中的 OpenAPI 重命名为 OpenApi

  • IChatCompletion 接口及其所有实现都重命名为具有 Service 后缀

  • ITextCompletion 重命名为 ITextGenerationService

  • ImageGeneration 重命名为 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 实用工具类,统一为 FunctionResultKernelFunctionFromMethod 提供相同的类型转换功能。
  • 移除了 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 兼容上也存在一些潜在的问题,预计官方在本周内会发布一个新的修正版。建议大家先不要着急升级到这个版本,等待下个更稳定的版本发布后再跟进升级。当然了尝鲜研究者除外啊

参考源: