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

发布时间:2026/11/8 18:30:17

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),仅供参考
延伸阅读

更多相关文章

2026/11/8 17:50:39

RVM多输入多输出回归:贝叶斯稀疏建模与不确定性量化

简介:本资源是一套基于MATLAB实现的相关向量机(RVM)多输入多输出(MIMO)回归建模方案,面向本科及以上层次的机器学习初学者、统计建模研究者及工程实践人员,适用于小样本非线性系统建模、传感器融…

2026/11/7 21:31:52

国产芯片替代实测:ST/TI/NXP对标验证与工程落地避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/8 21:52:06

跨境电商动态定价系统:实时监控与利润优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/8 21:57:33

女士能考高压电工证吗?上岗必备证书过期怎么办理

女士能考高压电工证吗?上岗必备证书过期怎么办理 证书过期了不知道怎么复审延期?别慌,这可能是你正在经历的困境。尤其是在高压电工证这类“上岗必备”的特种作业证书上,一旦过期就可能面临停岗、降薪甚至被清退的风险。很多人以为高压电工证是“男士专属…

2026/11/8 21:57:33

注册电器气 电工证怎么转回本地?官方报名入口在这儿

注册电器气 电工证怎么转回本地?官方报名入口在这儿 之前考的证在外省能不能转过来?这几乎是每个想把外地电工证转回老家的从业者都会问的问题。尤其是像郑州这样的城市,建筑、工程、电力行业从业者众多,很多人都是从外地过来打工,手里拿着外地的…

2026/11/8 21:57:33

怎样报考高压电工证合格标准与通过率

高压电工证怎么考?通过率揭秘+实操技巧全解析 实操考试心里没底怕挂科?别急,高压电工证虽然含金量高,但只要准备到位,通过率其实不低。尤其是掌握了正确的备考方法和考试技巧,很多人都顺利拿下了证书。本文将结合河南省安全技术防范行业协会的规范要求…

2026/11/8 21:57:33

商丘办电工证在哪里真实经历告诉你怎么避坑

商丘办电工证在哪里真实经历告诉你怎么避坑 不知道去哪报名怕被中介坑?这事儿我懂,去年我一个朋友在驻马店转岗,也是走了不少弯路,最后才明白, 商丘办电工证在哪里 这个问题,不能随便听信别人,得自己搞清楚。…

2026/11/8 21:57:33

注册电器气 电工证证丢了怎么补办

注册电器气电工证丢了怎么补办?良心建议帮你少走弯路 你是不是也在担心, 注册电器气电工证 丢了怎么办?是不是怕被中介骗钱、被坑?别慌,今天我就从一个干了十多年的老手角度,给你讲讲怎么补办,怎么不被坑,怎么选对路。…

2026/11/8 0:00:27

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/8 0:00:27

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑