资讯动态

Semantic Kernel 错误处理改进实战指南:基于 ADR-0004 的 .NET 异常体系设计与落地

发布时间:2026/9/12 8:13:23 来源:尧图企业网站定制
Semantic Kernel 错误处理改进实战指南基于 ADR-0004 的 .NET 异常体系设计与落地【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel导读本文以官方架构决策记录 docs/decisions/0004-error-handling.md 为骨架系统梳理 Semantic KernelSK在 .NET 侧错误处理的设计演进从异常存入 SKContext到异常向上抛出、从自定义 SK 异常泛滥到优先使用 .NET 标准异常、再到HttpOperationException的统一 HTTP 错误抽象。读完本文你将理解 SK 异常体系的取舍逻辑掌握KernelException、HttpOperationException、KernelFunctionCanceledException的正确用法与源码级实现细节并能在自己的 SK 应用中以标准 .NET 方式处理异常。适用范围说明本 ADR 与下文引用的源码均位于dotnet/目录面向 .NET 版本的 Semantic Kernel SDK。文档明确声明本文不涉及日志logging、弹性resiliency与可观测性observability三个领域。背景SK 错误处理存在的五个问题ADR-0004 发布于 2023-06-23状态accepted记录于 0004-error-handling.md。它指出当时 SK 的错误处理在五个方面偏离了 .NET 惯例异常传播方式特殊Kernel.RunAsync、SKFunction.InvokeAsync等公开方法不抛异常而是捕获后存入SKContext。这违反了 .NET 契约满足则成功执行、契约违反则抛出异常 的标准约定客户端开发者必须分析SKContext的特定属性才能判断调用是否成功体验糟糕。异常使用不当部分组件用自定义 SK 异常表达参数非法配置错误等场景而这些场景本应使用ArgumentNullException、ArgumentOutOfRangeException等 .NET 标准异常。异常层级不统一一半自定义异常派生自SKException另一半直接派生自Exception异常模型缺乏一致性。存在多余且冗长的异常Kernel、Planner 各自的KernelException、PlanningException以及每个 Memory 连接器专属的PineconeMemoryException、QdrantMemoryException等除了名字不同、成员签名完全相同不携带额外信息。这让客户端无法用单一 catch 块统一处理新增或移除一个组件实现就要改动一次客户端代码。丢失原始异常细节某些 SK 异常不保留原始失败原因也不通过属性暴露客户端无从理解问题根源、无法正确处理。决策驱动因素五条设计原则该 ADR 在 Decision Drivers 中确立了五条指导原则后续所有方案都围绕它们展开异常应传播给 SK 客户端代码而非存储在SKContext中使 SK 错误处理回归 .NET 惯例异常层级遵循少即是多less is more新增异常容易删除困难因此初始设计应尽量精简优先使用 .NET 标准异常而非 SK 自定义异常它们易识别、零维护成本、覆盖常见错误场景、提供标准化错误消息除非有助于 SK 或客户端构建可执行的应对逻辑否则不应将异常包装进 SK 异常再抛给调用方隐含约束保留原始异常为 InnerException缺失的必须补齐。决策方案七项改进措施方案一精简自定义异常层级移除除SKException及其有实际用途的派生类型之外的所有自定义异常类型需要传达更多细节时才创建新的派生异常。这一方案在当前仓库中的落地结果是原先的SKException已被统一为 KernelException.csMicrosoft.SemanticKernel命名空间下public class KernelException : Exception它成为所有 Semantic Kernel 异常派生的基类提供标准的三个构造函数无参、仅消息、消息 内层异常并在Exception.Data中可选携带符合 OpenTelemetry 标准的遥测信息。从源码结构看SemanticKernel.Abstractions项目内仅保留了两个公开异常类型KernelException.cs 与 HttpOperationException.cs外加一个特殊用途的 KernelFunctionCanceledException.cs见下文方案的落地形态。这种核心异常数量极少、按需派生的形态正是less is more原则的直接体现。方案二用 .NET 标准异常替代自定义异常当类参数值缺失或非法时抛ArgumentOutOfRangeException、ArgumentNullException等标准异常而非自定义 SK 异常并全面审查异常使用点找出其他可替换为标准异常的地方。这一方案在 KernelFunctionFromMethod.cs 中有典型实现当参数值类型不匹配且转换失败时代码抛ArgumentOutOfRangeException(name, value, e.Message)同时注意捕获条件catch (Exception e) when (!e.IsCriticalException())——非关键异常才被转换为参数范围异常关键异常直接向上传播。而在参数缺失这类无法用标准异常覆盖的场景实现则以KernelException包装标准异常例如 KernelFunctionFromMethod.cs 抛KernelException(Missing service for function parameter {parameter.Name}, new ArgumentException(...))L713-L714 抛KernelException(Missing argument for function parameter {name}, new ArgumentException(...))。这种外层 KernelException 内层标准异常的组合既保留了 SK 的统一入口又通过 InnerException 暴露了标准化的错误语义。方案三移除仅为包装而包装的异常删除仅仅为了包装而把未处理异常包进AIException或其他 SK 异常的逻辑——这类包装除了给出Something went wrong这类无信息量的通用消息外毫无用处。结合方案二可见当前仓库中KernelException的用法已经从纯包装收敛为携带可行动信息如缺失参数名、缺失服务、非法函数名等场景例如MemoryBuilder.cs依赖未注入时抛出带明确指引的KernelExceptionUseWithMemoryStoremethodFunctionIdBlock.cs非法函数名抛出带规则说明的KernelExceptionNamedArgBlock.cs命名参数格式错误时抛出带分隔符说明的KernelExceptionKernelPromptTemplate.cs 与 CodeBlock.cs模板解析错误抛出携带错误详情的KernelException。方案四保留原始异常为 InnerException排查所有重新抛出 SK 异常但未保留原始异常的场景并逐一修复。这条原则贯穿了上述所有KernelException(message, innerException)的调用点也体现在下文的HttpOperationException构造中。方案五引入 HttpOperationException 统一 HTTP 错误创建带StatusCode属性的HttpOperationException并实现从HttpStatusCode、HttpRequestException、Azure.RequestFailedException到该异常的映射逻辑所有与 HTTP 栈交互的 SK 代码在请求失败时抛出HttpOperationException并将原始异常设为 InnerException。当前实现位于 HttpOperationException.cs其关键设计标准构造器HttpOperationException()、HttpOperationException(string?)、HttpOperationException(string?, Exception?)增强构造器HttpOperationException(HttpStatusCode? statusCode, string? responseContent, string? message, Exception? innerException)核心属性StatusCodeHTTP 状态码为 null 表示未收到响应、ResponseContentHTTP 响应正文遗留属性RequestMethod、RequestUri、RequestPayload已标记[Obsolete]建议改用Exception.Data[Name]、Exception.Data[Url]、Exception.Data[Data]获取遥测兼容同KernelException一样可通过Exception.Data携带 OpenTelemetry 标准的键值信息。映射实现分为两处Azure/OpenAI 侧Azure.RequestFailedException通过 RequestFailedExceptionExtensions.cs 转换为HttpOperationException——当exception.Status 0NoResponseReceived时StatusCode为 null读取响应正文失败时静默吞掉保证一定抛出HttpOperationException而非其他异常OpenAI SDK 侧System.ClientModel的ClientResultException通过 ClientResultExceptionExtensions.cs 以相同模式转换Status 0→ null 状态码并尽力提取ResponseContent。调用链佐证OpenAI 连接器的 ClientCore.cs 中RunRequestAsyncT与RunRequestT两个方法统一try { ... } catch (ClientResultException e) { throw e.ToHttpOperationException(); }即所有 OpenAI 请求失败都收敛为HttpOperationException。单元测试 ClientResultExceptionExtensionsTests.cs 验证了三条关键行为无响应时StatusCode为 null 且保留原始异常为 InnerException有响应时正确回填StatusCode与ResponseContent消息与原始异常保持一致。方案六所有组件改为重新抛出异常将所有原本把异常存入 SK Context的组件改为重新抛出rethrow。这与方案一配合是 SK 错误处理向标准 .NET 模型靠拢的核心一步。落地后Kernel.InvokeAsync系列 API 的文档契约明确标注了KernelFunctionCanceledException见 Kernel.cs 的exception cref声明调用方可以用标准 try/catch 捕获异常而非检查上下文状态。方案七精简关键异常判定逻辑将IsCriticalException扩展方法精简为排除StackOverflowException与OutOfMemoryException前者根本不会被抛出调用代码不会执行后者不必然阻止恢复代码执行。当前实现位于 ExceptionExtensions.csIsCriticalException只对以下类型返回 trueex is ThreadAbortException or AccessViolationException or AppDomainUnloadedException or BadImageFormatException or CannotUnloadAppDomainException or InvalidProgramException;该扩展方法被 Kernel 核心执行路径广泛使用例如 KernelFunctionFromMethod.cs 的参数转换捕获以及 L1114 的文化回退逻辑catch (Exception e) when (!e.IsCriticalException() cultureInfo ! CultureInfo.InvariantCulture)——后者在特定文化解析失败时回退到 InvariantCulture 重试但关键异常不会被吞掉而是直接向上传播。方案的落地形态当前仓库中的异常全景将 ADR 的七项方案映射到当前仓库可以得到一张清晰的异常使用地图异常类型定义位置用途与 ADR 方案的关系KernelExceptionSemanticKernel.Abstractions/KernelException.cs所有 SK 异常的公共基类携带消息与 InnerException方案一精简层级、方案四保留 InnerExceptionHttpOperationExceptionSemanticKernel.Abstractions/Http/HttpOperationException.cs统一 HTTP 请求失败错误暴露StatusCode与ResponseContent方案五KernelFunctionCanceledExceptionSemanticKernel.Abstractions/Functions/KernelFunctionCanceledException.cs派生自OperationCanceledException当函数过滤器请求取消时由KernelFunction调用抛出附带Kernel、Function、Arguments、FunctionResult上下文方案六落地后的新增可行动异常ArgumentNullException/ArgumentOutOfRangeException等.NET BCL参数缺失、类型不合法等方案二关键异常ThreadAbortException等六类.NET BCL不捕获、直接传播方案七值得注意KernelFunctionCanceledException的设计KernelFunctionCanceledException.cs 将FunctionResult也纳入构造参数——当函数在成功完成后才被请求取消时调用方仍能从异常中取回函数结果。这正是 ADR 除非有助于构建可行动逻辑否则不包装原则的正面例证这个异常不是简单的包装而是携带了完整上下文、可被客户端直接消费的可行动类型。对 SK 客户端开发者的实践指引综合 ADR 决策与当前实现SK .NET 客户端代码应遵循以下异常处理范式1. 用标准 try/catch 处理调用结果。Kernel.InvokeAsync/KernelFunction.InvokeAsync的失败一律以异常形式呈现不要再检查上下文属性try { FunctionResult result await kernel.InvokeAsync(pluginName, functionName, arguments); Console.WriteLine(result); } catch (KernelException ex) when (ex.InnerException is ArgumentException) { // 参数缺失/非法根据 InnerException 的 ParamName 定位问题参数 } catch (HttpOperationException ex) when (ex.StatusCode is HttpStatusCode.TooManyRequests) { // 触发限流读取 ex.ResponseContent 获取服务端返回详情 } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { // 用户取消或函数过滤器请求取消 }2. 用IsCriticalException语义保护自己的恢复逻辑。仿照 KernelFunctionFromMethod.cs任何尝试失败后回退/重试的 catch 都应加when (!e.IsCriticalException())过滤避免吞掉进程级关键异常。3. 只捕获可行动的异常。对HttpOperationException优先按StatusCode分支处理对KernelException优先读取InnerException与消息中携带的参数名/指引如 MemoryBuilder 的 UseWithMemoryStoremethod 提示对无法恢复的错误直接放行交给上层或全局异常处理器。4. 识别遗留异常属性的迁移信号。若在旧代码中见到HttpOperationException.RequestUri/RequestMethod/RequestPayload应改用Exception.Data[Url]/[Name]/[Data]见 HttpOperationException.cs 的[Obsolete]标注。验证与测试错误处理契约的守护者ADR 的决策并非停留在设计文档层面仓库中的测试用例持续守护着这些契约ClientResultExceptionExtensionsTests.cs 验证ClientResultException → HttpOperationException转换的三种场景无响应、有响应正文、无正文确保StatusCode/ResponseContent/InnerException的映射准确ChatHistorySummarizationReducerTests.cs 验证消息归约器在 HTTP 失败时确实抛出HttpOperationException证明异常向上传播的契约生效集成测试侧Agents 与 Azure/OpenAI 连接器的多个测试如AzureOpenAIChatClientTests、OpenAIAssistantAgentTests在断言中引用了HttpOperationException印证其在真实服务交互路径上被一致抛出。延伸阅读完整决策记录docs/decisions/0004-error-handling.md异常类型实现KernelException.cs、HttpOperationException.cs、KernelFunctionCanceledException.cs异常转换工具RequestFailedExceptionExtensions.cs、ClientResultExceptionExtensions.cs关键异常过滤实现ExceptionExtensions.cs调用链示例ClientCore.cs、KernelFunctionFromMethod.cs单元测试ClientResultExceptionExtensionsTests.cs【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价