AutoGen .NET Hello 示例深度解析:用 .NET Aspire App Host 编排跨语言 gRPC 多智能体应用
本篇以 dotnet/samples/Hello/README.md 为切入点,讲解 AutoGen 仓库中 "Hello" 示例的 .NET Aspire App Host 是如何一次性拉起 HelloAgent、智能体后端(AgentHost)与一个 Python 智能体,形成跨语言(C#/Python)的事件驱动消息链路,并如何在 Aspire Dashboard 中查看遥测与日志。读完后你可以直接在本地运行该多项目示例、理解 AGENT_HOST、STAY_ALIVE_ON_GOODBYE 等关键环境变量的作用,并掌握从 proto 定义消息类型到进程内/gRPC 两种运行时切换的完整方法。
1. 这个示例在 AutoGen .NET 中的定位
dotnet/samples/Hello 目录是 AutoGen 0.4 .NET SDK 的 "Hello World" 级示例集合,其核心文档 dotnet/samples/Hello/README.md 说明:这是一个基于 .NET Aspire 的 App Host,负责启动 HelloAgent 工程与 agents backend(智能体后端),项目启动后可通过控制台输出的链接在 Aspire Dashboard 中查看遥测数据与日志,运行方式只有两条命令:
cd Hello.AppHost
dotnet run
整个目录的组织如下,每个子工程各司其职:
| 目录 | 角色 | 关键文件 |
|---|---|---|
Hello.AppHost |
.NET Aspire 编排入口(App Host) | Program.cs、Hello.AppHost.csproj |
HelloAgent |
C# 智能体:订阅 HelloTopic,处理消息并回话 |
HelloAgent.cs、Program.cs |
HelloAIAgents |
带 LLM 的扩展变体(继承 HelloAgent,调用 ChatClient) | HelloAIAgent.cs |
HelloAgentState |
演示智能体状态持久化的变体 | README.md |
protos |
共享的事件消息 schema(ProtoBuf) | agent_events.proto |
运行前置条件(参考 HelloAgent 的 README):.NET 8.0 或更高版本;由于 App Host 还会拉起一个 Python 智能体,本地还需为 Python 端准备好虚拟环境(见第 4 节)。
2. App Host 如何编排三个进程
Hello.AppHost/Program.cs 是理解本示例的关键。它通过 DistributedApplication.CreateBuilder 声明了一个分布式应用的资源拓扑(第 6~27 行):
var builder = DistributedApplication.CreateBuilder(args);
var backend = builder.AddProject<Projects.Microsoft_AutoGen_AgentHost>("backend").WithExternalHttpEndpoints();
var client = builder.AddProject<Projects.HelloAgent>("HelloAgentsDotNET")
.WithReference(backend)
.WithEnvironment("AGENT_HOST", backend.GetEndpoint("https"))
.WithEnvironment("STAY_ALIVE_ON_GOODBYE", "true")
.WaitFor(backend);
// xlang is over http for now - in prod use TLS between containers
builder.AddPythonApp("HelloAgentsPython", "../../../../python/samples/core_xlang_hello_python_agent", "hello_python_agent.py", "../../.venv")
.WithReference(backend)
.WithEnvironment("AGENT_HOST", backend.GetEndpoint("http"))
.WithEnvironment("STAY_ALIVE_ON_GOODBYE", "true")
.WithEnvironment("GRPC_DNS_RESOLVER", "native")
.WithOtlpExporter()
.WaitFor(client);
using var app = builder.Build();
await app.StartAsync();
var url = backend.GetEndpoint("http").Url;
Console.WriteLine("Backend URL: " + url);
await app.WaitForShutdownAsync();
从这段编排代码可以确认三个事实:
- backend 是分布式消息网关。
AddProject<Projects.Microsoft_AutoGen_AgentHost>("backend")引用的工程是 dotnet/src/Microsoft.AutoGen/AgentHost,即仓库中的 gRPC 智能体后端;WithExternalHttpEndpoints()让它对外暴露 HTTP(S) 端点,供其余进程连接。 - HelloAgent 以 gRPC 客户端身份接入 backend。
WithReference(backend)注入连接信息,AGENT_HOST环境变量被显式设置为 backend 的 https 端点。HelloAgent 的入口程序会依据AGENT_HOST决定使用 gRPC 运行时还是进程内运行时(见第 3 节),因此这里它走的是分布式路径。 - Python 智能体跨语言加入同一事件总线。
AddPythonApp的工作目录指向 python/samples/core_xlang_hello_python_agent,入口脚本为hello_python_agent.py;第 4 个参数../../.venv从该工作目录相对解析后,指向 python 包根目录下的.venv虚拟环境——可以推断需要在 python 目录下预先创建装好本地包的虚拟环境。Python 端通过GrpcWorkerAgentRuntime连接同一个 backend,从而实现 C# 与 Python 智能体在同一 topic 上收发消息。源码中的注释也提示:xlang 目前走 http,生产环境容器间应使用 TLS。
2.1 关键环境变量一览
| 环境变量 | 设置位置 | 作用 |
|---|---|---|
AGENT_HOST |
App Host 通过 WithEnvironment 注入 |
智能体据此连接 gRPC 后端(C# 端取自 HelloAgent/Program.cs;Python 端在 hello_python_agent.py 中默认回退到 http://localhost:50673) |
STAY_ALIVE_ON_GOODBYE |
App Host 对两个智能体均设为 true |
控制 HelloAgent 在发出 ConversationClosed 后是否自行关停:见 HelloAgent.cs,若该变量不为 true,则会再发布 Shutdown 消息并停止应用。在 Aspire 托管场景下保持 true,进程不因一次对话结束而退出 |
GRPC_DNS_RESOLVER |
仅 Python 端设为 native |
指定 gRPC 使用原生 DNS 解析器,配合容器化环境下的主机名解析 |
2.2 启动顺序与依赖等待
WaitFor 声明了显式依赖链:backend 先就绪 → HelloAgent 启动 → Python 智能体最后启动(backend.WaitFor → client → HelloAgentsPython)。启动完成后 App Host 会打印 Backend URL 并等待关闭信号,此时控制台同时提供 Aspire Dashboard 的访问链接。
Hello.AppHost.csproj 声明了编排所需的基础设施:使用 Aspire.AppHost.Sdk(9.0.0),目标框架 net8.0,标记 IsAspireHost 为 true,并引用 Aspire.Hosting.AppHost、Aspire.Hosting、Aspire.Hosting.Python(Python 应用支持)三个包;项目引用则精确指向 AgentHost 后端与 HelloAgent 两个工程。
3. HelloAgent 的消息处理流程
理解 App Host 编排后,再看被编排的 HelloAgent 本身。其消息类型定义在 protos/agent_events.proto(package HelloAgents,C# 命名空间为 Microsoft.AutoGen.Contracts),其中示例用到的三个消息为:
message NewMessageReceived {
string message = 1;
}
message ConversationClosed {
string user_id = 1;
string user_message = 2;
}
message Shutdown {
string message = 1;
}
HelloAgent/HelloAgent.cs 展示了一个最小智能体的完整形态:通过 [TypeSubscription("HelloTopic")] 订阅 topic HelloTopic,并通过实现 IHandle<NewMessageReceived>、IHandle<ConversationClosed>、IHandle<Shutdown> 三个接口声明它能处理哪些消息:
public async ValueTask HandleAsync(NewMessageReceived item, MessageContext messageContext)
{
Console.Out.WriteLine(item.Message);
ConversationClosed goodbye = new ConversationClosed
{
UserId = this.Id.Type,
UserMessage = "Goodbye"
};
// This will publish the new message type which will be handled by the ConversationClosed handler
await this.PublishMessageAsync(goodbye, new TopicId("HelloTopic"));
}
处理链是典型的事件链式编排:收到 NewMessageReceived → 打印消息并发布 ConversationClosed → ConversationClosed 处理器打印告别语,并在 STAY_ALIVE_ON_GOODBYE 不为 true 时发布 Shutdown → Shutdown 处理器调用 hostApplicationLifetime.StopApplication() 结束进程。
HelloAgent/Program.cs 则展示了同一工程支持两种运行模式,这正是 README 中 "使用 SDK 的 App Runtime 在本地启动智能体" 的落地方式:
- 进程内模式(默认):没有
AGENT_HOST时,appBuilder.UseInProcessRuntime(deliverToSelf: true).AddAgent<HelloAgent>("HelloAgent"),随后直接app.PublishMessageAsync(message, new TopicId("HelloTopic"))发送NewMessageReceived { Message = "Hello World!" }给自己。 - gRPC 分布式模式:设置了
--host <address>命令行参数或AGENT_HOST环境变量时,改用appBuilder.AddGrpcAgentWorker(agentHost)连接到网关(Aspire 场景即此模式)。
命令行参数语义(来自 Program.cs 的参数解析与帮助文本):
HelloAgent [--host <hostAddress>] [--nosend]
--host 使用 <hostAddress> 处的 gRPC 网关;也可通过 AGENT_HOST 环境变量设置
--nosend 不发送初始消息,等待其他智能体发送。注意:在 InProcessRuntime 下该参数无效(会挂起),程序会直接退出
在 Aspire 编排中,Python 智能体(WaitFor(client) 之后启动)会向 HelloTopic 发布 NewMessageReceived { message = "Hello from Python!" },HelloAgent 打印后回发 ConversationClosed,整条 C# ↔ Python 链路即由此贯通。
4. 在 Aspire Dashboard 中查看遥测与日志
README 的核心承诺是:启动后在控制台给出的链接进入 Aspire Dashboard,即可查看各进程的遥测与日志。相关配置位于 launchSettings.json,包含三个配置文件(profile):
| Profile | 应用地址 | 关键点 |
|---|---|---|
https(默认) |
https://localhost:15887;http://localhost:15888 |
DOTNET_DASHBOARD_OTLP_HTTP_ENDPOINT_URL=https://localhost:16038、DOTNET_RESOURCE_SERVICE_ENDPOINT_URL=https://localhost:17037,并开启 DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES=true |
http |
http://localhost:15888 |
对应 Dashboard 端口 16032 / 17031,额外设置 ASPIRE_ALLOW_UNSECURED_TRANSPORT=true |
generate-manifest |
不启动应用 | 以 --publisher manifest --output-path aspire-manifest.json 生成部署清单,用于容器化等场景 |
在 Dashboard 中可以看到 backend、HelloAgentsDotNET、HelloAgentsPython 三个资源的日志流与跟踪数据;Python 端因配置了 .WithOtlpExporter(),其 OpenTelemetry 导出同样汇入 Dashboard。此外 appsettings.json 将日志级别默认设为 Warning、Microsoft 命名空间为 Information,用于控制各进程日志输出粒度。
5. 消息类型的扩展方式
示例展示了消息类型由 ProtoBuf schema 驱动的模式:.proto 文件在构建时由 gRPC 工具转为 C# 类。HelloAgent.csproj 的做法是引用 Google.Protobuf 与 Grpc.Tools 包,并用 <Protobuf Include="..\..\..\src\Microsoft.AutoGen\Agents\protos\agent_events.proto" /> 纳入 proto 文件;AgentHost 相关工程与测试 中同样维护了 agent_events.proto。若要新增自定义消息,可按 HelloAgent README 的说明:新建 .proto 文件并在 .csproj 中加入 Grpc.Tools 与 <Protobuf Include="..."/>,然后像示例中 PublishMessageAsync 那样把消息包装后投递到事件总线即可。
6. 同目录的变体工程
- HelloAIAgents:HelloAIAgent.cs 继承自本地定义的
HelloAgent基类([TopicSubscription("agents")]),用new重写Handle(NewMessageReceived),通过注入的IChatClient调用大模型写一首 limerick 问候诗并回发Output。其 Program.cs 从配置读取HelloAIAgents:ModelType(azureopenai)与HelloAIAgents:LlmModelName,要求设置AZURE_OPENAI_CONNECTION_STRING环境变量;未设置时直接抛出InvalidOperationException。注意:该工程未被 Hello.AppHost 的 csproj 引用,属于独立运行的变体示例,不参与 Aspire 编排。 - HelloAgentState:演示智能体状态持久化 API 的变体,可查阅其 README 了解用法。
7. 关键文件索引
| 内容 | 路径 |
|---|---|
| 本示例总览文档(本文依据) | dotnet/samples/Hello/README.md |
| App Host 编排逻辑 | dotnet/samples/Hello/Hello.AppHost/Program.cs |
| Aspire 启动配置 | dotnet/samples/Hello/Hello.AppHost/Properties/launchSettings.json |
| C# 智能体与消息处理器 | dotnet/samples/Hello/HelloAgent/HelloAgent.cs |
| 进程内/gRPC 双模式启动 | dotnet/samples/Hello/HelloAgent/Program.cs |
| 事件消息 schema | dotnet/samples/Hello/protos/agent_events.proto |
| Python 侧跨语言智能体 | python/samples/core_xlang_hello_python_agent/hello_python_agent.py |
| gRPC 后端工程 | dotnet/src/Microsoft.AutoGen/AgentHost |
综上,dotnet/samples/Hello 用一个最小闭环完整呈现了 AutoGen .NET 的分布式智能体模型:Aspire App Host 负责进程编排与依赖管理,智能体通过 TypeSubscription 订阅 topic、通过 IHandle<T> 注册消息处理器、通过 ProtoBuf 定义跨语言消息契约,最终 C# 与 Python 智能体经由 AgentHost 网关在同一事件总线上协作,全部运行状态可经 Aspire Dashboard 观测。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00