惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
PCI Perspectives
PCI Perspectives
H
Help Net Security
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
S
Secure Thoughts
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
大猫的无限游戏
大猫的无限游戏
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Security @ Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
T
Tor Project blog
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
博客园 - 【当耐特】
G
Google Developers Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
I
Intezer
S
Schneier on Security
S
Securelist
W
WeLiveSecurity
C
Cybersecurity and Infrastructure Security Agency CISA
P
Palo Alto Networks Blog
Scott Helme
Scott Helme
Project Zero
Project Zero
Google Online Security Blog
Google Online Security Blog
T
Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Engineering at Meta
Engineering at Meta
Blog — PlanetScale
Blog — PlanetScale
V
Visual Studio Blog
Last Week in AI
Last Week in AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
A
Arctic Wolf
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog

博客园 - EdisonZhou

MAF快速入门(24)整合多个Skill来源 MAF快速入门(22)声明式Agent实战 MAF快速入门(21)RC5引入的Script运行能力 MAF快速入门(20)基于File-Based App开发MVP项目 MAF快速入门(19)给Agent Skill添加脚本执行能力 MAF快速入门(18)Agent Skill 快速开始 MAF快速入门(17)用户智能体交互协议AG-UI(下) MAF快速入门(16)用户智能体交互协议AG-UI(上) MAF快速入门(15)Agent调试利器:DevUI MAF快速入门(14)快速集成A2A Agent MAF快速入门(13)常见智能体编排模式 MAF快速入门(12)主工作流+子工作流 CTC蜀道会成都开发者年终聚会圆满结束! MAF快速入门(11)并行工作流 MAF快速入门(10)循环工作流 MAF快速入门(9)多路分支路由工作流 MAF快速入门(8)条件路由工作流 MAF快速入门(7)工作流的状态共享 MAF快速入门(6)混合编排工作流 MAF快速入门(5)开发自定义Executor
MAF快速入门(23)通过C#类定义Skills
EdisonZhou · 2026-04-17 · via 博客园 - EdisonZhou

大家好,我是Edison。

最近我一直在跟着圣杰的《.NET+AI智能体开发进阶》课程学习MAF开发智能体应用,我强烈推荐你也上车跟我一起出发!

MAF 1.1.0 推出了强类型Skill,是的你没有看错,我们可以通过C#类来定义可维护的Skill了。

1 强类型Skill

在写File类型的Skill的时候,我就在想MAF会不会支持强类型Skill,没想到这么快就来了。通过类定义Skill的优势在于强类型、可测试、易分发等。

类定义Skill的价值在于可以 资源、脚本、业务规则 内聚到一个C#类中,这样就便于代码治理、单元测试 与 团队协作。

不过,目前MAF的Agent Skills仍然属于实验性支持阶段,生产落地还需谨慎。这也就意味着,我们需要显示加入 #pragma warning disable MAAI001 来取消实验性告警

2 快速开始:跨境物流运营助手

这里我们来做一个跨境物流运营AI助手,体验一下强类型Skills。

在物流问答场景中,运营人员经常需要:

  • 读取换算规则(资源)
  • 执行换算动作(脚本)
  • 组织可解释的业务回复

在这个案例中,我们可以将上面提到的三类统一内聚到一个类中来管理。

本文案例使用的模型为:Qwen3.5-35B-A3B

在开始之前,我们创建了一个控制台应用,并安装了以下NuGet包:

<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.1.0" />

类定义Skill

首先,我们创建一个class文件命名为UnitConverterSkill,内容如下:

internal sealed class UnitConverterSkill : AgentClassSkill<UnitConverterSkill>
{
    public override AgentSkillFrontmatter Frontmatter { get; } = new(
        "unit-converter",
        "Convert between common units using multiplication factors.");
    
    protected override string Instructions => """
        当用户询问距离或重量换算时:
        1. 先读取 conversion-table 资源,找到对应换算系数。
        2. 再调用 convert 脚本执行计算,参数为用户输入的数值value和换算系数factor。
        3. 回复内容需要清晰地展示换算系数、换算过程和换算结果,并同时标明换算前后的两个单位。
        """;
    
    protected override JsonSerializerOptions? SerializerOptions => null;
    
    [AgentSkillResource("conversion-table")]
    [Description("常见距离与重量换算系数表。")]
    public string ConversionTable => """
        # Conversion Table
        Formula: result = value × factor
        | From       | To         | Factor   |
        |------------|------------|----------|
        | miles      | kilometers | 1.60934  |
        | kilometers | miles      | 0.621371 |
        | pounds     | kilograms  | 0.453592 |
        | kilograms  | pounds     | 2.20462  |
        """;

    [AgentSkillScript("convert")]
    [Description("按 value × factor 执行换算,并返回 JSON。")]
    public static string ConvertUnits(double value, double factor)
    {
        double result = Math.Round(value * factor, 4);
        return JsonSerializer.Serialize(new { value, factor, result });
    }
}

可以看到上面的内容其实就是把我们之前在文件skill中的内容都体现出来,只不过是通过继承AgentClassSkill<T> + Attribute的声明式组合来实现的。

创建中间件

为了方便看到Skill调用过程,我们实现一个带日志记录的工具调用中间件,其作用主要是记录Tool的执行日志,也可以方便我们验证Skill是否触发。

internal class ToolExecutionLoggingMiddleware
{
    /// <summary>
    /// 简化版函数调用中间件 - 记录 Tool 执行日志
    /// </summary>
    public static async ValueTask<object?> ExecuteAsync(
        AIAgent agent,
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
        CancellationToken cancellationToken)
    {
        Console.WriteLine($"\n→ 🍴Tool: {context.Function.Name}");
        var result = await next(context, cancellationToken);
        Console.WriteLine($"← 🥣Result: {result}");
        return result;
    }
}

创建Agent

这里我们通过AgentSkillsProvider来创建Agent,同时使用AgentBuilder注册我们写的日志中间件:

var skillsProvider = new AgentSkillsProvider(new UnitConverterSkill());
AIAgent agent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
    Name = "UnitConverterAgent",
    ChatOptions = new()
    {
        Instructions = "你是一个专业的AI助手,负责帮助用户实现单位的转换,使用用户提问的语言进行回复。",
    },
    AIContextProviders = [skillsProvider],
});
// 💡 使用 Agent Builder 注册函数调用中间件
agent = agent
    .AsBuilder()
    .Use(ToolExecutionLoggingMiddleware.ExecuteAsync) // 使用工具执行日志中间件,记录工具调用的日志
    .Build();
Console.WriteLine("✅ 基于强类型Skills 的 AI Agent 创建成功");
Console.WriteLine();

测试回答问题

这里还是之前的两个问题,一个中文一个英文来测试一下:

var session = await agent.CreateSessionAsync();
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"开始测试:基于 Class-Based Skills");
// 中文问题:英里 -> 公里
var question1 = "马拉松比赛的距离26.2 英里是多少公里?";
Console.WriteLine($"👤 用户: {question1}");
Console.WriteLine();
var response1 = await agent.RunAsync(question1, session);
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"🤖 Agent: {response1.Text}");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();
// 英文问题:磅 -> 千克
var question2 = "How many pounds is 75 kilograms?";
Console.WriteLine($"👤 用户: {question2}");
Console.WriteLine();
var response2 = await agent.RunAsync(question2, session);
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine($"🤖 Agent: {response2.Text}");
Console.WriteLine("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Console.WriteLine();

测试结果如下图所示:

问题1:可以看到unit-convert skill的相关资源都被调用触发,最终完成回复。

image

问题2:由于问题一已经加载了skill.md和reference文档,它们已经在上下文中了,所以这次直接执行了脚本就完成了回复。

image

3 小结

本文介绍了MAF新推出的强类型Skill这个特性,通过类定义Skill可以将 资源、脚本、业务规则内聚到一个C#类中,这样就便于代码治理、单元测试 与 团队协作。

不过,目前MAF的Agent Skills仍然属于实验性支持阶段,生产落地还需谨慎。

示例源码

GitHub: https://github.com/EdisonTalk/MAFD

参考资料

圣杰,《.NET + AI 智能体开发进阶》(推荐指数:★★★★★)

Microsoft Learn,Agent Framework Tutorials