13-SemanticKernel框架入门
当你已经学会直接调用模型 API 之后,很快就会遇到新的工程问题:提示词越来越多、上下文管理越来越乱、同一个模型调用逻辑在控制器、服务和后台任务里重复出现,甚至还希望让模型自动调用你写好的业务函数。到这个阶段,仅仅会“发请求拿结果”已经不够了,你需要一个能把模型、插件、模板和执行流程组织起来的框架。
Semantic Kernel 正是微软为这个目标提供的 AI 应用开发框架。本篇会带你从 .NET 开发者的视角理解它的定位:它不是另一个模型,而是一个把模型能力放进工程体系中的胶水层。你会学到如何创建 Kernel、如何使用 Prompt 模板与参数、如何编写插件,以及怎样让模型自动调用你的 .NET 代码。
一、为什么在模型 API 之上还需要框架
1.1 从会调用模型到能组织能力
直接调用模型 API 很适合做简单原型,但一旦需求变复杂,问题会立即暴露出来。你可能需要同一套提示模板被多个场景复用,也可能要在一次对话里既调用模型、又查数据库、还触发内部服务。随着这些需求出现,模型调用就不再只是一个孤立函数,而开始变成一个可编排、可维护、可测试的应用模块。
这也是 Semantic Kernel 的出发点。它并不是要替你隐藏所有细节,而是帮你提供一个统一容器,把提示词、执行参数、函数插件和聊天上下文放到同一种编程模型里。这样一来,你可以逐步从脚本式调用过渡到结构化 AI 应用开发,而不必每次都手工拼装请求细节。
1.2 Semantic Kernel 解决了哪些典型痛点
从工程实践来看,Semantic Kernel 最有价值的地方主要体现在三个方面。第一,它把模型服务注册进 Kernel 中,让你能够像使用依赖注入一样统一访问 AI 能力。第二,它让 Prompt 模板、变量和执行参数拥有一致的调用方式,从而减少字符串拼接式开发。第三,它把普通 .NET 方法包装成可被模型理解和调用的插件函数,这对让 AI 驱动业务动作尤其关键。
换句话说,如果直接调用 OpenAI API 解决的是“怎么和模型说话”,那么 Semantic Kernel 解决的就是“怎么让模型能力在一个真实项目里活得更像一等公民”。这也是为什么它在需要插件、记忆、工作流和函数调用的项目中会越来越常见。
二、先搭建第一个 Kernel
2.1 安装包并创建内核对象
学习 Semantic Kernel 最好的方式,不是先背概念,而是先把一个能跑起来的 Kernel 搭出来。只有当你看到模型服务是如何注册进内核里的,后面再理解插件、模板和聊天服务时才不会抽象。
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
using Microsoft.SemanticKernel;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
?? throw new InvalidOperationException("请先配置 OPENAI_API_KEY。");
var kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(modelId: "gpt-4o-mini", apiKey: apiKey)
.Build();
这里的 Kernel 可以理解成 Semantic Kernel 应用的运行中心。CreateBuilder 用来逐步添加能力,AddOpenAIChatCompletion 把 OpenAI 聊天模型注册进来,Build 则生成最终可使用的内核对象。这个过程和 ASP.NET Core 中通过 builder.Services 组装应用非常像,因此对 .NET 开发者来说学习成本并不高。
更重要的是,后面你不管是写 Prompt、做聊天、加插件,还是让模型调用函数,几乎都围绕这个 Kernel 展开。所以把它理解成 AI 运行时容器,会比单纯记忆 API 名称更有帮助。
2.2 先用 Prompt 感受最基础的调用方式
当 Kernel 准备好之后,最轻量的使用方式就是直接调用 Prompt。它适合快速验证一个提示词能否工作,也适合在后续示例里作为所有功能的共同入口。
var result = await kernel.InvokePromptAsync("请用三段话解释什么是 Semantic Kernel,以及它和直接调用模型 API 的区别。");
Console.WriteLine(result);
InvokePromptAsync 看上去像是在传一个字符串,但它背后已经经过了 Semantic Kernel 的统一执行管道。也就是说,你现在不需要自己 new 客户端、组织请求对象,就可以把一段 Prompt 直接交给内核处理。对初学者来说,这一步的重点不是代码更短,而是开始建立一个认识:以后你写的很多 AI 能力,都可以围绕“内核 + 输入参数 + 执行设置”来组织。
三、理解 Prompt、参数与聊天上下文
3.1 为什么 Prompt 模板和变量很重要
初学者写 Prompt 时,最容易养成的习惯是直接拼字符串。但在真实项目里,同一个提示往往要服务多种场景,例如语言不同、口吻不同、长度不同、上下文不同。如果没有模板和变量,你很快就会陷入大量重复字符串维护。Semantic Kernel 的 Prompt 模型,就是为了解决这个问题。
var promptTemplate = """
你是一名技术讲师,请把下面内容改写成{{style}}的中文说明,并控制在{{length}}字以内。
内容:{{$content}}
""";
var arguments = new KernelArguments
{
["style"] = "面向初学者、尽量通俗",
["length"] = 120,
["content"] = "Semantic Kernel 可以把模型调用、插件和提示模板组织到统一框架中。"
};
var result = await kernel.InvokePromptAsync(promptTemplate, arguments);
Console.WriteLine(result);
这个例子里,Prompt 不再是一段写死的文本,而是一个带占位符的模板。KernelArguments 用来为这些变量赋值,使得同一套模板可以在不同请求中重复使用。{{$content}} 通常表示正文输入,其他变量则负责控制风格、长度和业务语义。这样写的好处是后期维护很轻松:你改模板,不必改代码结构;你换参数,也不必复制多份 Prompt。
3.2 聊天历史和执行设置为什么要一起理解
Semantic Kernel 虽然能直接调用 Prompt,但在聊天机器人、问答助手这类场景里,使用聊天服务会更自然。因为它可以显式维护历史消息,同时允许你通过执行设置控制温度、最大输出长度和函数调用策略。这三者放在一起,才构成一段真正可控的对话。
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage("你是一名 .NET 架构学习助手,回答时先解释概念,再说明工程意义。");
history.AddUserMessage("什么是 RAG?");
history.AddAssistantMessage("RAG 是检索增强生成,它会先检索外部知识,再把结果交给模型生成回答。");
history.AddUserMessage("那它和微调有什么区别?");
var settings = new OpenAIPromptExecutionSettings
{
Temperature = 0.3,
MaxTokens = 400
};
var reply = await chatService.GetChatMessageContentAsync(history, settings, kernel);
Console.WriteLine(reply.Content);
这段代码把几个核心对象串到了一起。IChatCompletionService 是从内核里取出的聊天服务,ChatHistory 负责保存多轮对话,OpenAIPromptExecutionSettings 则规定本次调用的执行方式。很多新手觉得对话自动就有上下文,其实并不是这样;真正让模型理解追问关系的,是你把前面的系统消息、用户消息和助手回复都保存在了 history 中。
四、让模型调用你的 .NET 代码
4.1 插件的本质,是把普通方法变成模型可理解的能力
Semantic Kernel 最有代表性的特性之一,就是插件机制。它的价值不在于多一个概念,而在于你终于可以把原本写好的 .NET 方法,以一种对模型友好的方式暴露出去。这样模型就不只是回答文本,而是能在合适的时候调用你的业务函数,例如查询订单、添加日程、获取天气或写入工单。
using System.ComponentModel;
using Microsoft.SemanticKernel;
public sealed class CalendarPlugin
{
[KernelFunction, Description("添加团队日程")]
public string AddEvent(
[Description("日期,格式为 yyyy-MM-dd")] string date,
[Description("时间,格式为 HH:mm")] string time,
[Description("日程主题")] string topic)
{
return $"已记录日程:{date} {time} - {topic}";
}
[KernelFunction, Description("查看某一天的日程摘要")]
public string GetAgenda(
[Description("要查询的日期,格式为 yyyy-MM-dd")] string date)
{
return $"{date} 目前有 2 条日程:09:30 站会,15:00 架构评审。";
}
}
这个插件类里的方法本质上仍然是普通 C# 方法,真正让它们具有 AI 意义的,是 KernelFunction 和 Description 这些元数据。KernelFunction 告诉 Semantic Kernel:这个方法可以对外暴露给模型。Description 则告诉模型函数的用途和参数含义。模型并不会阅读你的源码逻辑,它主要依赖这些描述来判断什么时候应该调用这个函数、该传什么参数。
4.2 自动函数调用如何把聊天和业务动作串起来
当插件注册到内核之后,你就可以让模型在回答过程中自动触发这些函数。对于初学者来说,这是理解 AI 应用不只是聊天的关键一步:模型不再只是输出一段文本,而是可以借助你的函数完成有实际价值的动作。
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(modelId: "gpt-4o-mini", apiKey: apiKey);
builder.Plugins.AddFromType<CalendarPlugin>();
var kernel = builder.Build();
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddSystemMessage("你是一名日程助理,如果用户在安排会议或查询日程,请优先调用工具。");
history.AddUserMessage("帮我把明天下午 3 点的架构评审加入日程。");
var settings = new OpenAIPromptExecutionSettings
{
Temperature = 0,
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
var result = await chatService.GetChatMessageContentAsync(history, settings, kernel);
Console.WriteLine(result.Content);
这里最关键的配置是 ToolCallBehavior.AutoInvokeKernelFunctions。它表示当模型判断某个插件函数适合当前问题时,Semantic Kernel 可以自动代为调用,而不是仅仅返回“我想调用某个函数”的意图。整个执行流程大致是这样的:模型先读取用户问题与 system prompt,再根据插件描述判断是否需要工具,框架负责调用对应方法,最后把工具结果再交回模型组织成自然语言输出。
五、实战视角下如何使用 Semantic Kernel
5.1 一个简单的日程助手应该怎样组合起来
当前面的知识点连起来之后,你就能看出 Semantic Kernel 真正适合什么场景。比如做一个日程助手时,模型负责理解自然语言,插件负责执行“添加日程、查询日程”这类明确动作,聊天历史负责保持连续上下文,而 Kernel 则把这些部分放进同一套执行环境中。对于 .NET 团队来说,这意味着你可以沿用熟悉的服务封装、依赖注入和分层设计,只是在合适的位置把模型能力接进去。
一个可落地的做法通常是:把插件对应到现有业务服务,把 system prompt 写成清晰的角色和边界说明,把聊天历史存入会话或数据库,再通过 Web API 或消息队列对外提供服务。这样,Semantic Kernel 并不会取代你的业务代码,而是让模型能力以更整洁的方式融入现有系统。
5.2 什么时候应该用它,什么时候直接调 API 更合适
理解工具的边界,比盲目追求“上框架”更重要。如果你的需求只是单次问答、偶发摘要和简单改写,那么直接调用模型 API 往往更轻、更透明,调试也更方便。但如果你已经出现了模板复用、函数调用、多轮对话、插件组织和流程编排等需求,Semantic Kernel 就会逐渐体现出价值。
对初学者来说,最好的策略通常不是二选一,而是先会直接调用 API,再在项目复杂度上升时引入 Semantic Kernel。这样你既能理解底层原理,也不会在一开始就被框架概念压住。只要你明白它解决的是工程组织问题而不是模型能力问题,使用时就会更加从容。
练习题:
- 请用自己的话解释,为什么一个已经会调用模型 API 的项目,在需求复杂后仍然可能需要 Semantic Kernel。
- 试着把本文中的
CalendarPlugin再扩展一个“取消日程”的函数,并为参数补充清晰描述。- 假设你要做一个内部知识助理,分别说明 Prompt 模板、聊天历史和插件在系统里各自负责什么。
更多推荐

所有评论(0)