关注

第2系列_第3期_.NET AI 插件热加载机制_DLL扫描到Kernel注册

.NET AI 插件热加载机制:从 DLL 扫描到 Kernel 注册

系列: .NET C# Semantic Kernel 集成深度解析 ③/6
难度: ⭐⭐⭐(进阶源码,需.NET基础)
源码仓库: github.com/zongge0812/zonggeAgent
适用环境: .NET 9.0 + WPF


一、引言

在 AI 桌面应用中,插件的意义远超传统软件——SK 的插件系统直接赋予 AI “动手能力”。AI 不是光说不练,而是可以通过插件读取文件、分析代码、生成文档。

zonggeAgent 的插件系统实现了 3 个关键能力

┌──────────────────────────────────────────────────────────────┐
│  ① 热加载:新插件编译后直接放入目录,应用无需重启即可生效    │
│  ② 自动发现:DLL 扫描 + 反射 + ITools 接口自动匹配            │
│  ③ 权限过滤:聊天模式只读,开发模式全读写(安全隔离)        │
└──────────────────────────────────────────────────────────────┘

二、整体架构

插件系统的核心是 PluginLoader 静态类,位于 Tools/Implementations/ 目录下:

PluginLoader(静态类)
│
├── 缓存:_pluginsCache(List<PluginsCache>)
│
├── RegisterPlugin(Kernel)    → 入口:将插件注册到SK Kernel
│
├── LoadPluginsFromDirectories() → 核心:多目录扫描 + 反射加载
│   ├── ScanDirectoryForPlugins(baseDir)       → 主目录
│   └── ScanDirectoryForPlugins("plugins/")    → 热更新目录
│
├── ClearPluginCache()        → 清空缓存,支持热替换时重新加载
│
└── RegisterPluginDependencies() → 注册插件依赖到SK的IServiceCollection

调用位置

BaseAIProviderService.SendMessageAsync()SendMessageStreamAsync() 中调用:

// 每次对话都会执行
var chatService = await CreateChatServiceAsync(config);
var kernel = CreateKernel(chatService);

// ⚡ 热加载注册插件工具
PluginLoader.RegisterPlugin(kernel);

// 💬 聊天模式过滤
kernel = ApplyChatModeFilter(kernel, chatService);

这意味着:每次对话都会重新检查插件,热更新后的 DLL 在下一次对话立即生效。


三、DLL 扫描策略

3.1 双目录扫描

private static void LoadPluginsFromDirectories(
    Kernel kernel,
    string pluginDir = "plugins",
    string searchPattern = "*.dll")
{
   
   
    var scannedAssemblies = new List<Assembly>();
    var baseDir = AppDomain.CurrentDomain.BaseDirectory;

    // 1️⃣ 扫描程序主目录(bin/Debug/net9.0-windows/)
    //    编译后的插件DLL所在位置
    ScanDirectoryForPlugins(baseDir, searchPattern, scannedAssemblies);

    // 2️⃣ 扫描 plugins/ 子目录(热加载扩展点)
    var pluginDirectory = Path.Combine(baseDir, pluginDir);
    if (Directory.Exists(pluginDirectory))
    {
   
   
        ScanDirectoryForPlugins(pluginDirectory, searchPattern, scannedAssemblies);
    }
    else
    {
   
   
        Directory.CreateDirectory(pluginDirectory); // 创建空目录
    }
}
扫描目录 用途 更新方式
主目录 bin/Debug/net9.0-windows/ 项目编译时自动输出的插件DLL 重新编译项目
plugins/ 外部开发者/社区贡献的热加载DLL 直接放入DLL文件,无需编译

3.2 程序集过滤

不是所有 DLL 都是插件——ScanDirectoryForPlugins 内部实现了严格的过滤逻辑:

private static void ScanDirectoryForPlugins(
    string directory,
    string searchPattern,
    List<Assembly> scannedAssemblies)
{
   
   
    var dllFiles = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly);

    foreach (var dllPath in dllFiles)
    {
   
   
        var assemblyName = AssemblyName.GetAssemblyName(dllPath);
        var name = assemblyName.Name ?? "";

        // 🚫 跳过系统/框架程序集
        if (name.StartsWith("Microsoft.") || name.StartsWith(

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/Myasdfg0812/article/details/162954905

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--