A2A Endpoints and A2A Tool in Microsoft Foundry agents

最近我在研究 Microsoft Foundry 的多智能体能力时,注意到一个变化:智能体之间的协作终于不用再靠一堆自定义 API 拼凑了。A2A 工具和新的入站 A2A 端点现在支持 A2A 协议 1.0 版本,这个版本已经正式发布(GA)。之前预览阶段用的 a2a_preview 工具类型和 0.3 版协议依然保留,给已有的集成留了一条兼容路径。托管智能体(Hosted Agents)也可以通过暴露在 MCP 上的 Foundry 工具箱来使用 A2A 工具。

如果你一直在关注早期预览版本,可能记得 A2A 端点以前叫"A2A API head"。思路其实很直白:

  • A2A 端点:把一个 Foundry 智能体暴露出去,让外部智能体能发现它、调用它。
  • A2A 工具:让 Foundry 智能体反过来去调用另一个兼容 A2A 协议的智能体。
  • 托管智能体:通过暴露成 MCP 端点的 Foundry 工具箱来使用 A2A 工具。

这三块拼在一起,就能搭出一套多智能体系统:每个智能体各管一摊,把自己的能力发布出来,跨服务边界安全协作。

这为什么重要

在这之前,很多多智能体模式都得靠自定义 API、临时适配器,或者跟某个框架深度绑定的编排逻辑来实现。A2A 协议解决的就是这个问题,它给智能体之间的通信定了一套标准。说实话,这种"发智能体名片、按协议通信"的思路,比我之前见过的那些各家自造协议要靠谱不少。

也就是说,一个智能体可以直接向另一个智能体求助,完全不用了解对方内部是怎么实现的。调用方通过智能体名片(agent card)发现远程智能体的能力,通过 A2A 协议发送任务,拿到结果后再融入自己的对话里。

对于 Foundry 托管的 A2A 端点,发现过程是需要认证的。智能体名片的 URL 和协议端点都要求 Microsoft Entra ID 认证,不是公开可访问的。

举几个例子:

  • 客服智能体可以调用账单智能体。
  • 研究智能体可以调用数据分析智能体。
  • Foundry 托管的企业智能体可以调用运行在 Foundry 之外的专用智能体。
  • 托管智能体可以调用包了一层 A2A 连接的 Foundry 工具箱。

架构一:外部智能体通过 A2A 端点调用 Foundry 智能体

这种模式下,Foundry 智能体被暴露成一个 A2A 端点,外部智能体发现它的智能体名片,然后用 A2A 协议去调用。

外部智能体通过智能体名片发现 Foundry 智能体,用 A2A 协议 v1.0 调用,拿到由 Foundry 的工具、数据和模型生成的响应

Foundry 智能体会用自己配置好的模型、指令、工具和企业数据源来处理这个请求,处理完再把结果返回给调用方。不过 Foundry 提示词智能体必须先支持 Responses 协议,才能通过入站 A2A 端点暴露出去,这个前提条件容易被忽略。

Foundry 智能体暴露的 A2A 基础 URL 格式是这样的:

https://{account}.services.ai.azure.com/api/projects/{project}/agents/{agent}/endpoint/protocols/a2a

按版本区分的智能体名片 URL 则是:

https://{account}.services.ai.azure.com/api/projects/{project}/agents/{agent}/endpoint/protocols/a2a/agentCard/v1.0
https://{account}.services.ai.azure.com/api/projects/{project}/agents/{agent}/endpoint/protocols/a2a/agentCard/v0.3

新做集成的话,建议直接对准 v1.0,这个版本已经 GA 了。v0.3 还留着,但那是给已有预览集成兼容用的,v1.0 才是往后要走的路。

Foundry 用同一个 A2A 基础路径同时服务两个协议版本,调用方通过智能体名片协商、A2A-Version 请求头,或者 a2a-version 查询参数来选版本。生产环境的客户端最好显式指定 v1.0,不要指望默认行为帮你兜底。

Foundry 的入站 A2A v1.0 端点用的是 JSON-RPC。入站 A2A v0.3 同时支持 JSON-RPC 和 HTTP+JSON,但 v0.3 还处于预览阶段。目前只支持文本模态,也不支持流式响应。

架构二:Foundry 智能体用 A2A 工具调用另一个智能体

反过来的模式同样重要:Foundry 智能体可以用 A2A 工具去调用另一个兼容 A2A 的端点。

Foundry 智能体通过 A2A 工具调用远程 A2A 兼容智能体的架构示意

RemoteA2A 项目连接负责存放远程 A2A 的基础 URL 和认证配置,A2A 工具引用这个连接,并指定要用的 A2A 协议版本。

Foundry 会自动解析默认的智能体名片路径,并协商 A2A 协议版本。如果目标是 Foundry 智能体,你都不用配置 send_credentials_for_agent_card。

先设置好当前的 Foundry 项目,再创建 RemoteA2A 连接:

1
2
3
4
5
6
7
8
PROJECT_ENDPOINT="https://{account}.services.ai.azure.com/api/projects/{project}"
azd ai project set "$PROJECT_ENDPOINT"

azd ai connection create my-a2a-connection \
  --kind remote-a2a \
  --target "https://{account}.services.ai.azure.com/api/projects/{project}/agents/{agent}/endpoint/protocols/a2a" \
  --auth-type agentic-identity \
  --audience "https://ai.azure.com"

目标 Foundry 项目或智能体得给调用方的身份授予 Foundry Agent Consumer 角色,或者其他包含所需端点权限的角色。分配角色的时候,用的是调用方身份的 Microsoft Entra 对象 ID 或主体 ID,不是应用 ID 或客户端 ID,这一点我自己也搞混过一次。

角色分配既可以在目标项目范围创建,也可以在单个智能体范围创建:

1
2
3
4
5
az role assignment create \
  --assignee-object-id "{calling-agent-principal-object-id}" \
  --assignee-principal-type "ServicePrincipal" \
  --role "eed3b665-ab3a-47b6-8f48-c9382fb1dad6" \
  --scope "{target-project-or-agent-resource-id}"

智能体身份和托管身份在 Microsoft Entra ID 里都是以服务主体的形式存在的,所以这里主体类型用的是 ServicePrincipal。

架构三:托管智能体通过 Foundry 工具箱使用 A2A

托管智能体可以通过挂载一个 Foundry 工具箱来使用 A2A。工具箱里包含一个 A2A 工具箱工具,并通过兼容 MCP 的端点把它暴露出来。

完整的交互流程是这样的:

  • 托管智能体通过 MCP 连接到 Foundry 工具箱。
  • 托管智能体用 Microsoft Entra ID 向工具箱认证。
  • 工具箱调用它配置好的 A2A 工具箱工具。
  • A2A 工具箱工具引用一个 RemoteA2A 项目连接。
  • RemoteA2A 连接确定目标地址和下游认证配置。
  • 工具箱通过 A2A 协议调用远程智能体。
  • 结果通过工具箱的 MCP 端点返回给托管智能体。

托管智能体通过 Foundry 工具箱和 RemoteA2A 项目连接安全调用远程 A2A 智能体

这其实是个两跳架构:托管智能体先通过 MCP 连到 Foundry 工具箱,工具箱再通过 A2A 连到远程智能体。

托管智能体使用的工具箱 MCP 端点格式是:

https://{account}.services.ai.azure.com/api/projects/{project}/toolboxes/{toolbox-name}/versions/{version}/mcp?api-version=v1

如果托管智能体必须锁定在某个不可变的工具箱版本上,也可以用带版本号的工具箱端点。

托管智能体用 Microsoft Entra ID 向工具箱认证,用的作用域是:

https://ai.azure.com/.default

托管智能体通过 Microsoft Entra ID 向 Foundry 工具箱 MCP 端点认证,要直接获取令牌的话,用 https://ai.azure.com/.default 这个作用域就行。

下游的凭据、密钥、托管身份设置和 OAuth 配置都应该留在 RemoteA2A 项目连接里,不要写死在托管智能体的代码里。

认证才是真正要花心思的部分

在这套体系里,最需要设计的其实是认证。A2A 支持不同的模式,具体用哪种取决于调用方智能体应该以自己的身份行事,还是代表用户去行事。

这张表我建议直接收藏,选错认证方式是最容易在生产环境里踩坑的地方:

认证类型 适用场景
none 远程端点不需要认证,生产环境很少这么用
custom-keys 端点需要 API 密钥、PAT、bearer token 或自定义请求头
oauth2 每个用户都要通过 OAuth 2.0 授权流程单独授权,下游操作需要保留用户个人权限时用这个
user-entra-token 需要把用户的 Microsoft Entra 身份传递给远程服务
project-managed-identity 项目里所有智能体共用同一个项目身份
agentic-identity 用智能体身份、服务主体或托管身份做服务间调用,角色分配时用这个作为主体类型

对于 Foundry 智能体的入站 A2A 端点,认证要求更严格:

  • 入站 A2A 强制要求 Microsoft Entra ID 认证。
  • 不支持基于密钥的访问,也不支持匿名访问。
  • 调用方必须拥有 Foundry Agent Consumer 角色,或者其他能授予端点访问权限的角色。
  • 权限既可以在项目范围授予,也可以在单个智能体范围授予。
  • 调用可以用代表用户的身份,也可以用智能体身份、服务主体、托管身份这类服务身份。

如果下游操作需要尊重每个用户各自的权限,就用 OAuth 或者用户身份透传。

需要配置的内容

要把一个 Foundry 智能体暴露成 A2A 端点,需要配置两样东西:一张描述智能体能力的智能体名片,以及智能体端点上的 A2A 协议。

智能体 PATCH 请求体里相关的部分大概长这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "agent_card": {
    "description": "A specialist agent that answers questions about invoices.",
    "version": "1.0",
    "skills": [
      {
        "id": "invoice-lookup",
        "name": "Invoice lookup",
        "description": "Finds and summarizes invoice status."
      }
    ]
  },
  "agent_endpoint": {
    "protocol_configuration": {
      "responses": {},
      "a2a": {}
    }
  }
}

Foundry 门户里也能直接给提示词智能体配置智能体名片,配完之后别的智能体就能通过 Tools,用这个智能体的 A2A 端点来调用它了。

Foundry 里某个智能体的 A2A 端点配置

Foundry 智能体的智能体名片配置界面

写在最后

A2A 端点和 A2A 工具让 Foundry 智能体变得可以拼装组合了。与其造一个什么都懂的巨型智能体,不如拆成几个各有专长的小智能体,让它们发布自己的能力、彼此安全协作,这个思路我个人是认同的。

想让别的智能体调用你的 Foundry 智能体,就用 A2A 端点;想让你的 Foundry 智能体去调用别的智能体,就用 A2A 工具;如果是托管智能体,那就通过 Foundry 工具箱把 A2A 干净地接进托管运行时。

延伸阅读: