AI与.NET技术实操系列(四):使用Semantic Kernel和DeepSeek构建AI应用
引言
在人工智能技术飞速发展的今天,大型语言模型(Large Language Models, LLMs)已成为智能应用开发的核心驱动力。从智能客服到自动化内容生成,LLMs的应用正在深刻改变我们的工作和生活方式。
对于.NET开发者而言,掌握如何将LLMs集成到应用程序中,不仅是一项技术挑战,更是抓住未来趋势的关键。微软推出的Semantic Kernel(SK)为此提供了一个强大的工具,它使开发者能够在.NET环境中轻松构建基于LLMs的智能应用,大幅降低了开发门槛。
Semantic Kernel是一个开源项目,旨在为开发者提供一套灵活且功能丰富的API,以简化LLMs的集成和使用。通过SK,开发者可以快速实现智能对话、内容生成、知识检索等功能,而无需深入研究LLMs的底层实现。SK采用“插件化”和“模块化”的设计理念,允许开发者根据需求自由组合和扩展功能,打造高度定制化的AI应用。这种设计不仅提高了开发效率,还为创新提供了广阔的空间。
然而,SK的强大功能也伴随着一定的复杂性。开发者需要理解其核心概念(如“内核”、“技能”和“插件”),并掌握模型选择、性能优化和资源管理等技术细节。这些都需要一定的AI和.NET开发经验。
本文将通过一个具体的实践任务——构建一个智能助手,展示如何使用Semantic Kernel在.NET中开发AI应用。这个任务贴近实际业务需求,能够帮助读者深入理解SK的使用方法和设计哲学。我们将从SK的基础知识入手,逐步介绍其安装、配置和基本用法,并通过详细的代码示例,引导读者完成一个功能完备的智能助手应用。
希望本文能激发你的兴趣,帮助你在.NET中开启Semantic Kernel的探索之旅。随着AI技术的不断进步,SK将为开发者带来更多创新机会,让我们共同迎接智能应用的新时代!
Semantic Kernel简介
在深入探讨Semantic Kernel(SK)之前,我们先来了解它是什么以及它在AI应用开发中的作用。Semantic Kernel是微软开发的一个开源项目,旨在帮助开发者构建基于大型语言模型的智能应用程序。它提供了一套工具和API,使开发者能够轻松地将LLMs集成到.NET应用中,实现智能对话、内容生成和知识检索等功能。
什么是Semantic Kernel?
Semantic Kernel(SK)是一个轻量级的软件开发工具包(SDK),允许开发者通过.NET平台与LLMs进行交互。它的核心设计理念是“插件化”和“模块化”,使开发者能够根据需求灵活组合和扩展功能。SK通过以下关键组件实现其功能:
内核(Kernel):SK的核心组件,负责管理LLMs的调用、内存管理和技能的注册。它如同一个指挥中心,协调所有操作。 技能(Skills):一组预定义的功能模块,可以是原生的.NET代码,也可以是基于LLMs的提示(prompt)。技能是SK功能的具体实现单元。 插件(Plugins):技能的集合,可以作为一个整体注册到内核中,便于管理和复用。
通过这种设计,SK提供了一个灵活且可扩展的框架,使开发者能够快速构建复杂的AI应用。无论是简单的文本生成还是复杂的多轮对话系统,SK都能提供支持。
Semantic Kernel的优势
与直接调用LLMs的API相比,SK具有以下显著优势:
简化的API:SK封装了LLMs的复杂性,提供直观易用的接口,降低了开发难度。 插件化架构:开发者可以轻松添加、移除和组合技能,构建高度定制化的应用。 内存管理:SK内置了对上下文的管理功能,支持在对话中维护历史信息,提升交互的连贯性。 多模型支持:SK不仅兼容OpenAI的模型,还支持Azure OpenAI、Hugging Face等其他LLMs提供商的模型,具有良好的扩展性。
这些优势使SK成为.NET开发者构建AI应用的理想选择。无论你是初学者还是经验丰富的开发者,SK都能帮助你快速上手并实现创意。
设置和使用Semantic Kernel
在开始使用Semantic Kernel之前,我们需要进行一些准备工作,包括安装SK的NuGet包和配置开发环境。
安装Semantic Kernel
SK可以通过NuGet包管理器安装。以下是安装SK核心包的命令:
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.ChatCompletion
如果需要使用OpenAI的模型,还需安装相关的连接器包:
dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
这些包提供了SK的核心功能和与特定LLMs提供商交互的能力。
配置开发环境
SK支持.NET 6.0及以上版本,建议使用Visual Studio 2022或Visual Studio Code进行开发。以下是配置开发环境的步骤:
打开Visual Studio,创建一个新的.NET 控制台应用程序。 在解决方案资源管理器中,右键点击项目,选择“管理NuGet包”。 搜索“Microsoft.SemanticKernel”,安装最新版本。 在代码文件中添加必要的using指令:
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
完成这些步骤后,你的开发环境就已准备好,可以开始使用SK进行AI应用开发。
基本用法
在使用SK之前,我们需要初始化内核并配置LLMs的连接。以下是一个基本的配置示例:
var modelId = "";
var apiKey = "";
// Create a kernel with OpenAI chat completion
var builder = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId, apiKey);
// Build the kernel
Kernel kernel = builder.Build();
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
在这个示例中,如果使用的是OpenAI的GPT系列模型,你需要将"your-api-key"替换为你的OpenAI API密钥。如果使用其他模型(如Azure OpenAI),只需调整配置参数即可。
配置好内核后,我们可以通过SK调用LLMs生成文本。以下是一个简单的文本生成示例:
// Create a history store the conversation
var history = new ChatHistory();
// Get the response from the AI
var result = await chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAIPromptExecutionSettings,
kernel: kernel);
在这个示例中,我们直接将history传递给内核,SK会自动处理与LLMs的通信并返回生成的内容。这是最基本的用法,展示了SK的简洁性和易用性。
构建一个基于LLMs的智能应用
为了更好地理解Semantic Kernel的实际应用,我们将通过一个实践任务——构建一个智能助手,展示如何使用SK开发AI应用。这个智能助手能够回答用户的问题,并通过对话历史维护上下文,提供连贯的交互体验。
设计智能助手
在设计智能助手时,我们需要考虑以下几个方面:
用户输入:从控制台获取用户的问题或指令。 LLMs响应:使用SK调用LLMs生成回答。 对话管理:维护对话历史,确保回答与上下文相关。 技能扩展:为助手添加自定义功能,如查询天气或获取外部数据。
在这个示例中,我们将实现一个基础版的智能助手,随后展示如何通过技能扩展其功能。
实现智能助手
由于我的ChatGpt订阅已经过期,所以接下来应用所接入的大模型换成了DeepSeek,由于DeepSeek API 与 OpenAI 的ChatCompletion的 API 格式兼容,因此我们将复用 OpenAI 连接器,里面的代码只是做了一些微调。
不用设置OpenAPI的模型和API Key IChatCompletionService的获取方式发生了变化,不再从DI Container中获取,而是直接创建对象,有兴趣的朋友,可以把基于DeepSeek的IChatCompletionService对象注入到DI Container中,这样也显得专业,但这里就不做扩展了。
this._chatCompletionService = new OpenAIChatCompletionService("deepseek-chat", new Uri("https://api.deepseek.com"), "你的DeepSeek API Key");
以下是智能助手的完整代码实现:
class SmartAssistant
{
private readonly IChatCompletionService _chatCompletionService;
private readonly List<string> _conversationHistory = [];
private readonly Kernel _kernel;
public SmartAssistant()
{
// Create a kernel with OpenAI chat completion
IKernelBuilder builder = Kernel.CreateBuilder();
this._kernel = builder.Build();
this._chatCompletionService = new OpenAIChatCompletionService("deepseek-chat", new Uri("https://api.deepseek.com"), "你的DeepSeek API Key");
}
public async Task RunAsync()
{
Console.WriteLine("欢迎使用智能助手!输入 'exit' 退出。");
// Add a plugin (the LightsPlugin class is defined below)
//使用插件可以让你的人工智能代理能够运行你的代码以从外部来源检索信息或执行操作
this._kernel.Plugins.AddFromType<LightsPlugin>("Lights");
// Enable planning
OpenAIPromptExecutionSettings openAiPromptExecutionSettings = new()
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
// Create a history store the conversation
ChatHistory history = [];
// Initiate a back-and-forth chat
string? userInput;
do
{
// Collect user input
Console.Write("User > ");
userInput = Console.ReadLine();
// Add user input
history.AddUserMessage(userInput);
// Get the response from the AI
ChatMessageContent result = await this._chatCompletionService.GetChatMessageContentAsync(
history,
executionSettings: openAiPromptExecutionSettings,
kernel: this._kernel);
// Print the results
Console.WriteLine("Assistant > " + result);
// Add the message from the agent to the chat history
history.AddMessage(result.Role, result.Content ?? string.Empty);
} while (userInput is not null);
}
}
//使用插件可以让你的人工智能代理能够运行你的代码以从外部来源检索信息或执行操作。
public class LightsPlugin
{
// Mock data for the lights
private readonly List<LightModel> _lights =
[
new() { Id = 1, Name = "Table Lamp", IsOn = false },
new() { Id = 2, Name = "Porch light", IsOn = false },
new() { Id = 3, Name = "Chandelier", IsOn = true }
];
[KernelFunction("get_lights")]
[Description("Gets a list of lights and their current state")]
public async Task<List<LightModel>> GetLightsAsync()
{
return this._lights;
}
[KernelFunction("change_state")]
[Description("Changes the state of the light")]
public async Task<LightModel?> ChangeStateAsync(int id, bool isOn)
{
LightModel? light = this._lights.FirstOrDefault(light => light.Id == id);
if (light == null)
{
return null;
}
// Update the light with the new state
light.IsOn = isOn;
return light;
}
}
public class LightModel
{
[JsonPropertyName("id")] public int Id { get; set; }
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("is_on")] public bool? IsOn { get; set; }
}
//运行
var assistant = new SmartAssistant();
await assistant.RunAsync();
代码解析:
SmartAssistant类:封装智能助手的逻辑,使用 ChatHistory
存储对话历史。构造方法:初始化SK内核,创建DeepSeek的IChatCompletionService对象。 RunAsync方法:主方法,负责接收用户输入、构造提示、调用LLMs并输出回答。 ChatHistory和OpenAiPromptExecutionSettings构造:将对话历史拼接为完整的提示,确保上下文传递给LLMs。 内核调用:通过 DeepSeek的IChatCompletionService.GetChatMessageContentAsync
调用LLMs,获取生成的回答。
运行这段代码后,用户可以与智能助手进行多轮对话。例如:

这个智能助手展示了SK在对话管理方面的能力,开发者可以基于此进一步扩展功能。
Semantic Kernel在实际应用中的意义和挑战
Semantic Kernel为开发者提供了强大的工具,使他们能够快速构建基于LLMs的智能应用。然而,其应用价值和潜在挑战同样值得关注。
意义
加速开发:SK简化了LLMs的集成过程,使开发者能够专注于应用逻辑而非底层细节。 灵活性:插件化架构支持功能的自由扩展,适应多样化的业务需求。 提升体验:基于LLMs的智能应用能提供自然流畅的交互,显著改善用户体验。
例如,一个基于SK的智能客服系统可以在几小时内搭建完成,并根据企业需求快速调整功能,这种效率在传统开发中难以想象。
挑战
模型选择:不同的LLMs在性能、成本和适用场景上存在差异。开发者需要权衡这些因素,选择合适的模型。 性能优化:LLMs的调用涉及网络延迟和计算资源消耗,尤其在高并发场景下,需要优化架构以确保响应速度。 审查机制:LLMs可能生成不准确、有偏见甚至有害的内容,开发者必须实施审查机制,确保应用的安全性和公平性。
这些挑战要求开发者在技术实现之外,具备系统设计和伦理意识,才能充分发挥SK的潜力。
技术伦理
Semantic Kernel的出现不仅带来了技术上的便利,更引发了对AI应用深层次问题的思考。
技术与责任的平衡:随着AI能力的增强,开发者在享受技术红利时,也需承担确保应用安全、公正的责任。如何避免AI滥用,是一个值得探讨的话题。 隐私与数据安全:智能应用可能涉及用户数据的收集和处理,尤其在多轮对话中,开发者必须遵守隐私法规,保护用户权益。 社会的长期影响:AI技术的普及可能改变就业结构、决策方式甚至人际交往,开发者作为技术推动者,需思考如何让AI为社会带来正向价值。
这些问题没有简单的答案,但它们提醒我们:技术的发展不应只追求效率,更应关注其对人类和社会的影响。
结语
本文通过介绍Semantic Kernel的基础知识、设置和使用方法,以及构建智能助手的实践案例,为.NET开发者提供了一个全面而深入的指南。作为微软的开源项目,SK以其简洁的API、灵活的架构和强大的功能,为开发者打开了AI应用开发的大门。从基本的文本生成到复杂的技能扩展,SK的设计理念和特性为创新提供了无限可能。
通过本文的示例代码和讨论,希望你能感受到SK的实用性,并从中获得灵感,尝试在自己的项目中应用这一技术。随着AI技术的不断进步,Semantic Kernel将继续进化,为开发者带来更多机遇。让我们共同探索这一领域,在智能应用的浪潮中创造属于自己的价值!
参考链接:https://learn.microsoft.com/en-us/semantic-kernel/get-started/quick-start-guide?pivots=programming-language-csharp
AI与.NET技术实操系列(四):使用Semantic Kernel和DeepSeek构建AI应用的更多相关文章
- 技术实操丨HBase 2.X版本的元数据修复及一种数据迁移方式
摘要:分享一个HBase集群恢复的方法. 背景 在HBase 1.x中,经常会遇到元数据不一致的情况,这个时候使用HBCK的命令,可以快速修复元数据,让集群恢复正常. 另外HBase数据迁移时,大家经 ...
- sed修炼系列(四):sed中的疑难杂症
本文目录:1 sed中使用变量和变量替换的问题2 反向引用失效问题3 "-i"选项的文件保存问题4 贪婪匹配问题5 sed命令"a"和"N" ...
- Semantic Kernel 知多少 | 开启面向AI编程新篇章
引言 在ChatGPT 火热的当下, 即使没有上手亲自体验,想必也对ChatGPT的强大略有耳闻.当一些人在对ChatGPT犹犹豫豫之时,一些敏锐的企业主和开发者们已经急不可耐的开展基于ChatGPT ...
- .net基础学java系列(四)Console实操
上一篇文章 .net基础学java系列(三)徘徊反思 本章节没啥营养,请绕路! 看视频,不实操,对于上了年龄的人来说,是记不住的!我已经看了几遍IDEA的教学视频: https://edu.51cto ...
- Istio的流量管理(实操二)(istio 系列四)
Istio的流量管理(实操二)(istio 系列四) 涵盖官方文档Traffic Management章节中的inrgess部分. 目录 Istio的流量管理(实操二)(istio 系列四) Ingr ...
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- linux基础实操四
实操一: 1)为新加的硬盘分区,一个主分区大小为10剩余空间给扩展分区,在扩展分区上划分2个逻辑分别为5G 2)式化主分区为ext3系统 #mkfs.ext3 /dev/sdb1 3 将逻辑分区设置为 ...
- Istio的流量管理(实操一)(istio 系列三)
Istio的流量管理(实操一)(istio 系列三) 使用官方的Bookinfo应用进行测试.涵盖官方文档Traffic Management章节中的请求路由,故障注入,流量迁移,TCP流量迁移,请求 ...
- Java初学者作业——编写JAVA程序,要求输入技术部门5位员工的理论成绩和实操成绩,计算并输出各位员工的最终评测成绩。
返回本章节 返回作业目录 需求说明: 某软件公司要求对技术部门的所有员工进行技能评测,技术评测分为两个部分:理论部分以及实操部分,最终评测成绩=理论成绩×0.4+实操成绩×0.6,要求输入技术部门5位 ...
- 动手实操:如何用 Python 实现人脸识别,证明这个杨幂是那个杨幂?
当前,人脸识别应用于许多领域,如支付宝的用户认证,许多的能识别人心情的 AI,也就是人的面部表情,还有能分析人的年龄等等,而这里面有着许多的难度,在这里我想要分享的是一个利用七牛 SDK 简单的实现人 ...
随机推荐
- docker save与docker export实现docker镜像与容器的备份
本来想写一篇关于docker save/export/commit/load/import之间的关系的文章,后来看了看,已经有很多人写过了,我就不做重复工作了. 参见: docker save与doc ...
- helm values reference other values
https://helm.sh/docs/chart_template_guide/yaml_techniques/#yaml-anchors https://helm.sh/zh/docs/char ...
- File was changed on disk
刚开始从eclipse转到idea,发现idea从svn同步代码后,点开一个java类报错 说是某个方法不存在,以为是别人代码没有提全,就点到别人代码里面去看,顶行出现"File was c ...
- H2数据库用户自定义函数方法及范例
H2数据库,是Java实现的内存数据库.可使用它作为嵌入式内存数据库,但就其特性还用更多值得应用在实际项目中的意义.之前的一篇Blog中已经描述过其使用方法及丰富的连接数据库方式. 官方主页:http ...
- Qt编写安防视频监控系统65-子模块9数据调试
一.前言 数据调试模块,用于显示通信串口的数据,自定义不同颜色显示,可以勾选过滤某个串口进行数据查看,也可以选择所有数据,还可以勾选暂停显示复选框用来暂停打印显示信息.数据调试可以很方便的查看串口收发 ...
- Qt项目架构经验总结
(一)通用规则 除了极小的微型demo级别项目外,其余项目建议用pri分门别类不同文件夹存放代码文件,方便统一管理和查找. 同类型功能的类建议统一放在一起,如果该目录下代码文件数量过多,也建议拆分多个 ...
- spark (四) RDD概念
目录 1. RDD基本概念 1.1 弹性 1.2 分布式 1.3 数据集 1.4 数据抽象 1.5 不可变 1.6 可分区.并行计算 2. WordCount为例,看RDD特性 3. RDD的五大属性 ...
- DVWA靶场File Upload(文件上传) 漏洞所有级别通关教程及源码审计
文件上传 文件上传漏洞是由于对上传文件的内.类型没有做严格的过滤.检查,使得攻击者可以通过上传木马文件获取服务器的webshell文件 low 上传一个php文件,上传成功,并且可以在WWW\DVWA ...
- SQL优化——深分页&排序
问题背景 在开发 Web 应用或处理数据库查询时,分页是一项常见需求.然而,当面对深度分页(即页码较大,偏移量较高的分页情况)时,性能问题往往接踵而至.比如对一些需要拉特定的页面查询.范围导出.范围计 ...
- (.net core)Kong网关的使用
一.优势: 提供统一的 API 管理,简化流量控制.负载均衡.安全性控制等工作. 有可视化界面可操作,支持高度 可扩展性,可以通过插件来扩展功能. 在 微服务架构 中表现优异,支持多种协议和高并发场景 ...