.NET+AI | Agent Skills | 强类型 Agent Skills 如此优雅,助你轻松业务系统 Skills 化

发布时间:2026/7/14 10:48:44
.NET+AI | Agent Skills | 强类型 Agent Skills 如此优雅,助你轻松业务系统 Skills 化 目录一、为什么 File-based 之后还需要 Class-based Skill二、AgentClassSkill 到底带来了什么三、它是怎么进入 Agent 运行链路的四、为什么它更适合工程化五、它和 File-based Skill 是替代关系吗六、总结上一篇如果说 Inline Skill 解决的是“先把能力接进来”File-based Skill 解决的是“怎么把能力沉淀成资产”那么到了 Class-based Skill问题就变成了当一个 Skill 已经足够稳定甚至准备进入系统内部长期维护时能不能用更清晰、更可治理的方式来组织它这正是AgentClassSkillT出现的意义。它的重点不是再换一种写法而是把 Skill 从“可复用资产”进一步推进到“可治理模块”。一、为什么 File-based 之后还需要 Class-based SkillFile-based Skill 已经解决了很多问题比如结构化、分发、共享、跨项目复用。但它更偏“外部化能力资产”。而在真实项目里总有一些 Skill 会逐步稳定下来变成系统内部的核心能力。比如订单查询、物流换算、售后规则解释、风控校验。这类能力往往不只是“能共享”就够了还会进一步要求• 更清晰的类型约束• 更自然的单元测试• 更稳定的重构支持• 更容易接入 DI、日志、安全、审批这时候Class-based Skill 的价值就体现出来了。它不是把 Skill 做成一个文件目录而是直接把 Skill 做成一个强类型 C# 类。二、AgentClassSkillT到底带来了什么Class-based Skill 最核心的变化是把 Skill 的关键组成重新收拢到一个类型里。比如在物流换算场景里一个最小但有业务意义的 Skill 可以这样写#pragma warning disable MAAI001 using System.ComponentModel; using System.Text.Json; internal sealed class UnitConverterClassSkill : AgentClassSkillUnitConverterClassSkill { public override AgentSkillFrontmatter Frontmatter { get; } new( unit-converter, Convert between common logistics units.); protected override string Instructions 当用户询问距离或重量换算时 1. 先读取 conversion-table 2. 再调用 convert 3. 回复中包含原始值、系数和结果 ; [AgentSkillResource(conversion-table)] [Description(距离与重量换算系数表)] public string ConversionTable miles - kilometers 1.60934 kilograms - pounds 2.20462 ; [AgentSkillScript(convert)] [Description(按 value × factor 执行换算)] private static string Convert(double value, double factor) { return JsonSerializer.Serialize(new { value, factor, result Math.Round(value * factor, 4) }); } }这段代码已经把Frontmatter、Instructions、资源和脚本收进了同一个类里。这件事的意义不只是“结构更整齐”而是 Skill 的边界终于变得清晰了。你不再需要把说明写在一处、资源放在一处、动作散在另一处而是可以把这些能力收敛成一个完整对象。从工程角度看这种写法真正带来的不是优雅感而是可控感。三、它是怎么进入 Agent 运行链路的Class-based Skill 的底层思路其实并不复杂。框架会通过 Attribute 去扫描这个 Skill 类的成员• 哪些是资源• 哪些是脚本• 它们分别叫什么• 该怎么向模型描述然后再把这个 Skill 实例交给AgentSkillsProvider作为AIContextProvider挂到 Agent 上下文中。例如var classSkill new UnitConverterClassSkill(); var provider new AgentSkillsProvider(classSkill); var agentOptions new ChatClientAgentOptions { Name ClassSkillUnitConverterAgent, AIContextProviders [provider] };这意味着AgentClassSkillT并不是一个孤立的类型设计而是和整个 Agent 上下文装配机制连在一起的。模型最终看到的也不是“一个 C# 类”而是这个类经过扫描、注册和注入之后形成的 Skill 语义。所以Class-based Skill 的本质不是“代码式 Skill”而是“通过强类型类来声明 Skill”。四、为什么它更适合工程化这一点才是 Class-based Skill 最值得关注的地方。因为一旦 Skill 变成标准 C# 类你就自然拥有了很多 File-based 很难直接获得的能力• 编译期检查• IDE 重构支持• 更自然的单元测试• 更方便接入依赖注入• 更容易挂接日志、安全、审批等治理机制换句话说Class-based Skill 的优势不在“分发”而在“治理”。它特别适合那些已经不再频繁变化、但需要长期演进和稳定维护的核心能力。所以从定位上看• File-based Skill 更像外部化能力资产• Class-based Skill 更像系统内部能力模块前者强调可共享后者强调可治理。五、它和 File-based Skill 是替代关系吗不是。这两者最容易被误解成“一个新版本替代一个旧版本”但其实不是这个关系。更准确地说它们解决的是不同层面的问题• File-based Skill 解决“怎么把能力做成资产”• Class-based Skill 解决“怎么把能力做成模块”一个偏外部化一个偏工程化。所以在真实项目里它们很可能会长期共存• 可分发、可热更新、可共享的能力适合 File-based• 稳定、核心、需要测试和治理的能力适合 Class-based真正成熟的思路不是争论哪一种更高级而是根据能力属性选择更合适的载体。六、总结Class-based Skill 真正补齐的不是另一种写法而是一条更适合长期治理的 Skill 工程路径。它让 Skill 不再只是“能被 Agent 调用”也开始具备“能被系统长期维护”的结构基础。如果说 Inline Skill 代表“先接入”File-based Skill 代表“再沉淀”那么 Class-based Skill 代表的就是“进一步治理”。下一篇我们就把这三种写法放在一起看Inline、File-based、Class-based到底该怎么选引入地址