十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Semantic Kernel 函数与内核结果类型演进:从 SKContext 到 FunctionResult / KernelResult 的设计解析与实践指南

Semantic Kernel 函数与内核结果类型演进:从 SKContext 到 FunctionResult / KernelResult 的设计解析与实践指南 Semantic Kernel 函数与内核结果类型演进从 SKContext 到 FunctionResult / KernelResult 的设计解析与实践指南【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel导读本文基于 Semantic Kernel 仓库中的架构决策记录 ADR 0011Replace SKContext as Function/Kernel result type with FunctionResult and KernelResult models系统梳理 .NET 版 Semantic Kernel 将函数调用与内核执行的结果类型从SKContext迁移到FunctionResult/KernelResult的完整设计脉络。你将理解为什么需要这两个新类型、object Value与泛型GetValueT如何支撑复杂类型与流式返回、Metadata如何携带执行元数据以及如何从FunctionResults集合中精准定位流水线中任意函数的结果。文中所有示例均以当前仓库中 FunctionResult.cs 的真实实现为基准可直接对照使用。一、背景为什么SKContext不再适合作为结果类型在引入FunctionResult/KernelResult之前function.InvokeAsync与kernel.RunAsync都以SKContext作为返回类型。该架构决策记录0011-function-and-kernel-result-types.md指出了四个核心问题无法返回复杂类型SKContext的Result属性是string任何非字符串的返回都被迫序列化为文本更谈不上支持流式streaming能力。耦合了 LLM 专属逻辑SKContext中的ModelResults属性与具体模型响应强绑定仅对部分场景下的语义函数适用无法作为通用的结果载体。职责错位SKContext本质上是流水线内部在多个函数之间传递信息的机制不应暴露给调用方。调用 Kernel 的人应该给输入、拿结果而不是拿到一个内部上下文对象。缺少流水线细粒度信息SKContext只携带最后一次执行的函数相关信息无法回答流水线中某个特定函数到底返回了什么、表现如何。这四个痛点共同指向一个结论结果类型必须与内部上下文机制解耦。二、决策驱动与备选方案决策驱动该 ADR 明确了五项决策驱动因素成为后续设计的验收标准Kernel 应能返回复杂类型同时支持流式能力Kernel 应能以不耦合 AI 逻辑的方式返回函数执行数据例如 token 用量SKContext退居为函数之间传递信息的内部机制由于函数结果与内核结果本质不同、未来可能承载不同的属性集合二者应可区分调用方应能访问流水线中间某个特定函数的结果从而洞察每个函数的执行表现。备选方案对比方案说明结论使用dynamic作为返回类型提供一定灵活性但破坏 .NET 世界推崇的强类型且无法区分函数结果与内核结果被否决定义新类型FunctionResult与KernelResult保持强类型语义清晰两种结果各自演进被采纳最终决策是新建FunctionResult与KernelResult两个返回类型覆盖复杂类型返回、流式支持以及按函数分别访问结果的能力。三、核心设计object Value 泛型GetValueT设计思想FunctionResult中用object Value存放单个函数的结果KernelResult中用object Value存放执行流水线中最后一个函数的结果。为了让调用方以强类型方式取回数据两个类型都提供泛型方法GetValueT将object Value安全地转型为目标类型。当前仓库中FunctionResult的实现保留了这一设计骨架并做了一处值得注意的演进Value属性被标记为internal见 FunctionResult.cs外部代码统一通过GetValueT()访问进一步强化了类型安全的访问入口。基础用法示例以下是 ADR 文档中的原始示例展示了字符串、复杂类型与流式三种场景// string var text (await kernel.RunAsync(function)).GetValuestring(); // complex type var myComplexType (await kernel.RunAsync(function)).GetValueMyComplexType(); // streaming var results (await kernel.RunAsync(function)).GetValueIAsyncEnumerableint(); await foreach (var result in results) { Console.WriteLine(result); }在当前仓库 API 形态下Kernel.RunAsync已演进为Kernel.InvokeAsync返回TaskFunctionResult见 Kernel.cs同样语义的代码可写为// 单函数调用直接返回 FunctionResult FunctionResult result await kernel.InvokeAsync(function); // string var text result.GetValuestring(); // complex type var myComplexType result.GetValueMyComplexType();单元测试 KernelTests.cs 给出了最朴素的验证路径var function KernelFunctionFactory.CreateFromMethod(() Result, Function1); var result await kernel.InvokeAsync(function); Assert.NotNull(result); Assert.Equal(Result, result.GetValuestring());转型失败时的行为设计文档明确规定当FunctionResult/KernelResult中存的是TypeA而调用方试图转型为TypeB时应抛出携带类型明细的InvalidCastException帮助调用方快速定位应当使用的目标类型。当前实现中这一契约被完整保留且转换逻辑大幅增强——GetValueT()不止做简单强转还内置了对KernelContent、ChatMessageContent列表、Microsoft.Extensions.AI.ChatResponse等聊天内容类型的自动转换分支例如Value为ChatMessageContent且目标为string时返回其ToString()Value为IReadOnlyListChatMessageContent且目标为ChatResponse/ChatMessage时自动取首条消息转换当目标类型不可转换时统一抛出InvalidCastException($Cannot cast {this.Value.GetType()} to {typeof(T)})FunctionResult.cs。从源码结构看这些分支主要是为了在向Microsoft.Extensions.AI抽象迁移的过渡期保持与既有KernelContent代码的兼容FunctionResult.cs属于实现细节层面的自然演化。四、元数据Metadata属性设计初衷为了让调用方了解函数执行得怎么样FunctionResult增加了Dictionarystring, object Metadata属性用于携带任何执行相关信息例如 token 用量、模型响应等且不依赖具体 AI 提供方。当前实现在 FunctionResult.cs 中Metadata的实际类型是IReadOnlyDictionarystring, object??可通过构造函数以可选参数注入FunctionResult.cspublic FunctionResult( KernelFunction function, object? value null, CultureInfo? culture null, IReadOnlyDictionarystring, object?? metadata null)ADR 文档中的原始访问示例var functionResult await function.InvokeAsync(context); Console.WriteLine(functionResult.Metadata[MyInfo]);当前仓库中原生函数返回带元数据结果的典型写法见测试 FunctionFromMethodTests.csvar kernel new Kernel(); var sut KernelFunctionFactory.CreateFromMethod((KernelFunction func) { return new FunctionResult(func, Full content result, metadata: new Dictionarystring, object?() { { key1, value1 }, { key2, value2 }, }); }); var result await sut.InvokeAsync(kernel); Assert.Equal(value1, result.Metadata[key1]); Assert.Equal(value2, result.Metadata[key2]);该测试还验证了一个细节原生函数返回的FunctionResult元数据在流式调用InvokeStreamingAsync时也会被传播到StreamingMethodContent.Metadata上说明Metadata并不局限于一次性调用而是贯穿同步/流式两种执行路径。其他附带属性除了Value、Metadata之外FunctionResult当前还包含以下成员可作为排障与观测的补充信息Function产生该结果的KernelFunction实例FunctionResult.csCulture执行该函数的 Kernel 所配置的文化信息默认CultureInfo.InvariantCultureFunctionResult.csValueTypeValue的实际运行时类型FunctionResult.csRenderedPrompt函数调用时实际渲染出的提示词文本FunctionResult.cs对排查提示词工程问题非常有用。五、多函数结果KernelResult.FunctionResults设计目标KernelResult包含IReadOnlyCollectionFunctionResult FunctionResults用于保留流水线中每个函数各自的结果同时FunctionResult上提供FunctionName与PluginName属性方便调用方从集合中按名字精确取回指定函数的结果。ADR 文档给出的示例var kernelResult await kernel.RunAsync(function1, function2, function3); var functionResult2 kernelResult.FunctionResults.First(l l.FunctionName Function2 l.PluginName MyPlugin); Assert.Equal(Result2, functionResult2.GetValuestring());在仓库中的对应物从当前源码结构看KernelFunction正是通过Name与PluginName提供这两个标识的PluginName默认可从函数元数据中读取KernelFunction.csName则由每个函数实现KernelFunction.cs且ToString()会输出PluginName.Name的完整形态KernelFunction.cs。这意味着调用方不仅能拿到流水线最后一个结果还能逐个审视每个函数产出了什么、占用了多少资源这正是 ADR 决策驱动中访问流水线中间函数结果诉求的直接体现。六、该决策对当前代码库的落地情况该 ADR2023-09-21 提出状态 accepteddeciders 为 shawncal 与 dmytrostruk的核心理念在当前代码库中已被完整吸收并持续演进FunctionResult已成为唯一标准结果类型KernelFunction.InvokeAsync返回TaskFunctionResultKernelFunction.csKernel.InvokeAsync两个重载同样返回TaskFunctionResultKernel.cs流式能力独立成通道Kernel.InvokeStreamingAsync返回IAsyncEnumerableStreamingKernelContentKernel.cs与 ADR 中支持流式的目标一脉相承内部上下文彻底退居幕后SKContext不再出现在对外返回类型中函数间信息传递由内部机制承担调用方只与FunctionResult交互测试充分覆盖单元测试对GetValueT、Metadata、多插件导入与调用等行为均有断言KernelTests.cs、FunctionFromMethodTests.cs可作为阅读实现与验证行为的参考入口。七、实践小结围绕如何正确消费函数执行结果可以总结出以下可直接落地的要点统一走GetValueT()无论目标是string、自定义复杂类型还是聊天内容类型都以泛型方式取回避免直接触碰内部Value利用Metadata观测执行细节在原生函数中通过构造函数注入metadata字典即可让调用方读取 token 用量、模型响应等自定义信息且该信息在流式路径同样可用按需精确取结果多函数流水线场景下通过FunctionResults结合FunctionName/PluginName定位特定函数的结果而不是只依赖最后一个返回值把SKContext留给内部对外 API 一律面向FunctionResult设计保持输入-输出模型的清晰与强类型化。参考资源架构决策记录docs/decisions/0011-function-and-kernel-result-types.md结果类型实现dotnet/src/SemanticKernel.Abstractions/Functions/FunctionResult.cs调用入口dotnet/src/SemanticKernel.Abstractions/Kernel.cs函数抽象dotnet/src/SemanticKernel.Abstractions/Functions/KernelFunction.cs行为验证测试dotnet/src/SemanticKernel.UnitTests/KernelTests.cs、dotnet/src/SemanticKernel.UnitTests/Functions/FunctionFromMethodTests.cs【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表