A2A (Agent-to-Agent)
Mastra 支持 0.3.0 版 Agent-to-Agent (A2A) 协议,可用于构建跨平台的多 Agent 系统。你可以通过 A2A 将 Mastra Agent 公开为远程 Agent、将远程 A2A Agent 作为 Mastra 子 Agent 使用,或通过 JavaScript 客户端 SDK 调用 A2A 端点。
A2A 是一种开放协议,可跨网络、框架、供应商和编程语言边界将工作委派给 Agent。远程 Agent 会将自己的 Tool、提示词、Memory、Workflow 和基础设施保持为私有内容,同时公开一个可供其他系统发现和调用的协议端点。
何时使用 A2A何时使用 A2A的直接链接
- 父 Agent 需要将工作委派给专门的远程 Agent。
- 远程 Agent 由其他服务、团队、供应商或运行时负责。
- 后端、浏览器应用或其他兼容 A2A 的系统需要以编程方式访问 Mastra Agent。
- 长时间运行的远程工作需要任务 ID、状态更新、制品、取消、重新订阅或推送通知。
A2A 的工作原理A2A 的工作原理的直接链接
A2A 使用 Agent Card 进行发现。Agent Card 是由约定 URL 提供的 JSON 文档,其中描述了远程 Agent,并包含接受 A2A JSON-RPC 请求的执行 URL。
使用 Mastra Server 的默认 apiPrefix /api 时,注册为 weather-agent 的 Agent 会公开:
- Agent Card:
/api/.well-known/weather-agent/agent-card.json - 执行端点:
/api/a2a/weather-agent
Agent Card 包含 Agent 名称、描述、端点 URL、Provider、能力、安全元数据和 Skill 等字段:
{
"protocolVersion": "0.3.0",
"name": "Weather Agent",
"description": "Provides weather information.",
"url": "https://agent.example.com/api/a2a/weather-agent",
"version": "1.0",
"provider": {
"organization": "Acme",
"url": "https://acme.example.com"
},
"capabilities": {
"streaming": true,
"pushNotifications": true,
"stateTransitionHistory": false
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "weather",
"name": "weather",
"description": "Gets weather conditions for a location.",
"tags": ["tool"]
}
]
}
A2A 将工作表示为消息和任务。消息可携带文本、文件或结构化数据部分。
任务是具有 ID 和生命周期状态的有状态工作单元。客户端可以跟踪长时间运行的工作并发送后续轮次,还可以取消工作或在连接断开后重新订阅。
协议版本协议版本的直接链接
Mastra 在同一组 Agent Card 和执行 URL 上支持 A2A Protocol v0.3 与 v1.0。A2A-Version 请求标头用于选择传输协议:
- 缺失、为空或值为
0.3:使用现有的 v0.3 API。 1.0:使用 v1.0 API。- 其他任何值:返回
VersionNotSupported协议错误。
现有的 A2AAgent 和 MastraClient.getA2A() 集成会继续使用 v0.3。要发送 v1.0 请求,请使用 MastraClient.getA2AV1()。v1 客户端会自动发送 A2A-Version: 1.0,并新增 tasks/list 操作。
从 @mastra/core/a2a/v1 导入 v1.0 协议类型和编解码器。现有的 @mastra/core/a2a/client 导出仍使用 v0.3。
开始使用开始使用的直接链接
在 Mastra 中,A2A 有两种常见使用方式:
- 使用
A2AAgent将远程 A2A Agent 作为 Mastra 子 Agent 使用。 - 使用
MastraClient.getA2A()向 Mastra A2A 端点发送请求。
当另一个 Mastra Agent 需要将工作委派给远程 Agent 时,请使用 A2AAgent。当应用代码需要直接调用已启用 A2A 的 Mastra 端点时,请使用客户端 SDK。
将 A2A Agent 作为子 Agent 使用将 A2A Agent 作为子 Agent 使用的直接链接
使用 A2AAgent 封装远程 A2A Agent,然后按照 Supervisor Agent 模式将其添加到父 Agent。当远程 Server 托管多个 Agent 或使用自定义 well-known 路径时,请传入明确的 Agent Card URL。
import { Agent } from '@mastra/core/agent'
import { A2AAgent } from '@mastra/core/a2a'
const remoteWeatherAgent = new A2AAgent({
url: 'https://weather.example.com/api/.well-known/weather-agent/agent-card.json',
headers: {
Authorization: `Bearer ${process.env.WEATHER_AGENT_TOKEN}`,
},
})
export const supportAgent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: 'Answer user questions and delegate weather questions when needed.',
model: 'openai/gpt-5.6-sol',
agents: {
remoteWeatherAgent,
},
})
如果 url 指向域名,A2AAgent 会从 /.well-known/agent-card.json 获取 Agent Card。对于遵循该发现路径的单 Agent Server,请使用域名 URL。对于多 Agent Server,请传入完整的 Agent Card URL,例如 https://agent.example.com/api/.well-known/weather-agent/agent-card.json。
执行期间,A2AAgent 会:
- 获取并缓存远程 Agent Card。
- 从 Agent Card 中读取执行 URL 和能力。
- 对非流式运行调用
message/send,或在支持流式传输时调用message/stream。 - 将远程消息、任务、制品和状态更新转换为 Mastra 子 Agent 结果。
- 当远程任务需要后续输入或重新订阅时,支持
resumeGenerate()和resumeStream()。
如果远程 Agent Card 未声明支持流式传输,A2AAgent.stream() 会回退到非流式生成路径,并返回经过缓冲的流结果。
使用客户端 SDK 发送请求使用客户端 SDK 发送请求的直接链接
当应用代码需要调用已启用 A2A 的 Mastra Agent 时,请使用 MastraClient.getA2A()。通过 baseUrl 配置 Server 源站;如果 Server 的 apiPrefix 未使用默认前缀 /api,还需进行相应配置。
import { MastraClient } from '@mastra/client-js'
const client = new MastraClient({
baseUrl: 'https://agent.example.com',
headers: {
Authorization: `Bearer ${process.env.AGENT_API_TOKEN}`,
},
})
const a2a = client.getA2A('weather-agent')
const card = await a2a.getAgentCard()
console.log(card.name, card.capabilities)
使用 sendMessageStream() 发送消息,并通过 Server-Sent Events (SSE) 接收任务状态和制品更新:
const stream = a2a.sendMessageStream({
message: {
kind: 'message',
role: 'user',
messageId: crypto.randomUUID(),
parts: [{ kind: 'text', text: "What's the weather in Prague?" }],
},
})
for await (const event of stream) {
if (event.kind === 'artifact-update') {
console.log(event.artifact.parts)
}
}
如果流在任务仍在运行时断开,请使用 resubscribeTask() 接收进行中任务的实时更新:
const updates = a2a.resubscribeTask({
id: 'task-123',
})
for await (const event of updates) {
console.log(event)
}
使用 v1.0 客户端使用 v1.0 客户端的直接链接
使用 getA2AV1() 选择 A2A v1.0 传输协议。协议包提供了编解码器,可根据 JSON 结构的输入创建 v1 请求值:
import { ListTasksRequest } from '@mastra/core/a2a/v1'
import { MastraClient } from '@mastra/client-js'
const client = new MastraClient({
baseUrl: 'https://agent.example.com',
})
const a2a = client.getA2AV1('weather-agent')
const response = await a2a.listTasks(
ListTasksRequest.fromJSON({
contextId: 'customer-support',
pageSize: 20,
}),
)
for (const task of response.tasks) {
console.log(task.id, task.status)
}
v1.0 客户端支持 getAgentCard()、sendMessage()、sendMessageStream()、getTask()、listTasks()、cancelTask() 和 resubscribeTask()。
配置子 Agent 调用配置子 Agent 调用的直接链接
A2AAgent 接受适用于需要身份验证或受限环境的请求选项:
import { A2AAgent } from '@mastra/core/a2a'
const remoteWeatherAgent = new A2AAgent({
url: 'https://weather.example.com/api/.well-known/weather-agent/agent-card.json',
headers: {
Authorization: `Bearer ${process.env.WEATHER_AGENT_TOKEN}`,
},
retries: 2,
backoffMs: 250,
maxBackoffMs: 1000,
timeoutMs: 30_000,
})
当运行时需要自定义 fetch 行为或取消请求时,还可以传入 credentials、fetch 和 abortSignal。
人工介入人工介入的直接链接
A2A 使用 input-required 任务状态对人工介入 (HITL) 工作进行建模。当任务暂停以等待输入时,客户端通过发送带有相同 taskId 的后续消息提供缺失的输入,Server 随后继续执行任务。
Mastra 会在两个方向上将自身的 Agent 挂起模型映射到此状态:
- 作为 Server:公开的 Agent 挂起时,任务会转换到
input-required。这包括由 Tool 审批或调用suspend()的 Tool 导致的挂起。任务状态消息包含文本提示,以及带有结构化suspendPayload和resumeSchema的数据部分。后续message/send或message/stream请求只要带有相同的taskId,就会使用所提供的输入恢复挂起的运行。 - 作为客户端:当远程任务进入
input-required或auth-required状态时,A2AAgent会返回finishReason: 'suspended'和suspendPayload的挂起结果。调用resumeGenerate()或resumeStream()会使用原始taskId将输入或凭据发回远程任务。
import { A2AAgent } from '@mastra/core/a2a'
const agent = new A2AAgent({
url: 'https://agent.example.com/api/.well-known/booking-agent/agent-card.json',
})
const result = await agent.generate('Book a flight to Paris', { runId: 'run-1' })
if (result.finishReason === 'suspended') {
// Inspect result.suspendPayload, collect input from a human,
// then resume the remote task.
const resumed = await agent.resumeGenerate({ approved: true }, { runId: 'run-1' })
console.log(resumed.text)
}
input-required 任务的后续消息可以通过结构化数据部分携带恢复数据,也可以在文本部分中以 JSON 或纯文本形式携带。
当恢复的运行仍需要额外输入时,任务会重新进入 input-required,并重复此流程。恢复挂起的运行要求 Mastra Server 配置 Storage,以便跨请求还原挂起的运行状态。
A2A 任务记录存放在内存存储中,因此暂停的任务只能由将其挂起的同一个 Server 进程恢复。如果 Server 重启,或水平扩展部署未使用粘性路由,任务记录将会丢失,后续消息会因找不到任务而失败。
推送通知推送通知的直接链接
Mastra 支持向声明 capabilities.pushNotifications 的远程 Agent 发送 A2A 推送通知。当客户端无法保持流连接,或长时间运行的任务应在原始请求结束后更新回调 URL 时,请使用推送通知。
客户端获得任务 ID 后,可以为该任务注册回调 URL:
await a2a.setTaskPushNotificationConfig({
taskId: 'task-123',
pushNotificationConfig: {
url: 'https://app.example.com/a2a/tasks',
token: process.env.A2A_WEBHOOK_TOKEN,
},
})
当任务进入 completed、failed、canceled、rejected、input-required 或 auth-required 状态时,Mastra Server 会将当前任务快照发送到已注册的回调。推送通知采用尽力交付方式。请保护回调 URL、验证通知令牌,并避免将内部网络目标公开为推送通知目标。
推送通知配置存储在内存中,Server 重启后必须重新注册。
签名并验证 Agent Card签名并验证 Agent Card的直接链接
Mastra 支持签名的 A2A Agent Card,使客户端能够验证发现的 Agent Card 是否来自可信发布者,以及是否在传输过程中被更改。请在公开远程 Agent 的 Mastra Server 上配置签名:
import { Mastra } from '@mastra/core/mastra'
export const mastra = new Mastra({
server: {
a2a: {
agentCardSigning: {
privateKey: process.env.A2A_AGENT_CARD_PRIVATE_KEY!,
protectedHeader: {
alg: 'ES256',
kid: 'agent-card-key',
},
},
},
},
})
配置签名后,Mastra 会在 Agent Card 中包含 signatures 数组。客户端验证需要主动启用,未签名的 Agent Card 仍会原样返回。
通过 MastraClient.getA2A() 验证签名的 Agent Card:
const card = await a2a.getAgentCard({
verifySignature: {
algorithms: ['ES256'],
keyProvider: async ({ kid, jku }) => {
return fetchTrustedPublicJwk({ kid, jku })
},
},
})
if (!card.signatures?.length) {
throw new Error('Expected a signed A2A agent card.')
}
当客户端必须在调用远程 Agent 前强制使用可信密钥时,请使用客户端签名验证。
验证子 Agent 的 Agent Card验证子 Agent 的 Agent Card的直接链接
当父 Agent 需要在委派工作前验证远程 Agent 时,请使用 verifyAgentCard。验证钩子会接收已获取的 Agent Card,以及有关获取位置和时间的上下文。
import { A2AAgent } from '@mastra/core/a2a'
const remoteWeatherAgent = new A2AAgent({
url: 'https://weather.example.com/api/.well-known/weather-agent/agent-card.json',
verifyAgentCard: {
verify: async (card, context) => {
if (card.provider?.organization !== 'Weather Inc') {
throw new Error(`Unexpected provider for ${context.cardUrl}`)
}
},
},
})
在父 Agent 将工作委派给远程 Agent 前,可使用此钩子强制要求预期的 Provider、端点、证书绑定身份、签名 Agent Card 或其他信任要求。