从 dotnet run 到 Foundry 托管代理:只需三行 C# 代码
几周前,我和几个正在用 Microsoft Agent Framework 构建代理的朋友聊天。演示很精彩,代理很聪明,大家都很开心。然后有人问了一个问题:“代理做好了……那这东西到底怎么部署?”桌上一下子安静了,因为以前诚实的答案是:要写 Dockerfile、配 Web 服务器、做身份验证、准备会话存储、设置扩缩容规则、接好遥测,还有一大堆杂事。基本上等于为了把代理从你的机器里搬到线上,还得再开发一个完整的配套项目。
不过现在有好消息:Foundry Hosted Agents 可以让这个控制台应用在 Azure 里拥有一个托管的家。你保留用 Agent Framework 写好的代理逻辑,把它作为一个容器化应用部署到微软托管的基础设施上。Foundry 会给它一个端点,并帮你处理计算资源、扩缩容、身份、会话状态、可观测性和生命周期管理。
所以,今天不用再自己搭建和维护那“第二个项目”了,答案就是:1 个 NuGet 包、3 行 C# 代码、2 条命令。下面我来演示。
你将构建什么
你会拿一个现有的 Agent Framework 控制台应用,然后:
- 把它注册到 Foundry Responses 协议
- 用
azd在本地运行和调用它 - 预置它的 Azure 资源
- 把它部署为 Foundry Hosted Agent
- 在 Foundry 门户中查看对话、追踪、版本和评估结果
起点:一个最小的 MAF 代理
下面这段代码大致就是你现在所处的阶段:一个用 Microsoft Agent Framework 构建、跑在控制台应用里的简单代理:
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("Set FOUNDRY_PROJECT_ENDPOINT environment variable");
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-5-mini";
AIAgent agent = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential())
.AsAIAgent(
model: deployment,
instructions: "You are a friendly assistant. Keep your answers brief.",
name: "HelloAgent");
Console.WriteLine(await agent.RunAsync("Hello! Tell me a fun fact about .NET.")); 就这样。不需要服务器,不需要协议,没有任何花哨的东西。你运行 dotnet run,代理就会回答,这就是完美的代理版 Hello World。(如果你还没走到这一步,先看看《你的第一个 C# 代理》,只需 5 分钟。)但这个代理只存在于你的终端里,别人无法与它对话。于是又回到了我朋友的问题:那我到底怎么部署它?
让 Foundry 托管代理(Hosted Agents)登场吧。托管代理是 Microsoft Foundry 代理服务中的托管层。平台会帮你处理这些事:
- 托管基础设施:无需配置容器,无需 Web 服务器,无需扩缩容规则。平台按会话分配计算资源,并在空闲时缩到零。
- 内置会话状态:
$HOME和上传的文件会在多轮对话和空闲期间保持不变。你的代理会记住东西,而你一行存储代码都不用写。 - 专属代理身份:每个部署的代理都会自动获得自己的 Microsoft Entra ID。对模型、工具和下游服务的安全访问,无需手动配置托管标识。
- 兼容 OpenAI 的端点:你的代理会获得一个
/responses端点,因此任何兼容 OpenAI 的 SDK(Python、JavaScript 或 C#)都可以直接与之对话。
没错,托管代理已经正式发布(GA)了!
Responses 还是 Invocations?
托管代理支持两种协议。Responses 兼容 OpenAI,让平台管理对话历史、流式传输和会话生命周期。Invocations 让你控制原始 HTTP 请求,适用于 Webhook 或自定义负载。如果你不确定,先从 Responses 开始;一个代理可以同时暴露两种协议。
现在让我们把控制台代理改造成托管就绪(hosted-ready)状态。改动只有:1 个包 + 3 行代码。
开始之前
你需要 .NET 10 SDK、Azure Developer CLI、Azure 订阅,以及创建资源和角色分配的权限。继续之前请先用 azd auth login 登录。
现有代理已经引用了 Azure.AI.Projects。要让它具备托管能力,只需添加一个新包:
dotnet add package Microsoft.Agents.AI.Foundry.Hosting --prerelease
关于预发布包
Foundry 托管代理已经正式发布。
在撰写本文时,此示例使用的 .NET 托管集成包仍是预发布版,因此命令中包含了 --prerelease。接下来是完整的托管就绪版本。我标出了新增的行,共有三行:using Azure.AI.AgentServer.Core;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;
var projectEndpoint = new Uri(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set."));
var deployment = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-5-mini";
AIAgent agent = new AIProjectClient(projectEndpoint, new DefaultAzureCredential())
.AsAIAgent(
model: deployment,
instructions: "You are a friendly assistant. Keep your answers brief.",
name: "HelloAgent");
var builder = AgentHost.CreateBuilder(args); // 👈 new line 1
builder.Services.AddFoundryResponses(agent); // 👈 new line 2
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses()); // 👈 new line 3
var app = builder.Build();
app.Run(); 每行代码的作用:
AgentHost.CreateBuilder(args) 会创建一个为 Foundry 托管环境预配置好的应用宿主。你可以把它想象成 WebApplication.CreateBuilder,但它已经内置了 Foundry 相关的一切:健康检查(health checks)、OpenTelemetry、会话上下文(session context)全都接好了。
AddFoundryResponses(agent) 把你的 agent 注册到 Responses 协议处理器上。你的 AIAgent 本身完全不用改,只需要插进去就行。
RegisterProtocol(...) 映射了 /responses HTTP 端点。
现在看看你省掉了什么:没有 Kestrel 配置,没有会话存储,没有流式传输管道,没有对话历史管理。同一个 AIAgent,现在已经在说生产级的协议了。
获取完整的 C# 托管 agent 示例
先在本地跑起来
在部署任何东西之前,先在本地测试一下。Azure Developer CLI(azd)有个 AI agent 扩展,可以让这一步变得非常简单:
azd ext install azure.ai.agents
搭建项目,让它以托管 agent 的形式部署:
azd ai agent init
设置环境变量。这里用的是 Bash 语法;如果你用 PowerShell,就改成 $env:FOUNDRY_PROJECT_ENDPOINT = "..." 和 $env:AZURE_AI_MODEL_DEPLOYMENT_NAME = "gpt-5-mini"。
export FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
export AZURE_AI_MODEL_DEPLOYMENT_NAME="gpt-5-mini"
然后运行 agent 宿主:
azd ai agent run
你的 agent 现在已经在 http://localhost:8088 上运行了。来跟它打个招呼吧:
注意:本地端点只用于测试。不要把端口 8088 暴露到公网,也不要把本地宿主当成生产环境的认证边界。
azd ai agent invoke --local "Hello!"
如果你习惯用 curl:
curl -X POST http://localhost:8088/responses \
-H "Content-Type: application/json" \
-d '{"input": "Hello!"}'
本地宿主在 8088 端口监听,azd ai agent invoke 通过 Responses 协议发送请求。本地跑通了?很好,准备上线。
部署:两条命令
以前这段我通常要折腾几个小时。现在全部就这些:
azd provision
azd deploy 是第二条部署命令。其实一共就这两条部署命令。让我解释一下实际发生的事:azd provision 会创建一个资源组,里面包含一个 Foundry 实例、一个项目、一个模型部署、Application Insights 和 Azure 容器注册表(ACR)。如果你已经有 Foundry 项目,可以跳过这一步。azd deploy 会将你的代理打包成容器镜像,推送到 ACR,然后部署到 Microsoft Foundry 代理服务。
Azure 资源和成本
本演练会预配一些计费 Azure 资源。如果你只是试验,结束后不再需要,就用 azd down 移除整个环境。确认删除前,请先检查一下资源列表。
部署完成后,你的代理会自动获得:
- 一个专用终结点:
{project_endpoint}/agents/{name}/endpoint/protocols/openai/responses - 一个用于运行时身份验证的 Microsoft Entra 专用代理身份
这些你都没有配置,它自己就存在了。
你的代理,在 Foundry 门户中如鱼得水
而这里就是“为什么用 Foundry”真正兑现承诺的地方。打开 Foundry 门户,你的代理已经带着一整套生产工具围绕着它等着你了。
在 Playground 里和它聊天。你的代理已经部署上线,完全不需要写客户端代码。Foundry Playground 让你无需构建独立客户端应用,就能直接测试已部署的代理。
追踪:开箱即用
平台会把 Application Insights 连接字符串注入你的容器,协议库默认就会发出 OpenTelemetry 追踪。每个请求、每个模型调用,都清清楚楚地出现在“事务搜索”里。你一行遥测代码都没写。
一次对话追踪会显示代理响应背后的请求、模型调用和子操作。
评估
Foundry 自带代理评估器,你可以衡量已部署代理的回复质量,而不是靠猜。
版本与会话
每次部署都会创建一个不可变的代理版本,回滚因此很简单。会话由平台管理:空闲 15 分钟后计算资源自动释放,状态被持久化,等会话恢复时一切又会自动还原。每个部署都会生成一个不可变的代理版本,你可以随时查看并用于回滚。
还有工具
托管 Agent 可以直接使用 Foundry Toolbox 里的能力:代码解释器(Code Interpreter)、网页搜索、Azure AI Search、MCP(模型上下文协议)、A2A(Agent 间通信协议)等等,全部通过一个统一的 MCP 端点接入,认证也一并搞定。我朋友原本打算手工搭建的那些东西,这里就已经齐了。
额外福利:VS Code 体验
如果你平时主要在 Visual Studio Code 里写代码(比如我),还有一条更快的路径。Microsoft Foundry Toolkit 扩展能把整个流程浓缩成命令面板里的三条命令:
- Foundry Toolkit: Create new Hosted Agent:一键生成完整的项目脚手架——代码、
agent.yaml,全都给你备好。按下 F5,Agent 就在本地启动并挂上调试器,同时打开 Agent Inspector,让你可以直接和它对话。没错,你可以一边和 Agent 聊天,一边在它的代码里打断点。 - Foundry Toolkit: Deploy Hosted Agent:打开一个部署向导,自动在 ACR 里构建容器镜像、注册 Agent 版本,并分配好所需的 RBAC 角色。
如果你完全不想碰 Docker,还可以选 Code ZIP 部署方式:直接上传 .NET 代码,平台会负责构建和托管,连 Dockerfile 都不用写。