首页
/ AutoGen 0.4 .NET HelloAgent 入门:从事件订阅、gRPC 消息契约到跨语言运行时编排

AutoGen 0.4 .NET HelloAgent 入门:从事件订阅、gRPC 消息契约到跨语言运行时编排

2026-09-05 15:37:38作者:尤峻淳Whitney

本文基于 AutoGen 仓库中 Microsoft.AutoGen.Integration.Tests.AppHosts/HelloAgentTests 目录的官方示例文档,系统讲解 AutoGen 0.4 .NET 编程模型的最小完整闭环:如何定义一个订阅主题的 Agent、编写事件处理程序、启动进程内或 gRPC 分布式运行时、发布 protobuf 消息,并通过 Aspire AppHost 将 .NET Agent 与 Python Agent 编排在同一事件总线中进行跨语言(xLang)通信验证。读完本文,你可以复刻仓库中的 Hello World 示例,并理解每个关键类、注解和命令参数在源码中的真实落点。

一、示例定位与前置条件

dotnet/test/Microsoft.AutoGen.Integration.Tests.AppHosts/HelloAgentTests/ 目录下的文档 README 将其描述为:“一个演示如何创建简单的 .NET 控制台应用,监听事件并对事件进行一系列动作编排的示例”。它同时承担两个角色:

  • 教学示例:演示 AutoGen 0.4 自定义 Agent 的最小可用形态(继承基类 Agent、订阅事件、发布消息、等待关闭);
  • 集成测试资源:它是 Aspire 分布式应用 XlangTests.AppHost 中的一个可部署资源,被 HelloAppHostIntegrationTests.cs 用来验证 .NET 与 Python Agent 之间的消息投递。

前置条件(原文档明确列出):

  • .NET 8.0 或更高版本;
  • 推荐安装 GitHub CLI 用于克隆仓库。

项目文件 HelloAgentTests.csproj 印证了这些依赖:<TargetFramework>net8.0</TargetFramework>,并引用 Microsoft.Extensions.HostingGoogle.ProtobufGrpc.ToolsPrivateAssets="All",仅用于构建期生成代码),以及四个源码工程的 ProjectReference

<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Contracts\Microsoft.AutoGen.Contracts.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Agents\Microsoft.AutoGen.Agents.csproj" />
<ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />

这四个工程分别对应消息契约(Contracts)、运行时核心(Core)、Agent 抽象(Agents)与 gRPC 网关客户端(Core.Grpc),是理解本文所有 API 的来源。

二、运行示例

原文档给出的运行方式:

# Clone the repository
gh repo clone microsoft/autogen
cd dotnet/samples/Hello
dotnet run

需要注意仓库中存在两处形态几乎一致的 Hello 示例,可按需选择:

  1. 测试资源版dotnet/test/Microsoft.AutoGen.Integration.Tests.AppHosts/HelloAgentTests,其 Program.cs 在构建时自动判断运行模式;
  2. 示例集版dotnet/samples/Hello,包含 HelloAgentHelloAIAgentsHelloAgentStateHello.AppHost 等子项目,其中 HelloAgent/Program.cs 额外提供了命令行参数:
    • --host <hostAddress>:连接指定地址的 gRPC 网关(也可通过环境变量 AGENT_HOST 设置);
    • --nosend:不发送初始消息,等待其他 Agent 触发(文档明确提示:使用进程内运行时该参数会导致挂起,程序会直接终止并提示)。

配置层面,appsettings.json 将日志级别设为 Warning 起步,并为 GrpcMicrosoft.Hosting.Lifetime 等命名空间单独开放 Information 级别,同时声明 Kestrel 端点默认使用 Http2 协议——这是 gRPC over HTTP/2 的前提。

三、核心概念:事件驱动的 Agent 流程

原文档给出的事件流图(Mermaid)完整描述了一次对话的生命周期:

%%{init: {'theme':'forest'}}%%
graph LR;
    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item, CancellationToken cancellationToken = default)"}
    B --> |"PublishEventAsync(Output('***Hello, World***'))"| C[ConsoleAgent]
    C --> D{"WriteConsole()"}
    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item, CancellationToken cancellationToken = default)"}
    B --> |"PublishEventAsync(Output('***Goodbye***'))"| C
    E --> F{"Shutdown()"}

结合 HelloAgent.cs 的当前实现,这条链路的实际执行过程是:

  1. 主程序向主题 HelloTopic 发布 NewMessageReceived { Message = "Hello World!" }
  2. HelloAgentHandleAsync(NewMessageReceived, ...) 打印消息,并继续向同一主题发布 ConversationClosedUserMessage = "Goodbye");
  3. HandleAsync(ConversationClosed, ...) 打印告别语,若环境变量 STAY_ALIVE_ON_GOODBYE 不为 true,则发布 Shutdown
  4. HandleAsync(Shutdown, ...) 调用 hostApplicationLifetime.StopApplication() 终止宿主,Program.cs 中的 WaitForShutdownAsync() 返回,进程退出。

STAY_ALIVE_ON_GOODBYE 是跨语言编排场景的关键开关:在 Aspire 测试中由 XLangTests.AppHost/Program.cs 统一注入为 true,保证 .NET/Python 两个 Agent 在收发完一轮消息后继续保持存活,等待测试框架采集日志。

四、编写事件处理程序:TypeSubscription 与 IHandle

原文档指出:“AutoGen 应用的核心是事件处理程序。Agent 通过 TopicSubscription 选择要监听的主题,收到事件时其事件处理程序被调用;处理程序内部可以可选地发布新事件,交由事件总线分发给其他 Agent。事件类型是声明为 gRPC ProtoBuf 消息的 schema,通过 IHandle 接口在 Agent 中注册。”

对照当前源码 HelloAgent.cs,一个完整的 Agent 定义如下:

[TypeSubscription("HelloTopic")]
public class HelloAgent(
    IHostApplicationLifetime hostApplicationLifetime,
    AgentId id,
    IAgentRuntime runtime,
    Logger<BaseAgent>? logger = null) : BaseAgent(id, runtime, "Hello Agent", logger),
        IHandle<NewMessageReceived>,
        IHandle<ConversationClosed>,
        IHandle<Shutdown>, IHandleConsole
{
    // This will capture the message sent in Program.cs
    public async ValueTask HandleAsync(NewMessageReceived item, MessageContext messageContext)
    {
        Console.Out.WriteLine(item.Message); // Print message to console
        ConversationClosed goodbye = new ConversationClosed
        {
            UserId = this.Id.Type,
            UserMessage = "Goodbye"
        };
        await this.PublishMessageAsync(goodbye, new TopicId("HelloTopic"));
    }
    // ... ConversationClosed / Shutdown 处理程序同理
}

关键点逐一拆解:

  • [TypeSubscription("HelloTopic")](第 12 行):声明该 Agent 订阅的主题标识。运行时据此把总线上该主题的消息路由到本 Agent;
  • 继承 BaseAgentMicrosoft.AutoGen.Agents 命名空间下的 Agent 基类,构造参数为 AgentIdIAgentRuntime(消息发布/订阅的运行时抽象)、描述与可选 Logger;
  • 实现 IHandle<T>:每个 IHandle<T> 接口对应一个 HandleAsync(T item, MessageContext messageContext) 方法,即处理程序契约。本例订阅了 NewMessageReceivedConversationClosedShutdown 三种内置消息类型;
  • IHandleConsole:提供控制台输出能力,是“继承与组合”思想的一部分(见下一节);
  • PublishMessageAsync:在处理程序中继续向 TopicId 发布新消息,形成链式编排。

说明:原文档示例片段(ConsoleAgentPublishEventAsyncToCloudEventISayHello 等)反映的是该文档编写时的 API 形态;当前源码树中对应能力已由 BaseAgent + IHandle<T> + PublishMessageAsync 承载,且文档中提到的 dotnet/src/Microsoft.AutoGen/Agents/AgentWorker.cs 在当前工程中已不存在,等价职责由 Microsoft.AutoGen.Agents 工程(csproj 中可见)中的 BaseAgent 与运行时组件承担。阅读文档时应以 HelloAgent.csProgram.cs 的当前实现为准。

五、继承与组合

原文档专节强调:“本示例也展示了 AutoGen 中的继承。HelloAgent 继承自提供 WriteConsole 方法的基类。”

在当前源码结构中可以印证这一设计:Agent 的通用能力被拆分为基类 + 接口两层——

  • 基类 BaseAgent 提供身份(Id)、运行时句柄(PublishMessageAsync)与生命周期;
  • 行为接口(IHandle<T>IHandleConsole)按需组合。dotnet/samples/Hello/HelloAgent/HelloAgent.cs 的变体只实现三个 IHandle,而测试资源版额外加了 IHandleConsole,两者共享同一套处理逻辑,说明能力扩展走“组合接口”而非“加深继承链”的路线;
  • 更丰富的组合示例见 HelloAgentStateHelloAIAgents(后者演示了接入 LLM 的 AI Agent 变体,同一事件流可驱动不同能力组合的 Agent)。

六、启动 Application Runtime:进程内与 gRPC 双模式

原文档说明:“AutoGen 提供灵活的运行时,可以以多种方式启动。Program.cs 演示了如何本地启动运行时并一次性向 Agent 发送消息。”

当前 Program.cs 的完整逻辑仅 20 余行,是理解双模式切换的最佳入口:

var appBuilder = new AgentsAppBuilder(); // Create app builder
// if we are using distributed, we need the AGENT_HOST var defined and then we will use the grpc runtime
if (Environment.GetEnvironmentVariable("AGENT_HOST") != null)
{
    appBuilder.AddGrpcAgentWorker(
        Environment.GetEnvironmentVariable("AGENT_HOST"))
        .AddAgent<HelloAgent>("HelloAgent");
}
else
{
    // Set up app builder for in-process runtime, allow message delivery to self, and add the Hello agent
    appBuilder.UseInProcessRuntime(deliverToSelf: true).AddAgent<HelloAgent>("HelloAgent");
}
var app = await appBuilder.BuildAsync(); // Build the app
// Create a custom message type from proto and define message
var message = new NewMessageReceived { Message = "Hello World!" };
await app.PublishMessageAsync(message, new TopicId("HelloTopic", "HelloAgents/dotnet")).ConfigureAwait(false);
await app.WaitForShutdownAsync().ConfigureAwait(false); // Wait for shutdown from agent

三个要点:

  1. 构建器模式AgentsAppBuilder 负责装配运行时(UseInProcessRuntimeAddGrpcAgentWorker)与 Agent 注册(AddAgent<T>("HelloAgent")),BuildAsync() 后得到一个可 StartAsync/WaitForShutdownAsync 的应用对象;
  2. 单命令双模式:未设置 AGENT_HOST 时走进程内运行时(deliverToSelf: true 允许 Agent 接收自己发布的消息,这正是 Hello → Goodbye → Shutdown 自驱动闭环成立的必要条件);设置了 AGENT_HOST 时,Agent 通过 gRPC 连接到外部 AgentHost 网关,成为分布式拓扑中的一员;
  3. 消息源标识:本例发布消息时使用的 TopicId("HelloTopic", "HelloAgents/dotnet")——主题键之外还带有 source 后缀,这正是跨语言测试断言 "source": "HelloAgents/dotnet" 的来源(见 HelloAppHostIntegrationTests.cs)。

原文档中给出的 App.PublishMessageAsync("HelloAgents", ..., local: true) 一站式写法属于文档时期的静态入口形态,其语义(本地启动运行时 + 首发一条消息)与上面的构建器写法一一对应。

七、定义与发送消息:protobuf 契约与 CloudEvents

原文档“Sending Messages”一节的要点:消息集合由 gRPC ProtoBuf 规范定义,经 gRPC 工具生成 C# 类;用户可通过新增 .proto 文件并在 .csproj 中引入工具来定义自己的消息类型。

原文档自带的自定义消息示例(来自 DevTeam 场景):

syntax = "proto3";
package devteam;
option csharp_namespace = "DevTeam.Shared";
message NewAsk {
  string org = 1;
  string repo = 2;
  string ask = 3;
  int64 issue_number = 4;
}
message ReadmeRequested {
   string org = 1;
   string repo = 2;
   int64 issue_number = 3;
   string ask = 4;
}

对应的工程配置(原文档给出,且与 HelloAgentTests.csproj 中实际使用的包引用一致):

<ItemGroup>
  <PackageReference Include="Google.Protobuf" />
  <PackageReference Include="Grpc.Tools" PrivateAssets="All" />
  <Protobuf Include="..\Protos\messages.proto" Link="Protos\messages.proto" />
</ItemGroup>

仓库中可直接查看到的真实契约文件:

原文档同时指出:消息以 CloudEvents 规范 封装后发送到事件总线。跨语言测试 HelloAppHostIntegrationTests.cs 中的断言字符串 "INFO:autogen_core:Received a message from host: cloudEvent {" 直接证明了 Python 侧收到的正是 CloudEvents 封装的消息体。

八、作为集成测试资源:xLang 跨语言编排验证

HelloAgentTests 放在 Microsoft.AutoGen.Integration.Tests.AppHosts 下并非偶然。XLangTests.AppHost/Program.cs 用 Aspire 将其编排进一个分布式应用:

var builder = DistributedApplication.CreateBuilder(args);
var backend = builder.AddProject<Projects.Microsoft_AutoGen_AgentHost>("AgentHost").WithExternalHttpEndpoints();
// ...
dotnet = builder.AddProject<Projects.HelloAgentTests>("HelloAgentTestsDotNET")
    .WithReference(backend)
    .WithEnvironment("AGENT_HOST", backend.GetEndpoint("https"))
    .WithEnvironment("STAY_ALIVE_ON_GOODBYE", "true")
    .WaitFor(backend);
// Python 侧
python = builder.AddPythonApp("HelloAgentTestsPython", pythonHelloAgentPath, pythonHelloAgentPy, pythonVEnv)
    .WithReference(backend)
    .WithEnvironment("AGENT_HOST", backend.GetEndpoint("http"))
    .WithEnvironment("STAY_ALIVE_ON_GOODBYE", "true")
    // ...

拓扑为:AgentHost(运行时网关)为中枢,.NET HelloAgent 走 HTTPS gRPC 接入,Python hello_python_agent.py(见 core_xlang_hello_python_agent)走 HTTP 接入,三者经同一事件总线互通。XLANG_TEST_NO_DOTNET / XLANG_TEST_NO_PYTHON 环境变量用于在测试中裁剪单边资源。

HelloAppHostIntegrationTests.cs 中的用例逐一验证了消息路由,例如:

  • Test_Dotnet_Sends_AgentHost_Delivers_and_Python_Receives:等待 Python 资源日志中出现 "Hello World!",证明 .NET → 网关 → Python 的投递;
  • Test_Dotnet_Agent_Sends_And_AgentHost_Delivers_Back_To_It:断言 .NET 资源日志中先出现 "Hello World!" 后出现 "HelloAgent said Goodbye"——后者正是第四节中 ConversationClosed 处理程序的打印格式 $"{item.UserId} said {item.UserMessage}",把示例行为与测试断言严丝合缝地对应起来;
  • Test_Python_Agent_Sends_And_AgentHost_Receives:断言网关日志中出现 "source": "HelloAgents/python",与 .NET 侧的 "HelloAgents/dotnet" 形成对称验证。

九、小结

这篇 Hello World 文档及其配套源码,浓缩了 AutoGen 0.4 .NET 编程模型的四个支柱:

概念 文档表述 源码落点
事件订阅 TopicSubscription 监听主题事件 HelloAgent.cs[TypeSubscription("HelloTopic")]
事件处理程序 通过 IHandle 注册,可继续发布事件 HandleAsync 三实现 + PublishMessageAsyncHelloAgent.cs
运行时启动 本地进程内或连接网关,一条消息触发全链路 Program.csAGENT_HOST 分支
消息契约 protobuf 定义 schema,CloudEvents 封装投递 agent_events.protocloudevent.proto

掌握这条“订阅—处理—发布—关闭”的最小闭环后,即可沿仓库继续深入:dotnet/samples/Hello/HelloAgentState 演示为 Agent 增加状态,dotnet/samples/Hello/HelloAIAgents 演示接入 LLM 的 AI Agent,而 Microsoft.AutoGen.Integration.Tests 则展示了同一套 Agent 代码如何零修改地成为分布式跨语言系统中的一个节点。

登录后查看全文
热门项目推荐
相关项目推荐