news 2026/4/20 10:23:53

MAF快速入门(23)通过C#类定义Skills

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MAF快速入门(23)通过C#类定义Skills

大家好,我是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。

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

  1. 读取换算规则(资源)

  2. 执行换算动作(脚本)

  3. 组织可解释的业务回复

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

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

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

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

首先,我们创建一个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

这里我们来创建Agent:

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的相关资源被调用触发,最终完成回复。

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

3 小结

本文介绍了MAF新推出的强类型Skill这个特性,通过类定义Skill可以将 资源、脚本、业务规则内聚到一个C#类中,这样就便于代码治理、单元测试 与 团队协作。不过,目前MAF的Agent Skills仍然属于实验性支持阶段,生产落地还需谨慎。

示例源码

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

参考资料

圣杰,《.NET + AI 智能体开发进阶》

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 10:21:39

启发式算法WebApp实验室:从搜索策略到群体智能的能力进阶 (九)

一、引言&#xff1a;从“求解问题”到“设计搜索策略”在复杂优化问题中&#xff0c;我们往往面对一个根本性困境&#xff1a;问题可以形式化&#xff0c;但最优解难以在可接受时间内获得例如&#xff1a;上百节点的路径规划&#xff08;旅行商问题&#xff09;大规模组合选择…

作者头像 李华
网站建设 2026/4/20 10:18:23

从报表到大屏:手把手教你用 ECharts 坐标轴打造专业级数据可视化风格

从报表到大屏&#xff1a;手把手教你用 ECharts 坐标轴打造专业级数据可视化风格 数据可视化是现代商业决策和运营分析的核心工具。从简洁的商务报表到复杂的指挥中心大屏&#xff0c;如何通过坐标轴配置提升数据呈现的专业度&#xff0c;是每个前端工程师和数据分析师必须掌握…

作者头像 李华
网站建设 2026/4/20 10:13:21

别再折腾Python版本了!Windows Server上Seafile 5.0.3保姆级安装避坑指南

Windows Server上Seafile 5.0.3企业级部署全攻略 当企业需要搭建私有云存储时&#xff0c;Seafile凭借其出色的文件同步和团队协作功能成为热门选择。但在Windows Server环境部署时&#xff0c;Python版本兼容性问题往往成为技术人员的噩梦。本文将彻底解决这个痛点&#xff0…

作者头像 李华
网站建设 2026/4/20 10:12:22

小鼠基因qPCR总失败?试试哈佛PrimerBank数据库和Primer3 Plus的黄金组合

小鼠基因qPCR引物设计实战&#xff1a;从PrimerBank到Primer3 Plus的高效策略 当你在深夜的实验室里盯着qPCR仪上那条扭曲的扩增曲线时&#xff0c;是否曾怀疑过引物设计才是实验失败的罪魁祸首&#xff1f;作为分子生物学研究的基石技术&#xff0c;定量PCR的成败往往在引物设…

作者头像 李华