摘要:Microsoft.Extensions.AI 在 .NET AI 应用架构中的定位示意图:应用程序通过 Microsoft.Extensions.AI 调用下层各种 AI 服务(如 Semantic Kernel、OpenAI、Ollama 等),其核心由
随着 .NET 9 的发布,微软引入了一套 统一的 AI 抽象层来简化 AI 模型在 .NET 应用中的集成。Microsoft.Extensions.AI 正是这套 AI 支持库的核心组成部分,它提供标准的接口和管道让开发者可以通过一致的方式调用各类 AI 服务(无论是 OpenAI、Azure OpenAI 还是本地部署的模型)。这一设计类似于 .NET 中日志、配置等扩展模型 ——通过定义统一接口和依赖注入,让不同厂商的实现可以无缝插入,从而在应用层屏蔽差异。
简单来说,Microsoft.Extensions.AI 提供了一组 跨供应商的通用接口。其中最重要的是几个核心抽象:
IChatClient 接口:表示一个聊天/对话模型客户端,可与底层的大语言模型交互。无论使用 OpenAI、Azure OpenAI 或其他模型,只要提供了IChatClient的实现,应用就可以通过这一接口统一地发送对话请求并获取回复。
IEmbeddingGenerator 接口:表示一个向量嵌入生成器,用于将输入(如文本)转换为向量表示。不同向量数据库或模型的嵌入生成,也可通过这一接口统一调用。
ChatMessage、ChatResponse 等类型:用于表示聊天消息、模型回复等,通过强类型封装对话内容。
Microsoft.Extensions.AI 作为 .NET AI 支持的一部分,被深度嵌入到了 依赖注入(DI)容器和中间件管道中。这意味着开发者可以像使用日志记录(ILogger)等其他 Microsoft.Extensions 组件一样,通过 DI 获取 AI 客户端服务,并利用熟悉的中间件模式为 AI 请求添加缓存、监控等功能。同时,它也能方便地结合 .NET 的配置系统,例如通过配置文件或用户密钥存储(User Secrets)提供 API 密钥、端点 URL 等,让应用在不同环境下灵活调整 AI 服务配置。
值得注意的是,Microsoft.Extensions.AI 本身不直接提供具体的 AI 功能,而是定义了标准接口和扩展点,实际的功能由不同提供商的实现来完成。比如,针对 OpenAI 有专门的Microsoft.Extensions.AI.OpenAI扩展包,实现了IChatClient接口以调用 OpenAI 或其兼容端点(如 Azure OpenAI);针对本地模型有Microsoft.Extensions.AI.Ollama扩展包等等。通过这种方式,Microsoft.Extensions.AI 扮演着“AI 插件体系的粘合层”角色,为 .NET 开发者提供统一、松耦合的调用方式。在开发阶段可以选用本地轻量模型调试,部署到生产时再切换到云端强大的模型,而无需改动应用代码。总结来说,Microsoft.Extensions.AI 在 .NET 9 的 AI 体系中提供了标准化、可插拔的 AI 接口层。开发者和架构师可以借助它,将 AI 能力嵌入应用的各个层面,同时保持对底层模型和服务的选择弹性。
集成方式:依赖注入与管道中间件依赖注入(DI)集成是 Microsoft.Extensions.AI 的一大特点。通过扩展方法,开发者可以方便地将 AI 模型客户端注册到 DI 容器中,并在应用其他部分通过接口获取。例如,可以使用AddChatClient扩展方法注册一个varollamaClient =newOllamaChatClient(newUri("http://localhost:11434"),"llama3.1");builder.Services.AddChatClient(ollamaClient)
.UseDistributedCache;
上面代码示例中,我们将本地 Ollama 模型的客户端加入了 DI,并通过.UseDistributedCache为其构建了一个带有分布式缓存功能的管道。当应用运行时,可以通过host.Services.GetRequiredService获取到这个已配置好的客户端实例,并直接调用 AI 模型接口。Microsoft.Extensions.AI 采用了管道式的客户端构建模式。AddChatClient返回一个可链式调用的ChatClientBuilder,开发者可以在其上附加各种中间件(Middleware)功能,然后再调用.Build将最终管道生成客户端实例。常用的中间件扩展包括:
缓存(Caching):通过.UseDistributedCache将对话结果缓存到分布式缓存(如内存、Redis),下次相同请求可直接取缓存。
遥测(Telemetry):通过.UseOpenTelemetry将请求和响应打点到 OpenTelemetry,方便监控 AI 调用的性能和频率。
限流(Rate Limiting):可以利用.UseRateLimiting或自定义中间件,在请求发送前后加入并发限制等控制。
函数调用(Tool/Function Calling):通过.UseFunctionInvocation使模型具备调用预先注册的函数的能力,在对话中实现工具调用(类似于 OpenAI Functions)。
这些中间件的设计使得AI 客户端可以按需组合功能,类似 ASP.NET Core 的 HTTP 中间件管道或者 HttpClient 的委托处理器模式。通过ChatClientBuilder.Use(...)扩展点,开发者也可以插入自定义逻辑,封装在请求前后执行。例如,上述限流可以用自定义委托在每次请求前申请许可,再调用下一步。这种拦截管道机制让 AI 集成更灵活,且易于测试和维护。配置集成方面,Microsoft.Extensions.AI 与 .NET 的配置系统天然兼容。常见模式包括:
Options 模式:可通过IOptions等将默认参数(如模型 ID、温度等)注入。也可以使用.ConfigureOptions(...)在构建管道时统一设置默认选项。
用户密钥/配置文件:利用Microsoft.Extensions.Configuration,可以将 API Key、端点 URL 等敏感信息放入配置文件或用户秘密存储。例如,Azure OpenAI 的endpoint和模型部署名称可以通过dotnet user-secrets注入,然后在代码中通过配置读取,再用于创建客户端。
通过以上机制,Microsoft.Extensions.AI 与依赖注入和配置体系融为一体。架构师可以预先在应用的 Composition Root(例如 Startup/Program)中配置好所需的 AI 客户端及其管道,而开发者在具体业务逻辑中仅需请求IChatClient接口并调用方法即可,极大降低了使用 AI 服务的门槛和耦合度。使用案例:通过 Microsoft.Extensions.AI 集成 OpenAI 模型
下面我们通过一个具体案例,演示如何使用 Microsoft.Extensions.AI 来集成一个 AI 大语言模型(以 OpenAI 的 GPT-4 模型为例)。假设我们要构建一个简单的控制台聊天程序,用户输入问题,程序调用 OpenAI 模型获取回答并显示。
步骤1:添加 NuGet 包
首先,创建一个 .NET 9 控制台应用项目,并添加以下 NuGet 包(可使用dotnet add package命令):Microsoft.Extensions.AI(预览版) – 核心 AI 抽象和管道支持
Microsoft.Extensions.AI.OpenAI(预览版) – 提供 OpenAI 接口的实现
确保包含预发布版本,因为截至 .NET 9 发布时这些扩展仍处于预览状态。
步骤2:配置依赖注入并注册 AI 客户端
在 Program 主函数中,设置主机和依赖注入容器,将 OpenAI 客户端添加到服务中。这里我们演示两种方式之一:
方式A:使用 OpenAI API 密钥直连 OpenAI 云服务。这种方式使用 API Key 验证,不涉及 Azure AD。假设我们有一个 OpenAI API 密钥。
usingMicrosoft.Extensions.DependencyInjection;using Microsoft.Extensions.AI;
var chatClient = new OpenAI.Chat.ChatClient("gpt-4o-mini", "OPENAI_API_KE Y").AsIChatClient;
var services = new ServiceCollection;
services.AddChatClient(chatClient);
varprovider = services.BuildServiceProvider;上述代码通过UseOpenAI(apiKey)扩展方法,将 OpenAI 接入配置到。AddChatClient会自动在 DI 容器中注册一个IChatClient实例。我们在构建服务提供器后,就能够解析出IChatClient来使用。方式B:使用 DeepSeek 服务。由于DeepSeek兼容OpenAI API格式,可直接利用 Microsoft.Extensions.AI.OpenAI进行对接。using OpenAI;
using System.ClientModel;
using Microsoft.Extensions.AI;
var deepseekApiKey = "";
var deepseekModel = "deepseek-chat";
var deepseekUri ="https://api.deepseek.com";
OpenAIClientOptions clientOptions =
new OpenAIClientOptions;clientOptions.Endpoint = new Uri(deepseekUri);
// 创建自定义的OpenAI客户端
OpenAIClient client = new(new
ApiKeyCredential(deepseekApiKey), clientOptions);
varchatClient = client.GetChatClient(deepseekModel).AsIChatClient;varbuilder = Host.CreateApplicationBuilder;builder.Services.AddChatClient(chatClient);
using var app = builder.Build;
varclient = app.Services.GetRequiredService;在这段代码中,我们使用 OpenAI 提供的OpenAIClient连接 DeepSeek 服务,然后调用.GetChatClient().AsIChatClient将其转换为 Microsoft.Extensions.AI 的通用IChatClient实现并注册。这样获取到的client对象同样实现了IChatClient接口,可以像方式A那样统一使用。
步骤3:发送对话请求并获取回复
无论使用上述哪种方式获取到IChatClient,都可以通过其方法与模型交互,例如获取聊天模型的回答。基本的调用方式有两种:单次完整请求:使用GetResponseAsync(或等价的CompleteAsync方法)发送一个提示,获取模型完整回答。
流式请求:使用GetStreamingResponseAsync以流方式接收模型的逐步输出,适合用于实时显示逐字输出或函数调用场景。
以下示例演示简单的单次请求:
// 从 DI 获取已注册的 IChatClient(以方式A为例)varchatClient = provider.GetRequiredService;
// 准备用户消息并发送请求获取 AI 回复
stringuserQuestion ="能简单解释一下什么是 AI 吗?";
varresponse =awaitchatClient.GetResponseAsync(userQuestion);
Console.WriteLine("AI 答复: "+ response);
我们调用了GetResponseAsync,直接传入用户的问题字符串。由于这是一个简短问题,大多数IChatClient实现会将其作为单轮对话处理,返回一个ChatResponse对象,其中包含模型的回答。上例中直接将response输出,其中会调用其.ToString或.Message得到文本。实际使用时也可以进一步获取结构化信息,例如ChatResponse下的消息列表、使用的线程 ID(用于有状态对话)等。
运行效果:如果一切配置正确,程序将把用户输入的问题发送给后端的 OpenAI 模型,并打印出模型的回答内容(例如对 “什么是 AI?” 给出通俗的解释)。这个过程中,Microsoft.Extensions.AI 帮我们完成了请求的组装和发送,而应用代码只需关注问题和答案本身。
步骤4: 集成 Function Calling
Microsoft.Extensions.AI 也支持Function Calling,以下代码为简单示例:
usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.AI;
varchatClient =newOpenAI.Chat.ChatClient("gpt-4o-mini""OPENAI_API_KEY").AsIChatClient;
IChatClient client =
newChatClientBuilder(chatClient)
.UseFunctionInvocation
.Build;
varchatOptions =newChatOptions
{
Tools = [AIFunctionFactory.Create((stringlocation,stringunit) =>
{
// 在这里您可以调用天气 API
// 获取该位置的天气信息。
return"阵雨或毛毛雨,15摄氏度";
},
"get_current_weather"
"Get the current weather in a given location")]
};
// System prompt to provide context.
List chatHistory = [new(ChatRole.System,"""
您是一位热爱徒步旅行的爱好者,帮助人们发现他们所在地区有趣的徒步路线。您充满热情且友好。
""")];
// Weather conversation relevant to the registered function.
chatHistory.Add(newChatMessage(ChatRole.User,
"我住在深圳,我正在寻找一条中等强度的徒步路线。目前的天气怎么样?"));
Console.WriteLine($"{chatHistory.Last.Role} >>> {chatHistory.Last}");
ChatResponse response =awaitclient.GetResponseAsync(chatHistory, chatOptions);
Console.WriteLine($"Assistant >>> {response.Text}");
值得一提的是,通过 Microsoft.Extensions.AI 的抽象,更换底层模型或服务非常容易。例如,我们可以在开发时将UseOpenAI换成来调用本地 Ollama 提供的模型;部署不同环境时也能通过配置选择 Azure 或其他服务。这种灵活性对于需要同时面对多种环境的架构师来说非常有价值。
Microsoft.Extensions.AI 与 Semantic Kernel 的对比分析
Microsoft.Extensions.AI 常被拿来与另一项技术 Semantic Kernel相提并论。实际上,这两者在定位和功能上有显著差异,各自擅长不同的场景。下面我们从设计理念、可扩展性、开发模型、集成便利性等方面对比它们,并分析各自适用的场景。
设计理念差异Microsoft.Extensions.AI:强调轻量级和通用性。它提供的只是最低限度的抽象接口(如IChatClient、IEmbeddingGenerator)和调用约定,没有附加高级的 AI 流程控制功能。可以将其看作是一个“LLM 调用底盘”,重点在于以统一方式调用模型、获取结果,不对上层应用的业务逻辑做过多假设。
Semantic Kernel:定位于全功能的 AI 编排框架。它在底层调用接口之上,提供了丰富的高级功能,如提示模板(Prompt Templating),功能编排(Skills/Functions 链式调用),长期记忆存储,规划和步骤控制等。Semantic Kernel 更像一个“AI 大脑”,帮助开发者组织复杂的多步对话流程、工具调用和上下文管理。
换句话说,Microsoft.Extensions.AI 不包含“提示工程”、“记忆”等概念,而 Semantic Kernel 内置了这些强大的概念和工具。这使得 Microsoft.Extensions.AI 更中立纯粹,而 Semantic Kernel 则提供了开箱即用的高级AI能力。
可扩展性Microsoft.Extensions.AI:采用开放接口设计,易于扩展不同的 AI 提供商。任何第三方或社区提供的 AI 服务,只要提供了IChatClient等接口的实现,就能直接插入整个生态,与现有代码兼容。例如,目前已经有适配 OpenAI、Azure OpenAI、Ollama 等模型的实现包,未来还可以有针对其他 LLM(包括开源模型、本地模型)的实现,只需引用相应包即可。通过这种标准化,Microsoft.Extensions.AI 实际上鼓励 AI ISV 厂商快速提供 .NET 接口,从而丰富 .NET AI 生态。另外,中间件管道本身也支持扩展,开发者可以编写自定义的UseXXXSemantic Kernel:同样具有一定的扩展能力,例如支持插件式地添加新的 Memory 存储后端、新的模型连接器等。不过,相比 Microsoft.Extensions.AI 的接口级对接,Semantic Kernel 的扩展通常意味着深入其体系(如实现自定义SKFunction,或自定义 Planner 等)。Semantic Kernel 更多地扮演一个运行时协调者角色,可扩展性主要体现为可插入自定义技能模块。但在支持新的底层模型方面,Semantic Kernel 通常通过其Connectors(连接器)或直接利用 Microsoft.Extensions.AI 抽象来实现适配,因此在底层适配层上两者目标是一致的:Semantic Kernel 未来也计划以 Microsoft.Extensions.AI 作为其底层抽象,以标准方式调用各种模型。开发模型对比Microsoft.Extensions.AI:开发者使用它的方式非常直接——通过 DI 获取IChatClient,然后调用诸如/CompleteAsync之类的方法,与调用HTTP服务或数据库很相似。这种命令式调用模型让普通 .NET 开发者感觉熟悉,几乎没有额外学习成本。同时,由于没有强制的上层框架,开发者可以自由决定如何构造提示、处理回复。例如,可以在代码中自行组织多轮对话历史,再每次调用IChatClient时传入完整历史,以支持无状态的聊天模型。Semantic Kernel:其开发模型则带有声明式和框架式色彩。开发者需要创建一个 Kernel 实例,通过 Builder 配置模型和内存,然后定义插件和函数,甚至使用模板语言编写 Prompt。开发过程更像是在编排一系列步骤:比如先调用翻译技能再调用摘要技能。Semantic Kernel 提供了丰富的 API 来组合这些步骤(如kernel.CreatePipeline等),并管理上下文(通过ContextVariables传递信息)。这种模式功能强大,但相应地学习曲线更陡峭。开发者需要理解 Kernel、Plugin、Context 等一系列概念,初次接触时复杂度要高于 Microsoft.Extensions.AI 的直接调用。简单来说,如果把调用 AI 比作开车:使用 Microsoft.Extensions.AI 就像手动驾驶一辆熟悉的轿车,直接掌握方向盘;而使用 Semantic Kernel 则更像设置自动驾驶程序,让车辆按照预定策略行驶——前者直观灵活,后者智能强大但需要预先编排路线。
系统集成便利程度Microsoft.Extensions.AI:由于其诞生于 Microsoft.Extensions 家族,天然易于融入现有 .NET 应用架构。开发者可以在 Startup/Program 中通过AddChatClient将 AI 客户端注入服务容器,然后在任意需要的地方通过构造函数注入IChatClient使用。这种方式与使用数据库上下文(DbContext)或 HttpClient 工厂非常类似,对架构影响极小。此外,它还能和现有基础设施结合,如利用 ASP.NET Core 中间件或消息管道,在请求入口就调用 AI 服务等。对于希望在现有微服务或Web应用中加入 AI 功能的团队来说,Microsoft.Extensions.AI 几乎不会破坏原有结构。而且它提供的 Telemetry、Caching 等支持也让运维监控更容易。Semantic Kernel:作为一个框架,它的集成需要一些架构上的考量。通常你需要在应用中创建一个 Kernel 单例,并管理它的生命周期(可以将其注册为 Singleton 服务)。调用 Semantic Kernel 的代码可能集中在少数几个服务或模块中,因为 Kernel 会维护会话状态、内存等。对于简单场景,这可能略显繁重。不过,Semantic Kernel 也提供了与 ASP.NET 等集成的示例模板,方便快速启动智能应用原型。总体而言,如果是从零打造一个以 AI 为核心的应用,Semantic Kernel 提供了很多便利;但在已有系统里嵌入,它需要你按照它的方式组织部分代码,集成成本相对更高。
适用场景对比基于上述差异,可以总结出两者各自更适合的场景:
Microsoft.Extensions.AI更适合:
只需基础的 AI 调用场景,例如将一段文本发送给模型获得回答、获取补全或 embeddings 等。不涉及复杂的多轮对话管理或工具调用逻辑。
希望保持低依赖和中立性的项目。例如开发一个库或中间件,需要调用 AI 服务但不想强耦合到某个具体实现或沉重框架。Microsoft.Extensions.AI 提供最小化的抽象,不会给使用者带来过多负担。
已有应用需要嵌入 AI 功能,且团队更熟悉传统 .NET 编程模型。通过 Microsoft.Extensions.AI 可以很快地将 AI 调用融入现有代码,而无需学习新框架。
需要在不同 AI 提供商之间灵活切换的情况。例如本地调试用开源模型、生产使用付费API。使用统一接口后切换只需改配置而非代码。
Semantic Kernel更适合:
复杂的 AI 工作流或智能体场景。比如应用需要模型先执行一步分析,再根据结果查询数据库或调用另一个模型,最终形成答案。这种多步骤链式推理可以利用 Semantic Kernel 的管道和 Planner 功能来编排。
长期对话或记忆需求。Semantic Kernel 内置 Memory 存储和检索机制,可以让应用具备上下文记忆,在对话轮次增多时保持一致的语境。
希望利用本地代码与 AI 功能结合的强大能力。例如将 C# 方法封装为 SK 的本地函数(Native Skill),让 AI 能请求调用这些函数。这个特性在需要 AI 与系统执行动作(如查资料、调用服务)结合时非常有用。
健壮性要求高的场景。Semantic Kernel 提供了一些内建的策略如重试、超时、错误处理等。对于生产环境复杂AI调用,它的这些特性可以减少自己实现底层重试逻辑的工作。
需要强调的是,这两者并非对立竞争关系。实际上,Semantic Kernel 已经在与 Extensions.AI 团队合作,将 Microsoft.Extensions.AI 作为其底层的一部分。可以将 Microsoft.Extensions.AI 看作基础设施,而 Semantic Kernel 构建在其上以提供更高级别的功能。在实际项目中,也完全可以同时使用两者:例如通过 Semantic Kernel 来组织复杂对话流程,但底层连接模型的部分由 Microsoft.Extensions.AI 提供的IChatClient实现完成。选型建议综合来看,Microsoft.Extensions.AI和Semantic Kernel各有优势,选择取决于项目需求和团队技术偏好:
如果你的项目主要需要直接、高效地调用 AI 接口,且偏好与现有 .NET 架构深度融合,那么Microsoft.Extensions.AI是首选。它轻量稳定,提供统一抽象,方便在不同模型服务之间切换。对于大部分需要将 AI 简单集成到业务功能的应用来说,Extensions.AI 提供了足够的能力和极佳的开发体验。
如果你的项目希望构建复杂的 AI 驱动功能,需要模型具有一定“智能自主”行为(比如多步推理、工具调用、上下文记忆),那么Semantic Kernel更适合。这种情况下,Semantic Kernel 丰富的框架特性将大大简化开发难度,提供远超直接调用的能力,让 AI 逻辑与业务逻辑解耦,易于维护和演进。
最后建议,在评估使用哪种技术时,先明确你的应用场景和复杂度。对于一般的问答、内容生成等,Microsoft.Extensions.AI 完全可以胜任且实现最快;而对于一个拟人助手、需要长程对话和多任务处理的系统,引入 Semantic Kernel 会更为有效。在实际应用中,两者并非水火不容:你可以先用 Extensions.AI 搭建基础 AI 调用,在碰到更复杂需求时逐步引入 Semantic Kernel 的相关组件。通过合理搭配,你的 .NET 9 应用将既能保持架构简洁,又拥有先进的智能能力。
最后,如果需要系统学习Semantic Kernel,可以了解下这个课程:极客时间上新 : .NET + AI 体系课
来源:opendotnet