Skip to content
Go back

Squad 接入 Agent Framework:会学习的团队

Microsoft Agent Framework(MAF)现在可以创建以 GitHub Copilot SDK 为后端的智能体:这类智能体天然具备执行 shell 命令、读写文件、抓取 URL、集成 MCP 服务器的编码能力。而 Squad 是跑在 GitHub Copilot CLI/SDK 之上的开源多智能体框架——你描述一支小团队(一个协调者加若干各有章程的专家),协调者派活、让专家们讨论、最后交付结果。

两者组合的价值在于分工:MAF 提供智能体运行时、模型抽象、托管和遥测,Copilot CLI/SDK 提供一个已经会读仓库、改文件、跑终端的编码智能体,Squad 则贡献团队式编排。刚发布的预览包 Squad.Agents.AI 把这条缝补上了:一个 NuGet 包,一行 DI 注册,Squad 团队就成了 MAF 眼里的普通 AIAgent

这篇文章面向已经在用或打算用 MAF 的 .NET 开发者。读完你会知道:怎么把 Squad 团队接进 IServiceCollection、这个包内部做了什么、以及「会学习的团队」和普通无状态智能体到底差在哪里。

官方支持:Copilot SDK 作为智能体后端

MAF 对 GitHub Copilot 的支持已经正式发布——C# 和 Python 的集成都在 v1.0 稳定版中(C# 包 Microsoft.Agents.AI.GitHub.Copilot 目前已是 1.x 系列)。最简单的用法是把 CopilotClient 通过扩展方法 AsAIAgent() 提升为 MAF 智能体,再挂上工具和指令:

using GitHub.Copilot;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

AIFunction weatherTool = AIFunctionFactory.Create((string location) =>
{
    return $"The weather in {location} is sunny with a high of 25C.";
}, "GetWeather", "Get the weather for a given location.");

await using CopilotClient copilotClient = new();
await copilotClient.StartAsync();

AIAgent agent = copilotClient.AsAIAgent(
    tools: [weatherTool],
    instructions: "You are a helpful weather agent.");

Console.WriteLine(await agent.RunAsync("What's the weather like in Seattle?"));

这样创建的智能体背后是真实的 Copilot CLI 进程,具备编码场景需要的完整工具集。官方文档在 MS Learn | Agent Framework | GitHub Copilot Agents,.NET 和 Python 的示例分别在 agent-framework 仓库 的对应目录下。

Squad:住在仓库里的智能体团队

Squad 的设计和「一个提示词扮演多个角色」的聊天机器人不同:每个团队成员以文件形式住在你的仓库里,拥有自己的上下文,只读自己该读的知识,并把学到的东西写回去。团队状态因此跨会话持久——这是后面所有能力的根基。

初始化一个团队只需三条命令:

npm install -g @bradygaster/squad-cli
squad init        # 生成 .squad/team.md 等团队文件
copilot --agent squad --yolo

squad init 会在项目里创建 .squad/ 目录,里面是团队章程、成员和路由规则;--yolo 用于免去逐次批准工具调用。注意 Squad 目前仍是 Alpha 项目,API 和 CLI 命令可能变化。

一行 DI 注册:把团队变成 AIAgent

Squad.Agents.AI 是连接 Squad 与 MAF 的预览 NuGet 包(当前最新为 0.5.x 预览版,支持 net8.0/net9.0/net10.0):

dotnet add package Squad.Agents.AI --prerelease

接入的完整代码只有这几行:

using Microsoft.Agents.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Squad.Agents.AI;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSquadAgent(o =>
{
    o.SquadFolderPath = @"C:\path\to\your\team-root";
});

using var host = builder.Build();
var squad = host.Services.GetRequiredService<AIAgent>();
var session = await squad.CreateSessionAsync();
var response = await squad.RunAsync("What can this Squad team do?", session);
Console.WriteLine(response.Text);

AddSquadAgent() 会把你的 Squad 团队同时注册成两个类型:AIAgent(MAF 通过标准抽象使用它)和 SquadAgent(需要 Squad 专属配置的调用方可以降级使用)。

原理:DelegatingAIAgent 包一层

SquadAgent 本身是一个极薄的组合类:Copilot SDK 已经知道怎么和 copilot.exe 通信,Squad.Agents.AI 只是把它指向 Squad 团队目录、建立会话,再把结果作为普通 AIAgent 交给 MAF。核心结构如下:

public sealed class SquadAgent : DelegatingAIAgent
{
    public SquadAgent(SquadAgentOptions options)
        : base(BuildInnerAgent(options))   // 内部 AIAgent 传给基类
    {
    }

    // DelegatingAIAgent 会把 RunAsync、RunStreamingAsync、CreateSessionAsync
    // 全部转发给内部 agent,SquadAgent 本身不需要覆写任何方法。

    private static AIAgent BuildInnerAgent(SquadAgentOptions options)
    {
        // 1. Copilot SDK 客户端,指向 Squad 团队根目录
        var client = new CopilotClient(/* CLI path, env, token, etc. */);

        // 2. 会话启动时让 CLI 自动发现 .squad/ 文件夹,
        //    加载团队 agent、技能、指令和 MCP 服务器
        var teamRoot       = options.SquadFolderPath;
        var squadConfigDir = Path.Combine(teamRoot, ".squad");

        var sessionConfig = new SessionConfig
        {
            WorkingDirectory      = teamRoot,
            ConfigDirectory       = squadConfigDir,
            EnableConfigDiscovery = true,
            OnPermissionRequest   = PermissionHandler.ApproveAll,
        };

        // 3. 把 Copilot 客户端提升为 MAF AIAgent
        return client.AsAIAgent(sessionConfig, name: options.AgentName ?? "Squad");
    }
}

整个类没有协议转换、没有额外运行时,就是继承加委托。真正干活的三行是:构造 CopilotClient、配置指向团队 .squad/ 目录的 SessionConfig、调用 AsAIAgent()。其中 EnableConfigDiscovery 是关键:它让 CLI 在会话开始时自动加载团队的章程、技能和 MCP 服务器,而不是让智能体每轮都用文件工具重新读一遍。

流式输出走同一套接口,await foreach (var update in squad.RunStreamingAsync(prompt, session)) 即可逐块消费响应。完整源码在 SquadAgent.cs

为什么值得:无状态智能体和自学习团队

MAF 的 workflow 可以把确定性步骤、无状态 AI 调用和精心提示词的专用智能体组合起来,但每次调用它们都从零开始——它们只知道提示词告诉它们的。Squad 不一样,它是一个自学习团队,使用越久积累的领域知识越多:

这改变了 Squad 在 MAF 管线里的意义。四个典型的落地场景:

换句话说,MAF 管线里的 Squad 槽位不是「调用一个 LLM」,而是「调用一支已经学习你的项目六周的团队」。主机只看到一个 AIAgent,底层是带着机构记忆在调度的协调者和专家。针对性智能体给你可重复性,Squad 给你随时间变好的可重复性

进阶:多团队、BYOK 与可观测性

预览包还提供了几个值得注意的能力:

多团队注册。 .NET 8+ 键控 DI 支持在同一个容器里注册多支团队,例如 AddKeyedSquadAgent("research", ...)AddKeyedSquadAgent("platform", ...),通过 [FromKeyedServices("research")] 在端点里解析。

BYOK 令牌。 ConfigureCopilotClient 委托可以在 Squad 设置完标准值后定制底层的 CopilotClientOptions,比如从自己的凭据库注入 GitHub token 或自定义环境变量:

builder.Services.AddSquadAgent(o =>
{
    o.SquadFolderPath = @"C:\team";
    o.ConfigureCopilotClient = clientOpts =>
    {
        clientOpts.GitHubToken = myVault.GetSecret("copilot-token");
    };
});

子智能体可观测性。 包默认对每次专家分发发射一个 OpenTelemetry span(squad.subagent {Name},活 span 上带生命周期事件)。已经接入 Aspire、Jaeger 或 Application Insights 的主机无需额外管道就能看到完整的多智能体扇出:谁被问了、说了什么、花了多久,都和请求的其他部分在同一个 trace 里。关闭方式是把 EmitSubagentActivities 设为 false,改用 OnSubagentTrace 回调自行处理。

安全方面也做了默认处理:token 和密钥在 ToString() 输出中脱敏、不进 JSON 序列化,ConfigureCopilotClient 委托无法改动 Cwd/CliPath/CliArgs(防止把智能体路由到别的 CLI 进程)。另外包默认给 copilot.exe--agent squad,让它加载 .github/agents/squad.agent.md 作为团队协调者的 agent 定义;文件不存在时静默跳过,不影响未初始化团队的降级使用。

前置条件与常见问题

接入前确认:

常见问题按优先级排查:会话中大量工具调用被逐个询问批准——用 --yolo 或在 SessionConfig.OnPermissionRequest 里配置 PermissionHandler.ApproveAllsquad.agent.md 不存在导致协调者不真正扇出——检查 .github/agents/ 目录;团队目录路径写错——SquadFolderPath 必须是 squad init 初始化过的根目录,且包不会替你校验路径存在。

如果你的项目已经基于 MAF,想要一个随使用越变越懂你领域、又不用反复改写提示词的多智能体编排,Squad.Agents.AI 是目前最便宜的上车路径:框架的工作 MAF 团队做了,团队的工作 Squad 做了,中间的缝只有一次 DI 调用。包仍在预览阶段,API 可能变化,生产使用前建议盯一下仓库的变更记录。

如果你关注 AI 助手、开发工具和软件工程实践,可以关注 Aide Hub。这里会继续分享能落地的工具教程、技术观察和项目经验。

参考


Tags


Previous

拆不拆微服务?先回答这 5 个问题

Next

什么时候该用微服务?一份务实的架构决策指南