资讯动态

Semantic Kernel与Microsoft Agent Framework:从函数编排到智能体运行时的进化与实践

发布时间:2026/10/21 8:24:17 来源:尧图企业网站定制
1. 先讲清楚来龙去脉Semantic Kernel 到底解决了什么这两个星期.NET 圈子里聊得最多的东西除了新版本预览就是 Microsoft Agent Framework。很多朋友第一反应是Semantic Kernel 还没玩明白这又来一个框架其实我一开始也是这么想的直到把继承关系捋了一遍才发现这根本不是又造了一个轮子而是把 .NET 上做 AI 应用的那套抽象从“调模型”升级到了“编排智能体”。先聊 Semantic Kernel。它的核心价值是在 .NET 世界里给大语言模型画了一条标准线。在此之前大家调 LLM 的方式五花八门有人直接拼 REST 请求有人封装了 HttpClient 然后各自维护重试逻辑有人把 Prompt 散落在业务代码里。Semantic Kernel 做了三件很务实的事情第一把模型调用统一成一个 Kernel 对象模型服务商在外面内核在中间业务代码不直接碰 SDK第二把工具抽象成 Plugin让模型可以调用业务函数这才有了“函数调用”的基础第三引入 Planner 的概念让模型根据用户目标自己规划执行步骤。这套设计解决了我当时最头疼的问题模型换了一家业务代码不用跟着推倒重来新增一个业务能力不需要改调用链路只需要注册一个 Plugin。但用久了你会发现问题。Kernel 本质上还是“一次请求一次响应”的思路。哪怕 Planner 做了多步规划它的循环还是由 Kernel 驱动的每一步都要你手动把结果塞回上下文再让模型决定下一步。说白了Semantic Kernel 把模型调用标准化了但没有把“自主决策”这个过程框架化。你想做一个真正有自主行为的 Agent得自己写循环、自己管理状态、自己处理多轮上下文甚至要自己解决“模型跑飞了怎么办”的问题。这些不是不能做而是没有标准每个团队都会长出属于自己的那套半成品框架。所以 Microsoft Agent Framework 的出现不是要把 Semantic Kernel 扔掉。它的定位更像是Semantic Kernel 已经帮你搞定了模型抽象和工具抽象Agent Framework 在此基础上把“Agent 运行时的骨架”给你搭好。你不再需要自己写 while 循环去驱动一个智能体框架把 Agent 的启动、执行、挂起、恢复、多 Agent 协作全都收编了。这才是它值得关注的根本原因。2. 继承了什么那些你没注意到的心智传承很多人上手 Agent Framework 之后会觉得“确实有 Semantic Kernel 的影子”但说不清哪里像。这里我把继承的点拆开讲你会发现它走了一条非常务实的路线不推翻抽象层只在执行层动刀。2.1 工具与插件抽象从 KernelPlugin 到 AgentToolSemantic Kernel 里最成功的抽象就是 Plugin。一个 Plugin 里可以挂多个 function每个 function 有名字、有描述、有参数 schema模型拿到这些 metadata 之后决定要不要调用。这套设计的妙处在于模型不需要理解你的 C# 代码它只看到一堆 JSON schema 和函数描述。Agent Framework 完整保留了这套思路Agent 的工具调用依然可以走 KernelPlugin同时它也接入了 MCP 标准这意味着你以前给 Semantic Kernel 写的插件在 Agent Framework 里几乎不用改就能继续用。这很重要。如果一个新框架要求你把所有工具重写一遍那迁移成本会劝退大部分人。Agent Framework 的做法是你原来怎么注册插件现在还怎么注册只是把调用主体从 Kernel 换成 Agent。我在迁移一个内部工具库时深有体会几十个函数改动量基本只限于注册入口那一行函数体一行没动。2.2 依赖注入与 Hosting 模型用过 Semantic Kernel 的朋友应该对AddKernel()、AddChatCompletionService()这套扩展方法有印象。Agent Framework 完全沿用了同样的宿主模型基于IServiceCollection注册服务基于IHost管理生命周期。你如果本来就在 ASP.NET Core 里集成过 Semantic Kernel迁移到 Agent Framework 那一下会非常顺滑。依赖注入该用 Scope 还是 Singleton消息历史和模型客户端注册在哪一层这些心智模型都不用重学。2.3 对话历史的抽象ChatMessage 与 ChatHistorySemantic Kernel 后来把消息抽象统一到了ChatMessage/ChatHistory这套模型里并且配合流式接口定义了标准的事件流。Agent Framework 底层并没有自己另搞一套消息结构它直接构建在Microsoft.Extensions.AI的抽象之上。这就产生了一个很有意思的效果你在 Semantic Kernel 里已经做过的多轮会话管理、消息角色映射、Token 计数到了 Agent Framework 可以原样保留。抽象层的统一换来的是心智负担的连续性。2.4 Kernel 本身还在只是退居后场Agent Framework 里并不是没有 Kernel 的概念了。恰恰相反每个 Agent 在内部还是会构建一个 Kernel 实例来执行函数调用。这个设计很聪明它没有把 Kernel 从架构里拿掉而是把 Kernel 降级为 Agent 内部的一个执行引擎。Agent 负责决定“下一步做什么”Kernel 负责“这一步怎么做”。所以你看与其说 Agent Framework 超越了 Semantic Kernel不如说它把 Semantic Kernel 嵌到了更完整的运行时里各自负责不同的层次。3. 超越在哪里从函数编排到智能体运行时继承的部分讲清楚了接下来才是重点Agent Framework 到底比 Semantic Kernel 强在哪我的判断是它把“Agent 的一等公民化”做到了框架层面。这不是加几个类的问题而是整个编程模型的升级。3.1 Agent 不再是一段循环而是一个生命体Semantic Kernel 里你想实现一个 Agent本质上还是要自己写“把用户输入放进上下文调模型看有没有工具调用有就执行把结果放回去再调模型……”这套循环每次都要重新发明。Agent Framework 把 Agent 定义成了一个有生命周期、有状态、有行为的实体。它会规定 Agent 怎么启动、怎么响应事件、怎么暂停等待用户输入、怎么在必要时转入后台继续执行。你可以给它设置指令Instructions、设置行为模式Behavior甚至可以挂入自定义的事件处理器来拦截每个执行阶段。举个例子。以前我想做一个自动客服需要在每个回合判断“用户是不是在问开单问题”是就走工具调用不是就闲聊。这个分流逻辑在 Semantic Kernel 里全靠 Prompt 去约束模型效果不稳定。在 Agent Framework 里你可以在 Agent 的某个状态节点上专门挂一个判断函数也可以订阅事件在特定阶段注入规则。模型决策之外代码逻辑有了正式的介入点。3.2 状态持久化不再是临时方案Semantic Kernel 本身没有状态持久化方案。你处理一个多轮对话如果进程重启上下文就丢了。很多团队是自己把 ChatHistory 序列化到 Redis 或数据库里但遇到并发更新、多实例共享时往往很痛苦。Agent Framework 设计了一套 Agent 状态存储机制它会区分“会话状态”和“Agent 定义”并且提供持久化的租约机制——也就是说多个实例同时处理同一个会话时状态不会被踩。你可以把整个 Agent 的进度存起来服务重启之后接着跑。这个能力在生产环境里意义非常大尤其是那种执行时间很长的后台 Agent跑一半挂了能恢复处理这种体验在旧的 Semantic Kernel 模式下需要自己大量造轮子。3.3 多 Agent 协作终于有了标准范式Semantic Kernel 很难原生支持多 Agent 协作因为它的 Kernel 是单执行流的。你要做“评审 修改 总结”这种多角色协作得自己管理多个 Kernel、多个 ChatHistory 实例还要把不同 Agent 的输出互相投喂。Agent Framework 直接带来了 AgentGroupChat 这类协作模式你可以定义多个 Agent把它们拉进同一个群聊框架会负责消息在 Agent 之间的分发也支持协作终止策略比如达到某轮数或某类消息后自动结束。它的底层很像一场结构化的座谈会每个人都能发言但主持逻辑在框架手里。我把这种能力比作从单人对话升级到了剧组拍戏以前你一个人又当编剧又当演员又当场务现在 Agent Framework 帮你搭了一个片场每个角色都有自己的岗位说明你只要把人拉齐演出自动开始。3.4 可观测性被当成一等公民跑过 AI 应用的人都知道最痛苦的就是调试。模型为什么没调用工具上下文里到底塞了什么哪一步开始答非所问这些东西在 Semantic Kernel 里要靠自己打日志。Agent Framework 把事件流、活动追踪Activity内置到了运行时你可以订阅每个 Agent 的每个决策节点可以通过事件查看工具调用的参数和返回值可以把整条链路的轨迹导到链路追踪系统里。这些能力早期阶段你未必用得上但一旦到了生产环境它就是救命稻草。这里再说一句公道话超越不意味 Semantic Kernel 没有价值。相反Agent Framework 的每一步“超越”基底依然是 Semantic Kernel 打下的抽象能力。它更像是 Semantic Kernel 在 Agent 时代的一次进化继承在前超越在后。4. 战略整合怎么落地真实业务里的选型与演进路径光谈架构显得虚。这一节我们聊一个很现实的问题我现在有一堆基于 Semantic Kernel 的代码要不要迁新项目选哪个我给出的建议是别急着二选一先把场景分类。4.1 场景分类什么继续用 Semantic Kernel什么交给 Agent Framework我做了个分类表基本能覆盖大部分真实场景场景特征建议方案原因单轮知识问答、文档摘要、文本分类继续用 Semantic Kernel / M.E.AI不需要自主规划Kernel 足够成本最低函数调用、参数抽取、结构化输出继续用 Semantic Kernel一次调用就能完成不需要多轮循环多步工具操作、动态规划、需要中途等待用户确认Agent FrameworkAgent 运行时能管理暂停与恢复体验远优于手写循环多角色协作、评审链、聚合分析Agent FrameworkAgentGroupChat 提供标准协作模式长时间后台执行、断点恢复Agent Framework状态持久化是内置能力简单的流式聊天 少量工具二者都可如果团队已熟 SK不必为了新而新我的切分标准是一次请求能解决的事别上 Agent需要运行时自己判断走哪条路的事交给 Agent Framework。4.2 演进路径从 Semantic Kernel 到 Agent Framework 的最小代价迁移如果你已经有 Semantic Kernel 的项目并不需要一次性推倒重来。我建议走三步第一步先把模型客户端和插件的注册统一到Microsoft.Extensions.AI抽象上。这一步其实在 Semantic Kernel 内部已经部分完成你需要确认团队里没有直接用底层 SDK 的代码。只要所有模型调用都走统一的客户端接口后续的 Agent 化就会顺利很多。第二步挑一个只涉及单一 Agent 的场景做试点。比如把一个原来用 Planner 多步调用工具的后端服务改造成 Agent Framework 实现。这一步你会明显感觉到差异原来需要自己维护执行循环的代码全部删掉了换来的是框架的事件回调和状态管理。试点通过后再扩大范围。第三步涉及多角色协作时再上 AgentGroupChat。这里不建议一上来就做多 Agent因为调试复杂度是几何级上涨的。先把单 Agent 的生命周期和状态持久化摸熟团队有了手感再去玩协作范式。我一直跟团队强调新框架的引入要跟着痛点走不要跟着热点走。哪个场景最痛就先拿哪个场景做手术刀。4.3 与 ASP.NET Core 的整合路径Agent Framework 的宿主模型决定了它和 ASP.NET Core 的整合比 Semantic Kernel 还要自然。你可以把 AgentHost 注册为单例服务把会话存储注册为作用域服务把每个用户的会话 ID 作为租约键。在实际接口层Controller 只负责接收用户输入并提交给 Agent结果通过事件流返回或者通过 SignalR 推送。这里有个设计取舍同步接口和异步任务要分开。简单问答用同步等待即可但长耗时操作一定要走异步任务 状态查询。Agent Framework 的状态持久化正好支持这种模式Agent 在后台跑用户随时拿着会话 ID 来问“好了没”。这个体验比所有请求都同步阻塞要舒服得多。4.4 工具生态的整合MCP 与既有插件双轨并行工具层是整合的重点。我的建议是历史积累的 KernelPlugin 继续保留因为内部系统业务函数大多已经写成这样新的外部工具优先走 MCP 标准。MCP 带来的好处是你不需要为目标工具单独写适配代码只要对方提供了 MCP 服务器Agent 就可以直接发现并调用它的工具。这一块在未来只会越来越重要因为整个工具的生态在往标准化方向走早接入早受益。Agent Framework 里这两条路是并行的不冲突。5. 实操指南动手搭一个最小 Agent讲了不少理念我们来点能直接抄作业的东西。下面的示例基于 Agent Framework 的编程模型具体包名会以正式发布版本为准但大体的 API 形态不会有本质变化。5.1 环境准备推荐使用 .NET 8 以上版本。你需要的核心 NuGet 包大概包括Agent Framework 核心包提供 AgentHost、Agent、AgentChat 等核心类型Microsoft.Extensions.AI系列包模型客户端、聊天完成抽象模型服务商的适配包比如 OpenAI 或 Azure OpenAI 的 M.E.AI 适配层如果需要状态持久化再加上对应存储实现的软件包格式上我习惯先建一个控制台项目跑通最小链路再接 ASP.NET Core。5.2 最小 Agent定义、注册、运行先定义 Agent 的基本配置。一个 Agent 至少要包含一个名字用于在协作中区分身份、一段指令Instructions说明这个 Agent 的职责和边界、一个模型客户端ChatClient。代码大致是这样var builder Host.CreateApplicationBuilder(args); builder.Services.AddChatClient(clientBuilder { clientBuilder.Use(innerClient); // 内部统一模型客户端 }); builder.Services.AddAgentHost(agentHostBuilder { agentHostBuilder.AddAgent(assistant, agentBuilder { agentBuilder.UseChatClient(); // 使用默认模型客户端 agentBuilder.Instructions(你是一个乐于助人的助手回答尽量简洁不确定时明确说不知道。); }); }); var host builder.Build(); await host.StartAsync(); var agentHost host.Services.GetRequiredServiceAgentHost(); var chatClient agentHost.CreateChatClient(assistant, new AgentChatOptions { Name main-chat }); var result await chatClient.CompleteAsync(帮我列一下周末去爬山需要准备的物品。); Console.WriteLine(result);这段代码的直观之处在于模型客户端、Agent 指令、会话上下文三者分隔得很清楚。你不需要手动去构造 ChatHistory 然后一遍遍调用模型CompleteAsync内部已经处理了该 Agent 的完整执行流程。5.3 给 Agent 挂上工具继续用你熟悉的 Plugin接下来是工具调用。如果你以前写过 Semantic Kernel 插件这一步几乎是肌肉记忆builder.Services.AddSingletonWeatherTool(); builder.Services.AddAgentHost(agentHostBuilder { agentHostBuilder.AddAgent(weather-assistant, agentBuilder { agentBuilder.UseChatClient(); agentBuilder.Instructions(你是一个天气助手。查询天气时使用工具不要凭空编造数据。); agentBuilder.UseKernelPlugin(plugin plugin.AddTypeWeatherTool()); }); });其中WeatherTool里每个公开方法都会自动成为可被模型调用的函数public sealed class WeatherTool { [KernelFunction(get_weather)] public Taskstring GetWeatherAsync(string city) { return Task.FromResult($今日{city}多云20~28℃微风。); } }框架会把这个函数转成模型需要的 schema模型在需要天气信息时自动触发调用。这里最要注意的是函数描述要写清楚。描述不清模型就不会在合适的时机调用它这和 Semantic Kernel 时代的经验完全一致。5.4 做一个多 Agent 协作小例子多 Agent 协作是 Agent Framework 的重头戏。我做一个最简单的“评审-修订”流程一个写作 Agent一个评审 Agent。评审 Agent 可以给写作 Agent 提意见写作 Agent 根据意见修改。核心代码如下builder.Services.AddAgentHost(agentHostBuilder { agentHostBuilder.AddAgent(writer, agent { agent.UseChatClient(); agent.Instructions(你是一名技术文章作者文字要求清晰、准确、有逻辑。); }); agentHostBuilder.AddAgent(reviewer, agent { agent.UseChatClient(); agent.Instructions(你是一名资深技术评审。评估文章时只指出核心问题给出修改建议。); }); }); var groupChat agentHost.CreateGroupChat(new GroupChatOptions { Agents { writer, reviewer }, TerminationStrategy new MaximumTurnStrategy(4) }); await groupChat.AddMessageAsync(new ChatMessage(user, 写一段 200 字左右的.NET AI 发展说明。)); var finalState await groupChat.CompleteAsync();MaximumTurnStrategy是终止策略的一种最多来回复 4 次防止两个 Agent 无限讨论下去。如果你是第一次接触多 Agent这个限制尤其重要不加的话生产事故就是“两个模型互相客气”聊到费用爆炸。5.5 开启持久化让 Agent 重启不丢上下文假设你有一个跑批的 Agent用户早上提交任务下午来查结果。这个场景下不能把历史放在内存里。注册状态存储的示例代码大概是这样builder.Services.AddSingletonIChatHistoryStore, DatabaseChatHistoryStore(); builder.Services.AddAgentHost(agentHostBuilder { agentHostBuilder.AddAgent(batch-agent, agent { agent.UseChatClient(); agent.UseThreadStore(); // 启用线程状态持久化 }); });这样之后每个会话有一个唯一线程 ID服务重启后通过它把历史加载回来继续执行。UseThreadStore背后的机制会做租约管理同一线程在同一时刻只允许一个运行实例持有它。这个设计解决了我以前自己读写 Redis 时最担心的问题——多个实例同时消费同一个任务时状态会不会串。5.6 代码层面的整体注意点最小可跑的例子并不复杂但有几个点新手很容易踩第一模型客户端的注册方式要和 Agent 的注册保持一致。如果 Agent 注册时指定了某个服务商后面运行时就不能再指望同一个 Agent 在不同的模型间自由切换。模型切换不太建议在生产环境做灵魂替换测试例外。第二工具的注册尽量放在 AgentBuilder 块里。放全局会导致所有 Agent 都能看到所有工具模型的选择压力会变大出现工具误调用的概率也更高。隔离最小化是个好习惯。第三指令Instructions要写得像一个岗位说明书不要写成一个请求。比如“你是一个客服”和“你的职责是1 判断问题归属2 查知识库3 给结论”效果差距极大。模型对角色定义的理解直接决定后续调用的准确度。6. 常见问题与排查技巧实录从我自己和身边朋友踩坑的情况来看下面这些问题出现频率最高。整理成一个速查表按症状、原因、解决方案展开。症状常见原因解决方案Agent 一直在转圈不返回结果工具调用后缺少停止条件或多 Agent 无终止策略检查 TerminationStrategy单 Agent 场景确认工具结果被正确返回给模型模型没有按预期调用工具函数描述不清晰或模型上下文里工具列表太长精简工具数量写清楚函数描述和参数 schema必要时测试不同模型会话恢复后上下文缺失没有启用线程持久化或存储实现只存取了一部分消息持久化整个 ChatHistory 而不是只存最终结果确认租约释放逻辑多个用户共用同一会话没有用用户 ID 或任务 ID 作为会话标识每次创建 ChatClient 时传入唯一 Name / ThreadIdAgent 输出风格不一致模型采样参数没设指令太薄在 Agent 定义里统一设置模型参数指令补充边界和示例休息后进程还在线程却断了存储链接失效或租约超时检查数据库链接池配置调大租约超时时间使用多 Agent 时上下文错乱共享了同一个 ChatHistory确保 GroupChat 内部的消息路由是由框架管理的不要手动手动往会话里塞消息6.1 关于“工具调用不生效”的深层排查工具调用不生效我一般按三层排查。第一层看模型端的原始响应里有没有 tool_calls 字段。没有的话要么函数描述问题要么模型本身不支持并发工具调用。第二层看传入模型的工具 schema 是不是正确。手动打印一次 Agent 内部的 KernelFunctionMetadata 列表比猜要快得多。第三层看工具执行过程中的异常。工具抛出异常后如果 Agent 没有把异常信息转换成反馈给模型的文本模型会以为工具没结果然后开始胡猜。正确的做法是工具异常要捕获并作为文本返回给模型让模型决定下一步。6.2 关于多 Agent 协作的“跑飞”问题多 Agent 协作最常见的问题就是聊个不停。除了设置最大轮数终止策略我还习惯在每个 Agent 指令里加上一条明示“如果你认为目标已经达成请在回复开头输出 [DONE]。”然后在一个事件处理器里检测这个标签主动终止协作。这算是给模型装了一个急停按钮。6.3 关于持久化与租约的冲突租约机制是为了并发安全但如果一个任务订阅了很长时间没有完成租约超时就会让另一个实例接管任务。如果你不希望任务被抢走要么调大租约时长要么实现一个心跳续租的逻辑。我看过有人因为默认值太小导致一个运行 5 分钟的任务在中途易主第二个实例加载了一个不完整的上下文结果全乱了。7. 我的一些实际体会聊到最后说点踩过坑之后才会明白的事。第一Agent Framework 值得关注的核心不是它多了几个类而是它把 AI 应用的编程模型从“调用模型”推进到了“治理智能体”。以前我们管理的是模型请求以后我们管理的是 Agent 的生命周期、行为边界和协作关系。这个概念转换比任何 API 都重要。第二不要盲目把现有系统全部迁移到 Agent Framework。我见过有团队把一个简单的翻译接口也改造成了 Agent结果响应延迟从 500ms 变成了 6 秒。Agent 是有成本的它适合复杂的自主任务不适合简单的一次性请求。保留判断力比追新更重要。第三如果你在做一个长期跑批的场景状态持久化和可观测性一定要在生产前就设计好。事发之后再补会很被动。Agent 的执行路径不像传统代码那样可以静态分析多一步有据可查的日志就多一分掌控。最后分享一个小技巧在 Agent 的指令模板里统一加上“你在不确定答案时必须如实说明不确定性禁止编造”。这句话在 Semantic Kernel 时代我就一直在用到了 Agent Framework 依然适用尤其是你的 Agent 接了外部工具以后胡编的成本更高了。工具在变框架在变但做 AI 应用最本质的那件事没变——保证模型在受控的范围内做决策跑得快也跑得稳。

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

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

免费获取报价 →
↑