Foundry 托管智能体

Microsoft Foundry 代理服务中的 托管代理允许将 Agent Framework 代理部署为容器化应用程序,在 Microsoft 托管的基础设施上。 平台处理缩放、会话状态持久性、安全性和生命周期管理,以便你可以专注于代理的逻辑。 Microsoft Foundry 托管代理现已正式发布。

借助 Agent Framework 托管集成,只需极少量代码即可通过 Foundry Responses 或 Invocations 协议公开提供一个 Agent,包括用 Workflow.as_agent() 包装的工作流。

何时使用托管代理

如果需要,请选择 Foundry 托管代理:

  • 托管基础结构 - 无需自行配置容器、Web 服务器或缩放规则。
  • 内置会话管理 — 平台在轮次和空闲期间保留 $HOME 和上传的文件。
  • 专用代理标识 - 每个已部署的代理获取其自己的 Entra 标识,以便安全访问模型、工具和下游服务。
  • 与 OpenAI 兼容的终结点 - 客户端可以通过响应协议使用任何与 OpenAI 兼容的 SDK 与代理交互。

注释

Python agent-framework-foundry-hosting 集成目前为预发布版本。 Microsoft Foundry 托管代理(托管托管服务)已正式发布。

Prerequisites

对于本地测试,还需要:

安装托管 NuGet 包:

dotnet add package Microsoft.Agents.AI.Foundry.Hosting --prerelease
dotnet add package Azure.AI.Projects --prerelease
  • Python 3.10 或更高版本

安装预发行版托管包、Foundry 客户端和Azure身份验证包:

pip install --pre agent-framework-foundry agent-framework-foundry-hosting azure-identity

在 Foundry 中,平台提供调用方的用户上下文和调用上下文;托管基础结构使用它们来隔离每个用户的状态,并将请求上下文转发到 Foundry 服务。 本地运行时不会获得该平台的上下文信息,因此应用程序必须在需要时自行提供身份和状态控制机制。

响应协议

对于大多数代理,推荐以Responses协议为起点。 它公开与 OpenAI 兼容的 /responses 终结点,平台会自动管理会话历史记录、流式处理和会话生命周期。

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-4o";

AIAgent agent = new AIProjectClient(projectEndpoint, new DefaultAzureCredential())
    .AsAIAgent(
        model: deployment,
        instructions: "You are a helpful AI assistant.",
        name: "my-agent");

var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses());

var app = builder.Build();
app.Run();

AgentHost.CreateBuilder 创建为 Foundry 托管环境预配置的应用程序主机。 AddFoundryResponses 使用 Responses 协议处理程序注册你的智能体,并且 MapFoundryResponses 映射 /responses HTTP 终结点。

import os

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.identity import DefaultAzureCredential

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a helpful AI assistant.",
)

server = ResponsesHostServer(agent)
server.run()

ResponsesHostServer 包装你的智能体并通过 Foundry Responses 协议公开它。 对于非工作流代理,默认值 history_source="agent_server" 使用配置的代理服务器响应提供程序作为模型的历史记录源。 默认情况下,当客户端存储历史记录时,主机会阻止下游模型服务保留第二个副本。

不要将默认历史记录源与具有 HistoryProviderload_messages=True 组合。 此外,不要设置conversation_idprevious_response_idconversation下游服务延续选项。 主机拒绝这些配置以防止重复历史记录。

当代理的历史记录提供程序或下游模型服务必须管理对话历史记录时,应使用 ResponsesHostServer(agent, history_source="agent")。 此模式仅传递来自代理服务器的当前请求输入,并保留代理的历史记录和服务存储行为。 自定义 SupportsAgentRun 实现必须使用此模式。 参数 store 保持独立:它选择在两种模式下保留响应 API 输入和输出的响应提供程序。

宿主拥有所提供的代理,并且可能会添加宿主特定的上下文提供程序。 不要将该代理复用于另一台主机,也不要在主机构造完成后直接调用它。

持久保存状态并处理长时间运行的会话

ResponsesHostServer 在默认情况下会配置 Foundry 支持的存储。 对于非工作流代理, AgentSessionStoreProvider 提供一个 FoundryAgentSessionStore. 对于工作流代理而言,CheckpointStoreProvider 提供一个 FoundryCheckpointStoreFunctionApprovalStoreProvider 为待审批事项提供 FoundryFunctionApprovalStore。 这些存储在托管环境中使用 Foundry 状态存储,在本地运行时则使用本地智能体服务器状态。

使用 history_source="agent" 时,配置的会话存储会持久化由 AgentSession 携带的提供程序状态,包括来自 InMemoryHistoryProvider 的消息。

若要自定义存储,请将 function_approval_store_provider 传递给 StoreProvideragent_session_store_provider。 将 ContextScopedStoreProvider 传递给 checkpoint_store_provider。 例如,实现 SessionStoreStoreProvider[SessionStore],以使用您自己的非工作流代理会话存储。

azure.ai.agentserver.responses中导入ResponsesServerOptions,并将其传递给ResponsesHostServeroptions参数。 可用的长时间运行的会话选项取决于代理类型:

能力 代理类型 要求和行为
弹性后台响应 仅限工作流 设置 ResponsesServerOptions(resilient_background=True)。 使用 background=truestore=true 发送 Responses 请求。 重启后,主机将恢复最新的持久工作流检查点,或者在不存在检查点时重播原始输入。 不要在工作流上配置检查点存储,因为主机管理它。 确保外部副作用具有幂等性,因为最后一个持久检查点之后的处理可能会重复执行。
可控对话 仅适用于非工作流 设置 store=true 并使用 ResponsesServerOptions(steerable_conversations=True) 发送 Responses 请求。 通过复用相同的 conversation 值,将各轮次保持在同一条线性链上。 或者,发送紧接在前面的 previous_response_id,并保留已解析的 agent_session_id。 主机拒绝将创建分叉的过时前置任务。

如果为非工作流代理启用弹性后台响应,或为工作流代理启用可引导对话,ResponsesHostServer 会引发 RuntimeError。 有关完整的实现,请参阅 自定义存储可复原的长时间运行的工作流,以及 可引导长时间运行的代理 示例。

当 Foundry 托管的 MCP 工具需要用户同意时, ResponsesHostServer 返回包含 oauth_consent_request 输出项的不完整响应。 向用户展示其 consent_link,然后在用户完成同意操作后,以 previous_response_id 作为该不完整响应的 ID 继续处理。 主机端会在此次重试期间保留代理会话,并且仅提供绝对 HTTPS 同意链接。

调用协议

调用协议可让你完全控制 HTTP 请求和响应。 如果您需要自定义负载、非会话处理或不兼容 OpenAI 的流式处理协议,请使用它。

使用 C# 中的调用协议,可以实现用于处理传入请求的自定义 InvocationHandler

using Azure.AI.AgentServer.Core;
using Azure.AI.AgentServer.Invocations;
using Microsoft.Agents.AI;

var builder = AgentHost.CreateBuilder(args);

builder.Services.AddSingleton<AIAgent, MyAgent>();
builder.Services.AddInvocationsServer();
builder.Services.AddScoped<InvocationHandler, MyInvocationHandler>();

builder.RegisterProtocol("invocations", endpoints => endpoints.MapInvocationsServer());

var app = builder.Build();
app.Run();

该方法 AddInvocationsServer 注册调用协议服务。 实现 InvocationHandler 以定义代理处理每个请求的方式。

对于轻量级设置,请使用 agent_framework_foundry_hosting 包中的 InvocationsHostServer。 它像 ResponsesHostServer 一样封装您的代理,并自动处理会话管理。

import os

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import InvocationsHostServer
from azure.identity import DefaultAzureCredential

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a friendly assistant. Keep your answers brief.",
    default_options={"store": False},
)

server = InvocationsHostServer(agent)
server.run()

若要完全控制请求处理,请直接从InvocationAgentServerHost包使用azure.ai.agentserver.invocations并实现自己的调用处理程序:

import os
from collections.abc import AsyncGenerator

from agent_framework import Agent, AgentSession
from agent_framework.foundry import FoundryChatClient
from azure.ai.agentserver.invocations import InvocationAgentServerHost
from azure.identity import DefaultAzureCredential
from starlette.requests import Request
from starlette.responses import JSONResponse, Response, StreamingResponse

_sessions: dict[str, AgentSession] = {}

client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
    credential=DefaultAzureCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a friendly assistant. Keep your answers brief.",
    default_options={"store": False},
)

app = InvocationAgentServerHost()


@app.invoke_handler
async def handle_invoke(request: Request):
    """Handle streaming multi-turn chat."""
    data = await request.json()
    session_id = request.state.session_id
    stream = data.get("stream", False)
    user_message = data.get("message", None)

    if user_message is None:
        return Response(content="Missing 'message' in request", status_code=400)

    session = _sessions.setdefault(session_id, AgentSession(session_id=session_id))

    if stream:

        async def stream_response() -> AsyncGenerator[str]:
            async for update in agent.run(user_message, session=session, stream=True):
                yield update.text

        return StreamingResponse(
            stream_response(),
            media_type="text/event-stream",
            headers={"Cache-Control": "no-cache", "Connection": "keep-alive"},
        )

    response = await agent.run([user_message], session=session, stream=stream)
    return JSONResponse({"response": response.text})


if __name__ == "__main__":
    app.run()

Warning

自定义处理程序示例中的内存中会话存储在重启时丢失。 在生产中使用持久存储(例如 Cosmos DB)。

如需了解完整的 Invocations 部署,请参阅 Foundry 托管的 Telegram 示例。 它将 API 管理置于托管代理 Webhook 的前面,并使用托管标识、密钥保管库和 Cosmos DB 进行持久聊天历史记录。

注释

即将推出对 Foundry 托管代理的 Go 支持。 有关最新状态,请参阅 Agent Framework Go 存储库

Tip

有关托管代理项目的示例,请参阅 Python 示例C# 示例azd ai agent init或使用该命令从头开始搭建新的托管代理项目。 有关分步说明,请参阅本 快速入门指南

在本地运行

Azure开发人员 CLI(azd)提供了在本地运行和测试托管代理的最简单方法。

初始化项目

从示例清单创建新文件夹并初始化:

mkdir my-hosted-agent && cd my-hosted-agent
azd ai agent init -m <path-to-agent.manifest.yaml>

Tip

清单可以是本地 YAML 文件的路径,也可以是远程清单的 URL。

设置环境变量。

export FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
export AZURE_AI_MODEL_DEPLOYMENT_NAME="<your-model-deployment>"

运行代理主机

azd ai agent run

代理主机在http://localhost:8088启动。

调用代理

azd ai agent invoke --local "Hello!"

或者使用curl

curl -X POST http://localhost:8088/responses \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello!"}'

或在 PowerShell 中:

(Invoke-WebRequest -Uri http://localhost:8088/responses -Method POST -ContentType "application/json" -Body '{"input": "Hello!"}').Content

部署到 Foundry

在本地验证代理后,将其部署到 Microsoft Foundry:

  1. 预配资源(如果您还没有 Foundry 项目):

    azd provision
    

    这会创建一个资源组,其中包含 Foundry 实例、项目、模型部署、Application Insights 和容器注册表。

  2. 部署代理:

    azd deploy
    

    这会将代理打包为容器映像,将其推送到Azure 容器注册表,并将其部署到 Foundry 代理服务。

Foundry 托管基础结构会在运行时自动将以下环境变量注入代理容器:

Variable 说明
FOUNDRY_PROJECT_ENDPOINT Foundry 项目的端点 URL。
AZURE_AI_MODEL_DEPLOYMENT_NAME 模型部署名称(在azd ai agent init期间配置)。
APPLICATIONINSIGHTS_CONNECTION_STRING 用于遥测的 Application Insights 连接字符串。

部署后,代理可通过其专用 Foundry 终结点进行访问,也可以从 Foundry 门户进行测试。

后续步骤