基于.Net的NetCoreKevin框架中AgentFramework实现AI智能体Skill和工具动态管理和加载
系统实现效果图
开源地址
https://github.com/junkai-li/NetCoreKevin
https://gitee.com/netkevin-li/NetCoreKevin
1. 背景与目标
在大模型应用开发中,智能体需要灵活组合各种 工具(Tool) 与 技能(Skill) 来完成任务。NetCoreKevin 框架基于自主研发的 AgentFramework 底层,提供了一套"数据驱动 + 文件热加载"的动态能力扩展方案,让开发者无需修改核心代码即可为不同智能体按需配置工具和技能。
本文深入剖析该方案的实现细节,涵盖从数据库定义、动态注入 AITool,到 .zip 技能包的自动解压与加载全过程,帮助读者快速理解底层架构并应用于实际项目。
2. 整体架构概览
NetCoreKevin 的能力管理分为两个维度:
- 工具(Tool) :粒度小、无状态,通过
AIFunctionFactory将普通 C# 方法包装为 AI 可调用的函数,直接注入ChatOptions.Tools列表。 - 技能(Skill) :有状态的复合能力单元,以文件包(
.zip)形式存储,通过AgentSkillsProviderBuilder构建为AIContextProvider,由 AgentFramework 负责调度。
核心组件协作关系如下:
┌─────────────────────────────────────────────┐
│ ChatClientAgent │
│ (ChatOptions.Tools + AIContextProviders) │
└───────┬──────────────────────┬─────────────┘
│Tools │Skills
▼ ▼
┌──────────────┐ ┌───────────────────────┐
│AIAgentTool │ │AgentSkillsProvider │
│SkillService │ │Builder (AgentFramework)│
└──┬───┬───────┘ └───────────┬───────────┘
│ │ │
│ ▼ ▼
│ SysTools (静态工具) 文件系统 Skill 目录
│ IKevinAITaskService 等
▼
AISkillToolManagementService (数据库)
底层完全依赖 AgentFramework 提供的:
AgentSkillsProviderBuilder、AgentFileSkillsSourceOptionsAITool、AIFunctionFactoryPySubprocessScriptRunner等执行器
3. 数据驱动的 Skill 与 Tool 定义
框架将工具和技能统一存储在 TAISkillToolManagement 实体中,由 IAISkillToolManagementService 提供管理服务。关键字段包括:
| 字段 | 说明 |
|---|---|
| Name | 工具/技能唯一标识名 |
| SkillToolType | 枚举:Tool / Skill |
| ClassMethod | 工具绑定的方法名(如 AddOrUpdateCronTask) |
| Description | 功能描述,供大模型决策用 |
| ActiveStatus | 是否启用 |
| IsSystem | 是否系统内置(禁止删除) |
技能还附带一个 .zip 附件,包含脚本文件、资源等,通过文件服务管理。
csharp
// 获取所有启用的工具
public async Task<List<AISkillToolManagementDto>> GetAllTools()
{
return (await AISkillToolManagementRp.Query(...)
.Where(t => t.SkillToolType == AISkillToolTypeEnums.Tool
&& t.ActiveStatus == InActiveStatusEnums.Active)
.ToListAsync())
.MapToList<TAISkillToolManagement, AISkillToolManagementDto>();
}
4. 工具的动态注入
工具注入由 AIAgentToolSkillService 实现,其核心流程为:
- 根据
agentId查询绑定表IAISkillToolBindIdService,获得该智能体允许使用的工具管理 ID。 - 通过
AISkillToolManagementService.GetAllTools()过滤出这些 ID 对应的工具记录,提取ClassMethod名称。 - 调用
GetAITools将方法名转化为AITool实例。
4.1 静态工具与动态工具的区分
SysTools.Tools 是一个预注册的全局字典,存放所有"静态工具"(无需依赖注入即可直接使用的工具)。如果工具名存在于字典,直接取出;否则进入 switch 分支,通过 AIFunctionFactory.Create 将具体服务方法包装为 AITool。
csharp
private async Task<List<AITool>> GetAITools(object data, List<string> toolNames)
{
var aiTools = new List<AITool>();
_kevinAITaskService.InitData(data);
foreach (var item in toolNames)
{
if (SysTools.Tools.ContainsKey(item))
{
aiTools.Add(SysTools.Tools[item]); // 静态工具
}
else
{
switch (item)
{
case "AddOrUpdateCronTask":
aiTools.Add(AIFunctionFactory.Create(
_kevinAITaskService.AddOrUpdateCronTask,
new AIFunctionFactoryOptions { Name = "AddOrUpdateCronTask",
Description = "创建或更新一个周期性自动任务" }));
break;
case "RemoveCronTask":
// ... 类似
break;
// ... 更多工具
}
}
}
return aiTools;
}
4.2 与智能体集成
在构造 ChatClientAgentOptions 时,如果配置启用了工具,则从服务中获取工具列表,合并到 ChatOptions.Tools:
csharp
if (aiapp.IsAITools)
{
chatAgOs.ChatOptions.Tools ??= new List<AITool>();
chatAgOs.ChatOptions.Tools.AddRange(
_aIAgentToolSkillService.GetUserAIAgentToolsAsync(
new { AIChatsId = add.AIChatsId },
aiapp.Id.ToString(),
CurrentUser.UserId.ToString()
).Result
);
}
这样每个智能体实例都能拥有不同的工具集,实现多租户级别的能力隔离。
5. 技能文件的动态加载
技能本质上是包含脚本(.py、.sh、.ps1)和资源文件的目录包。上传时打包为 .zip,由 AISkillToolManagementService.AddEdit 负责下载、解压并放置到应用根目录下的 Skills/{技能名称}/ 路径中。
csharp
// 处理技能 zip 包
if (data.SkillToolType == AISkillToolTypeEnums.Skill)
{
var flieData = _FileRp.Query().FirstOrDefault(t =>
t.Table == "AISkillToolManagement" && t.Sign == "SkillZip" && t.TableId == data.Id.ToString());
if (flieData != null)
{
var path = Path.Combine(AppContext.BaseDirectory, "Skills", data.Name, data.Name);
if (Directory.Exists(path))
Directory.Delete(path, true);
Directory.CreateDirectory(path);
_FileStorage.FileDownload(flieData.Url, path + flieData.Name);
using var fileStream = File.OpenRead(path + flieData.Name);
FileZipHelper.ExtractZipStreamToDirectory(fileStream, path);
File.Delete(path + flieData.Name); // 删除原始 zip
}
}
5.1 通过 AgentFramework 注册文件技能
在构建智能体时,从服务获取该智能体绑定的技能路径列表,然后利用 AgentSkillsProviderBuilder 将它们逐一注册为 FileSkill:
csharp
if (aiapp.IsSkill)
{
var skillPaths = _aIAgentToolSkillService.GetUserAIAgentSkillsAsync(...).Result;
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileScriptRunner(PySubprocessScriptRunner.StaticRunAsync)
.UseOptions(options => options.DisableCaching = true);
foreach (var skillPath in skillPaths)
{
skillsProvider.UseFileSkill(
Path.Combine(AppContext.BaseDirectory, "Skills", skillPath),
new AgentFileSkillsSourceOptions
{
AllowedScriptExtensions = [".py", ".sh", ".ps1"],
ScriptDirectories = ["scripts", "tools", "templates"],
});
}
chatAgOs.AIContextProviders = [skillsProvider.Build()];
}
AgentSkillsProviderBuilder 属于 AgentFramework 核心,它负责扫描指定目录下的脚本文件,并与 PySubprocessScriptRunner 等执行器关联,生成可以响应大模型调用的技能上下文。
6. 管理与绑定服务
6.1 技能/工具管理服务
AISkillToolManagementService 提供标准 CRUD 操作:
- 分页查询,支持按类型筛选;
- 新增/编辑时自动处理附件解压;
- 删除(逻辑删除)并对系统内置项进行保护。
6.2 智能体绑定
IAISkillToolBindIdService 维护智能体与技能/工具管理 ID 的映射关系,决定每个智能体可用的能力列表。AIAgentToolSkillService 正是依赖此服务实现按 agentId 和 userId 的动态过滤。
csharp
public async Task<List<AITool>> GetAIAgentToolsAsync(object data, string agentId)
{
var agentBindIds = (await _iAISkillToolBindIdService.GetListById(agentId))
.Select(t => t.AISkillToolManagementId).ToList();
var tools = (await _iAISkillToolManagementService.GetAllTools())
.Where(t => agentBindIds.Contains(t.Id)).ToList();
return await GetAITools(data, tools.Select(t => t.ClassMethod ?? "").ToList());
}
这种方式使得能力配置完全与代码分离,可通过后台管理界面灵活调整,而无需重启服务。
7. 总结
NetCoreKevin 框架基于 AgentFramework,通过 数据库驱动 + 文件系统热加载 实现了 AI 智能体工具与技能的动态管理。其核心优势在于:
- 工具注入 :方法名映射与
AIFunctionFactory结合,可零侵入地将业务方法暴露给大模型。 - 技能加载 :
.zip文件包上传自动解压,再利用AgentSkillsProviderBuilder注册为上下文提供者,支持脚本类技能的热插拔。 - 权限隔离:通过绑定表实现不同智能体、不同用户的能力差异化,满足多租户场景。
该方案已在生产环境中验证,显著提升了智能体应用的迭代效率和可维护性。未来框架还将引入远程插件仓库、版本回滚等高级特性,持续降低智能体扩展的门槛。
本文所有代码均基于 NetCoreKevin 框架及 AgentFramework 真实实现。