Semantic Kernel 混合模型编排(Hybrid Model Orchestration)设计决策与实战指南

发布时间:2026/9/12 4:41:00
Semantic Kernel 混合模型编排(Hybrid Model Orchestration)设计决策与实战指南 Semantic Kernel 混合模型编排Hybrid Model Orchestration设计决策与实战指南【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel本篇文章以 Semantic Kernel 官方架构决策记录ADR0064-hybrid-model-orchestration.md 为主体系统讲解在本地 NPU 模型与云端模型之间进行混合推理编排的三种候选方案及其取舍并结合当前仓库中的源码与可运行示例深入剖析最终选定的IChatClient装饰器方案。读完本文你将理解为什么 ADR 选择每个编排策略实现为一个IChatClient的简单路线并能基于仓库内现成的FallbackChatClient示例在你的应用中实现本地/云端模型的无缝降级与容错切换。背景与问题陈述为什么需要混合模型编排随着本地模型与云端模型的不断涌现和持续改进加上终端设备 NPU神经网络处理器对本地 AI 推理的支撑日趋成熟AI 应用需要能够有效且无缝地同时利用本地与云端模型进行推理从而获得最佳的 AI 用户体验。这一诉求具体表现为两类典型场景离线优先与兜底应用默认使用云端模型当网络不可用或云端服务返回 5xx 错误时无缝切换到本地模型继续推理成本与延迟优化根据请求内容如输入 token 规模、数据敏感度动态选择合适的模型例如敏感数据只交给本地模型处理。要实现这些能力需要在应用与底层具体模型之间引入一层模型编排层model orchestration layer。ADR 明确提出了该编排层必须满足的三个决策驱动因素Decision Drivers模型编排层应简单且可扩展simple and extensible编排层对客户端代码不可见——调用方不应感知或处理底层编排的复杂性编排层应允许针对当前任务采用不同的模型选择策略。围绕这三个约束ADR 依次评估了三种实现方案最终确定了决策结果。候选方案一每个编排策略实现一个IChatClient最终采纳这是最简单、最直接的做法每种编排策略都作为IChatClient接口的一个独立实现。由于IChatClient是 Microsoft.Extensions.AI 生态中的统一聊天客户端抽象采用该方案不需要引入任何新的抽象层。以回退Fallback策略为例——优先使用第一个配置好的聊天客户端进行推理当该 AI 模型不可用时回退到下一个客户端public sealed class FallbackChatClient : IChatClient { private readonly IChatClient[] _clients; public FallbackChatClient(params IChatClient[] clients) { this._clients clients; } public TaskMicrosoft.Extensions.AI.ChatCompletion CompleteAsync( IListChatMessage chatMessages, ChatOptions? options null, CancellationToken cancellationToken default) { foreach (var client in this._clients) { try { return client.CompleteAsync(chatMessages, options, cancellationToken); } catch (HttpRequestException ex) { if (ex.StatusCode 500) { // 尝试下一个客户端 continue; } throw; } } } public IAsyncEnumerableStreamingChatCompletionUpdate CompleteStreamingAsync( IListChatMessage chatMessages, ChatOptions? options null, CancellationToken cancellationToken default) { // ... 流式实现 } public void Dispose() { /* 不能在此处释放客户端因为上游可能仍在引用它们 */ } public ChatClientMetadata Metadata new ChatClientMetadata(); public object? GetService(Type serviceType, object? serviceKey null) null; }延迟latency-based策略、token 计数token-based策略等其他编排策略都可以按同样的套路实现一个实现IChatClient的类 对应的客户端选择逻辑。该方案的优势不需要任何新抽象实现简单直接足以覆盖绝大多数使用场景。候选方案二HybridChatClient类 每种编排策略一个 handler备选该方案引入一个HybridChatClient类它同样实现IChatClient但把选择客户端的职责委托给由抽象基类ChatCompletionHandler派生的具体处理器public sealed class HybridChatClient : IChatClient { private readonly IChatClient[] _chatClients; private readonly ChatCompletionHandler _handler; private readonly Kernel? _kernel; public HybridChatClient(IChatClient[] chatClients, ChatCompletionHandler handler, Kernel? kernel null) { this._chatClients chatClients; this._handler handler; this._kernel kernel; } public TaskExtensions.AI.ChatCompletion CompleteAsync( IListChatMessage chatMessages, ChatOptions? options null, CancellationToken cancellationToken default) { return this._handler.CompleteAsync( new ChatCompletionHandlerContext { ChatMessages chatMessages, Options options, ChatClients this._chatClients.ToDictionary(c c, c (CompletionContext?)null), Kernel this._kernel, }, cancellationToken); } public IAsyncEnumerableStreamingChatCompletionUpdate CompleteStreamingAsync( IListChatMessage chatMessages, ChatOptions? options null, CancellationToken cancellationToken default) { // ... 流式实现 } // ... } public abstract class ChatCompletionHandler { public abstract TaskExtensions.AI.ChatCompletion CompleteAsync( ChatCompletionHandlerContext context, CancellationToken cancellationToken default); public abstract IAsyncEnumerableStreamingChatCompletionUpdate CompleteStreamingAsync( ChatCompletionHandlerContext context, CancellationToken cancellationToken default); }HybridChatClient通过ChatCompletionHandlerContext类把所有必要信息传递给 handler该上下文包含聊天客户端列表、聊天消息、选项以及Kernel实例public class ChatCompletionHandlerContext { public IDictionaryIChatClient, CompletionContext? ChatClients { get; init; } public IListChatMessage ChatMessages { get; init; } public ChatOptions? Options { get; init; } public Kernel? Kernel { get; init; } }上一方案中的回退策略可以改写为如下 handlerpublic class FallbackChatCompletionHandler : ChatCompletionHandler { public override async TaskExtensions.AI.ChatCompletion CompleteAsync( ChatCompletionHandlerContext context, CancellationToken cancellationToken default) { for (int i 0; i context.ChatClients.Count; i) { var chatClient context.ChatClients.ElementAt(i).Key; try { return client.CompleteAsync(chatMessages, options, cancellationToken); } catch (HttpRequestException ex) { if (ex.StatusCode 500) { // 尝试下一个客户端 continue; } throw; } } throw new InvalidOperationException(No client provided for chat completion.); } public override async IAsyncEnumerableStreamingChatCompletionUpdate CompleteStreamingAsync( ChatCompletionHandlerContext context, CancellationToken cancellationToken default) { // ... 流式实现 } }调用方代码则非常直观IChatClient onnxChatClient new OnnxChatClient(...); IChatClient openAIChatClient new OpenAIChatClient(...); // 优先尝试第一个客户端失败则回退到下一个 FallbackChatCompletionHandler handler new FallbackChatCompletionHandler(...); IChatClient hybridChatClient new HybridChatClient([onnxChatClient, openAIChatClient], handler); var result await hybridChatClient.CompleteAsync(Do I need an umbrella?, ...);Handler 可以链式组合构造更复杂的编排场景——某个 handler 先做预处理再把调用委托给下一个 handler且可以携带扩充后的客户端列表。例如第一个 handler 识别出云端模型请求访问敏感数据于是把调用委托给本地模型处理IChatClient onnxChatClient new OnnxChatClient(...); IChatClient llamaChatClient new LlamaChatClient(...); IChatClient openAIChatClient new OpenAIChatClient(...); // 优先尝试第一个客户端失败则回退到下一个 FallbackChatCompletionHandler fallbackHandler new FallbackChatCompletionHandler(...); // 检查请求是否包含敏感数据识别允许处理敏感数据的客户端并把调用委托给下一个 handler SensitiveDataHandler sensitiveDataHandler new SensitiveDataHandler(fallbackHandler); IChatClient hybridChatClient new HybridChatClient(new[] { onnxChatClient, llamaChatClient, openAIChatClient }, sensitiveDataHandler); var result await hybridChatClient.CompleteAsync(Do I need an umbrella?, ...);ADR 给出了一些复杂编排场景的典型组合直观展示了选择器 执行器两层 handler 的复用威力第一层 Handler第二层 Handler场景说明InputTokenThresholdEvaluationHandlerFastestChatCompletionHandler根据 prompt 的输入 token 规模与每个模型的 min/max token 容量识别候选模型返回最快模型的响应InputTokenThresholdEvaluationHandlerRelevancyChatCompletionHandler同上识别模型返回最相关模型的响应InputTokenThresholdEvaluationHandlerFallbackChatCompletionHandler同上识别模型返回第一个可用模型的响应SensitiveDataRoutingHandlerFastestChatCompletionHandler基于数据敏感度识别模型返回最快模型的响应SensitiveDataRoutingHandlerRelevancyChatCompletionHandler基于数据敏感度识别模型返回最相关模型的响应SensitiveDataRoutingHandlerFallbackChatCompletionHandler基于数据敏感度识别模型返回第一个可用模型的响应方案二的优势与代价都很明确Pros可以复用同一批 handler组合出各种复合编排策略Cons相比方案一需要额外的新抽象与组件——上下文类以及处理委托给下一个 handler的衔接代码。ADR 中注明验证该方案可行性的 POC 位于微软 Semantic Kernel 仓库的 PR #10412 中仓库外资料此处仅作背景说明。候选方案三扩展现有IAIServiceSelector接口否决Semantic Kernel 本身已经有一套动态选择 AI 服务的机制public interface IAIServiceSelector { bool TrySelectAIServiceT( Kernel kernel, KernelFunction function, KernelArguments arguments, [NotNullWhen(true)] out T? service, out PromptExecutionSettings? serviceSettings) where T : class, IAIService; }该接口在仓库中的真实定义见 IAIServiceSelector.cs其默认实现为按执行设置顺序 服务 id / 模型 id选择服务的OrderedAIServiceSelector见 OrderedAIServiceSelector.cs。从该默认实现的源码可以看到它优先按arguments.ExecutionSettings中的 service id 精确匹配其次按 model id 匹配最后才回退到默认服务——这是一种典型的静态选择逻辑。ADR 从四个角度论证了该接口不适合作为混合编排的基础依赖特定上下文该方法要求kernel、function、arguments三者齐备而这些上下文在编排场景中不一定总是可用只兼容IAIService它只对实现IAIService的服务生效无法兼容 Microsoft.Extensions.AI 生态中实现IChatClient的众多 AI 服务。尽管仓库中提供了ChatClientAIService这一适配器见 ChatClientAIService.cs把IChatClient包装成可被IAIServiceSelector识别的IAIService但它也仅是让注册与选择环节可行无法支撑先探测再推理的编排混合编排常需要先向某个服务发起一次提示prompt以判断其可用性、延迟等——例如发一条消息探测服务是否可用可用则返回本次完成结果不可用则回退。但TrySelectAIService不接受聊天消息列表或选项参数无法发送消息即便能发送由于该方法不返回 completion消费方还得把同一批消息重新发给选中的服务再取一次结果而且该方法是同步的在同步代码中发送聊天消息通常是被不鼓励的做法设计目标不同IAIServiceSelector的本职是基于 SK 上下文与服务元数据同步地选出一个IAIService实例它完全不考虑 completion 与流式 completion 的结果。因此该方案的结论是Pros复用了现有的 AI 服务选择机制Cons不适用于所有 AI 服务依赖可能缺失的上下文消费方代码必须了解IAIServiceSelector而非直接使用IChatClient方法是同步的。决策结果采纳方案一最终选择Option 1——因为它不需要任何新抽象且简单直接足以覆盖大多数使用场景。ADR 同时明确如果未来出现更复杂的编排需求可以再考虑 Option 2。仓库实战FallbackChatClient可运行示例解读如果觉得 ADR 中的代码是伪代码可以放心——仓库中已有该方案的完整可运行实现HybridCompletion_Fallback.cs位于 Concepts 示例项目注册于 Concepts/README.md 的 ChatCompletion 章节。该文件同时给出了两种用法示例并附带了一个生产级质量的FallbackChatClient内部实现类非常值得逐行研读。默认回退的 HTTP 状态码集合与 ADR 中粗略的ex.StatusCode 500判断不同仓库实现把哪些状态码触发回退收敛为一个显式列表private static readonly ListHttpStatusCode s_defaultFallbackStatusCodes [ HttpStatusCode.InternalServerError, // 500 HttpStatusCode.NotImplemented, // 501 HttpStatusCode.BadGateway, // 502 HttpStatusCode.ServiceUnavailable, // 503 HttpStatusCode.GatewayTimeout // 504 ];同时通过public ListHttpStatusCode? FallbackStatusCodes { get; set; }暴露覆盖入口允许按需自定义触发回退的状态码集合。异常类型归一化回退判定先把不同 SDK 抛出的异常归一化为 HTTP 状态码HttpStatusCode? statusCode ex switch { HttpOperationException operationException operationException.StatusCode, HttpRequestException httpRequestException httpRequestException.StatusCode, ClientResultException clientResultException (HttpStatusCode?)clientResultException.Status, _ throw new InvalidOperationException($Unsupported exception type: {ex.GetType()}.), };ShouldFallbackToNextClient还会检查当前是否为最后一个客户端如果是则不再回退直接抛出所有客户端都失败时最终抛出InvalidOperationException(Neither of the chat clients could complete the inference.)。非流式完成GetResponseAsync非流式回退的核心逻辑与 ADR 一致按顺序遍历客户端GetResponseAsync成功则立即返回抛出的异常若命中回退状态码则继续尝试下一个客户端。流式完成GetStreamingResponseAsync值得注意的细节是流式场景的处理——由于IAsyncEnumerable的异常发生在枚举期间而非调用期间示例实现采用先取第一个 update 暴露异常的技巧// Move to the first update to reveal any exceptions. if (!await enumerator.MoveNextAsync()) { yield break; } // ... yield return enumerator.Current; // 先产出第一个 update // 再产出其余 update while (await enumerator.MoveNextAsync()) { yield return enumerator.Current; }也就是说只有流尚未开始产出任何内容就抛出异常时才触发回退一旦首个 update 成功产出后续流中的异常将按原样抛出。这一行为语义清晰已开始的响应不中断、不回退。与 Kernel 的集成方式示例展示了两种接入方式二者都通过FallbackChatClient(...).AsChatCompletionService()把它转换为 SK 的IChatCompletionService方式一通过 DI 容器注册回退客户端作为唯一完成服务IKernelBuilder kernelBuilder Kernel.CreateBuilder(); // 注册一个不可用的客户端用 StubHandler 强制返回 503 Service Unavailable kernelBuilder.Services.AddSingletonIChatClient(CreateUnavailableOpenAIChatClient()); // 注册一个云端可用客户端 kernelBuilder.Services.AddSingletonIChatClient(CreateAzureOpenAIChatClient()); // 回退客户端包装所有已注册的 IChatClient kernelBuilder.Services.AddSingletonIChatCompletionService((sp) { IEnumerableIChatClient chatClients sp.GetServicesIChatClient(); return new FallbackChatClient(chatClients.ToList()).AsChatCompletionService(); }); Kernel kernel kernelBuilder.Build(); kernel.ImportPluginFromFunctions(Weather, [KernelFunctionFactory.CreateFromMethod(() Its sunny, GetWeather)]); AzureOpenAIPromptExecutionSettings settings new() { FunctionChoiceBehavior FunctionChoiceBehavior.Auto() }; FunctionResult result await kernel.InvokePromptAsync(Do I need an umbrella?, new(settings));方式二不依赖 Kernel直接构造回退客户端IChatCompletionService fallbackCompletionService new FallbackChatClient([unavailableChatClient, availableChatClient]).AsChatCompletionService(); IAsyncEnumerableStreamingChatMessageContent result fallbackCompletionService.GetStreamingChatMessageContentsAsync(Do I need an umbrella?, settings, kernel);示例中模拟不可用客户端的手法也值得借鉴通过自定义StubHandler一个继承DelegatingHandler的内部类拦截 HTTP 响应并强制改写为ServiceUnavailable503从而在不依赖真实故障的前提下稳定复现回退路径。这与仓库测试中常用的HttpMessageHandlerStub见 HttpMessageHandlerStub.cs思路一致。扩展阅读混合编排可以组合哪些客户端方案一之所以够用前提是各模型供应商都能以统一的IChatClient暴露出来。当前仓库的 Connectors 层提供了丰富的现成选择例如本地 ONNX 模型dotnet/src/Connectors/Connectors.Onnx/目录下的OnnxRuntimeGenAIChatCompletionService经OnnxChatClientExtensions可暴露为IChatClient对应集成测试见 OnnxRuntimeGenAIChatClientTests.cs云端 OpenAI / Azure OpenAIdotnet/src/Connectors/Connectors.OpenAI/与dotnet/src/Connectors/Connectors.AzureOpenAI/示例代码中的AsIChatClient()即来自该层其他本地/云端模型Google、MistralAI、Ollama、HuggingFace、Bedrock 等连接器同样在dotnet/src/Connectors/下成体系存在。也就是说无论你是云端 OpenAI 为主、ONNX 本地兜底还是多个云端供应商互为冗余只需把各自的IChatClient组装进FallbackChatClient或你自研的其他策略实现即可获得统一、可插拔的混合推理能力。总结围绕本地 云端混合推理这一需求本 ADR 完整走完了从问题定义、方案设计到决策落地的过程决策驱动因素锁定为简单可扩展、对调用方透明、支持多种选择策略三个候选方案各有利弊方案一每策略一个IChatClient以零新抽象胜出方案二HybridChatClient handler 链以更高的组合灵活性作为未来备选方案三扩展IAIServiceSelector因设计目标不同而被明确否决最终决策落在方案一且仓库中已有可直接借鉴的FallbackChatClient完整实现与 DI 集成示例。对于大多数应用而言方案一已经完全够用你只需要实现或复用仓库示例中的一个实现IChatClient的编排类把多个本地/云端客户端传进去然后像使用普通聊天客户端一样使用它即可——底层是本地还是云端、是否发生过回退对上层调用方完全透明。关联资料本文核心依据为 docs/decisions/0064-hybrid-model-orchestration.md可运行示例见 HybridCompletion_Fallback.cs相关接口与默认实现见 IAIServiceSelector.cs、OrderedAIServiceSelector.cs 与 IChatClientSelector.cs。【免费下载链接】semantic-kernelIntegrate cutting-edge LLM technology quickly and easily into your apps项目地址: https://gitcode.com/GitHub_Trending/se/semantic-kernel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询