现在 Microsoft Agent Framework(简称 MAF)在 2026 年已经越来越稳定,.NET 开发者也因此有了一个很好的机会去做出真正能在企业里用的 AI 智能体(Agent)。这篇文章会重点介绍怎么用类的方式来开发技能,并且说明如何借助大家熟悉的面向对象思路,把智能体的功能模块做得结构清楚、容易组合,还能被有效管理。


一、为什么推荐用“类”来做技能?

早先 MAF 的版本里,大家通常靠写静态文件(比如 SKILL.md)或者直接注册函数来定义技能。这种方式虽然一开始上手快,但一旦用在正式项目里,问题就慢慢出来了:

  • 代码和提示词混在一起,改一处可能影响很多地方,维护起来很麻烦;
  • 写好的功能很难在别的地方再用,也不能通过继承或组合来扩展;
  • 没办法加权限控制、操作记录或者版本追踪这些企业真正需要的能力。

而如果用类来组织技能,这些问题就能自然解决。因为每个技能就是一个独立的对象,既能封装自己的逻辑,又方便测试和复用,完全符合 .NET 开发者平时写代码的方式。


二、基本的结构怎么搭

1. 先写一个通用的基类 AgentSkill

public abstract class AgentSkill
{
    public string Name { get; }
    public string Description { get; }

    protected AgentSkill(string name, string description)
    {
        Name = name;
        Description = description;
    }

    public abstract Task<SkillResult> ExecuteAsync(SkillContext context);
}

2. 用 SkillContext 把运行时需要的信息传进去

public class SkillContext
{
    public required IChatClient ChatClient { get; init; }
    public required Dictionary<string, object> Parameters { get; init; }
    public required ILogger Logger { get; init; }
    public CancellationToken CancellationToken { get; init; }
}

3. 执行完以后统一用 SkillResult 返回结果

public record SkillResult(bool Success, string? Message, object? Data = null);

三、动手做个例子:自动对账功能

我们拿公司里经常要做的 银行流水和账本自动比对 来演示怎么实现一个具体的技能:

public class ReconciliationSkill : AgentSkill
{
    private readonly IFinancialService _financialService;

    public ReconciliationSkill(IFinancialService financialService)
        : base("Reconciliation", "自动比对银行流水和账务数据")
    {
        _financialService = financialService;
    }

    public override async Task<SkillResult> ExecuteAsync(SkillContext context)
    {
        try
        {
            var bankStatement = context.Parameters["bankStatement"] as string;
            var ledgerEntries = context.Parameters["ledgerEntries"] as string[];

            var discrepancies = await _financialService.CompareAsync(bankStatement, ledgerEntries);

            if (discrepancies.Any())
            {
                return new SkillResult(false, "发现对账不一致", discrepancies);
            }

            return new SkillResult(true, "账目核对成功");
        }
        catch (Exception ex)
        {
            context.Logger.LogError(ex, "对账技能出错");
            return new SkillResult(false, "系统内部错误");
        }
    }
}

四、怎么把它接进 MAF 框架里

MAF 提供了 AIContextProvider 这个扩展点,我们可以用它把所有技能自动注册进去:

public sealed class SkillsContextProvider : AIContextProvider
{
    private readonly IEnumerable<AgentSkill> _skills;

    public SkillsContextProvider(IEnumerable<AgentSkill> skills)
    {
        _skills = skills;
    }

    public override async Task PopulateContextAsync(AIContext context, CancellationToken cancellationToken = default)
    {
        foreach (var skill in _skills)
        {
            context.Functions.Add(
                new FunctionDefinition(
                    name: skill.Name,
                    description: skill.Description,
                    parameters: new JsonObject { /* 这里定义参数格式 */ }
                )
            );
        }
    }
}

然后在程序启动文件 Program.cs 里加上这两行,让系统知道要用这个技能:

builder.Services.AddSingleton<AgentSkill, ReconciliationSkill>();
builder.Services.AddSingleton<AIContextProvider, SkillsContextProvider>();

五、这样写更容易加上管理功能

因为每个技能都是一个类,所以很容易在里面加入企业实际需要的管控能力:

  • 比如在执行前检查用户有没有权限;
  • 或者统一记下谁在什么时候调用了什么功能、输入了什么、结果怎么样;
  • 出问题的时候可以用像 Polly 这样的工具做自动重试或降级处理;
  • 还可以通过加标签或者放在不同命名空间里来区分技能的版本。

六、最后说几句

“.NET + AI” 不只是把两个技术拼在一起,而是让写代码的人能用熟悉的方法去构建智能系统。用类来组织技能,就能把以前做软件工程的经验——比如封装、复用、测试、监控——都用到 AI 能力上,让这些智能功能不再是看不清、摸不着的黑盒子,而是实实在在、能长期维护、能持续改进的企业资产。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐