Appearance
A2A(Agent2Agent Protocol)处理独立 Agent 服务之间的发现、调用、任务状态和结果交付,它规定服务接口,不规定 Agent 内部怎样推理和执行
一次调用可能持续数秒,也可能持续数小时,执行期间还可能等待输入或授权,网络连接则可能在任务结束前中断;A2A 用 Agent Card 描述服务契约,用 Task 保存独立于连接的执行状态
模型、提示词、记忆、RAG、内部工具和工作流仍由 Agent 自己决定;远端实现可以使用大模型,也可以是规则引擎、审批流或人工处理队列,只要服务边界符合协议,调用方就不需要了解内部实现
版本基线采用 2026 年发布的 A2A 1.0 规范
1.0 以 a2a.proto 为规范性数据模型,同时定义 JSON-RPC、gRPC、HTTP+JSON 三种标准绑定;0.3 与 1.0 的兼容性差异放在文末
调用边界
一次调用涉及 User、A2A Client 和 A2A Server
User 提出目标,Client 代表 User 发起远程委托,Server 接收委托并执行工作,规范将 Server 称为 Remote Agent;Client 通常也是一个 Agent
A2A 只约束图中跨网络的边
能力描述、消息发送、任务创建、状态报告和结果交付属于协议范围;两端怎样推理不属于协议范围
| A2A 规定的内容 | Agent 自己决定的内容 |
|---|---|
| Agent 的发现信息与调用接口 | 使用什么模型和提示词 |
| Message、Task、Artifact 的数据结构 | 怎样拆解、规划和执行任务 |
| 任务查询、取消、订阅和推送操作 | 怎样调用内部工具或 MCP Server |
| 协议版本、错误语义和认证声明 | 怎样保存记忆、日志与业务数据 |
普通 RPC 通常假设一次请求对应一次确定的返回
Agent 工作可能等待外部系统、分阶段产生结果,或者要求调用方补充信息;A2A 用 Task 状态机记录这些执行条件,客户端不必从超时、连接关闭或自然语言回复中猜测任务状态
即时且无状态的答复可以直接返回 Message,需要追踪状态的工作返回 Task
数据模型、操作与协议绑定
A2A 1.0 分成对象、操作和绑定三层
对象层定义 Agent Card、Message、Part、Task、Artifact 和流式事件;操作层定义 Send Message、Get Task、Cancel Task、Subscribe to Task;绑定层处理 HTTP 路径、JSON-RPC 方法名和 gRPC Service
同一项操作在三种标准绑定中的写法不同,行为必须等价:
| 操作语义 | JSON-RPC | gRPC | HTTP+JSON |
|---|---|---|---|
| 发送消息 | SendMessage | SendMessage | POST /message:send |
| 流式发送 | SendStreamingMessage | SendStreamingMessage | POST /message:stream |
| 查询任务 | GetTask | GetTask | GET /tasks/{id} |
| 取消任务 | CancelTask | CancelTask | POST /tasks/{id}:cancel |
| 订阅任务 | SubscribeToTask | SubscribeToTask | POST /tasks/{id}:subscribe |
三种绑定的完整映射见 Method Mapping Reference
业务代码应依赖 A2A 对象和操作,绑定层负责序列化、认证载体和错误映射;业务代码直接拼接 /message:send,等于绑定 HTTP+JSON
业务代码固定使用 JSON-RPC,也就无法与只提供 gRPC 的 Agent 协商
1.0 的 JSON 表示遵循 ProtoJSON 规则
Proto 字段 context_id 在 JSON 中写作 contextId,枚举写成 TASK_STATE_WORKING、ROLE_USER 这样的字符串;这些形式是线上数据格式,SDK 必须按此编码
Agent Card 与接口协商
客户端在发送业务消息前读取 Agent Card;Card 是机器可读的调用契约,包含 Agent 身份、Skill、输入输出类型、认证要求和协议接口
公开发现地址是:
text
GET https://agent.example.com/.well-known/agent-card.json示例 Card 同时提供 HTTP+JSON 和 gRPC,并将 HTTP+JSON 声明为首选接口:
json
{
"name": "Research Agent",
"description": "接受研究主题,返回带结构化摘要的研究报告",
"supportedInterfaces": [
{
"url": "https://research.example.com/a2a",
"protocolBinding": "HTTP+JSON",
"protocolVersion": "1.0"
},
{
"url": "research.example.com:443",
"protocolBinding": "GRPC",
"protocolVersion": "1.0"
}
],
"version": "2.4.0",
"capabilities": {
"streaming": true,
"pushNotifications": true,
"extendedAgentCard": true
},
"securitySchemes": {
"oidc": {
"openIdConnectSecurityScheme": {
"openIdConnectUrl": "https://id.example.com/.well-known/openid-configuration"
}
}
},
"securityRequirements": [
{
"schemes": {
"oidc": {
"list": ["openid", "research.invoke"]
}
}
}
],
"defaultInputModes": ["text/plain", "application/json"],
"defaultOutputModes": ["text/markdown", "application/json"],
"skills": [
{
"id": "topic-research",
"name": "专题研究",
"description": "根据研究问题检索、归纳并生成结构化报告",
"tags": ["research", "report", "citation"],
"examples": ["比较三种主流向量数据库的索引机制"],
"inputModes": ["text/plain", "application/json"],
"outputModes": ["text/markdown", "application/json"]
}
]
}supportedInterfaces 是有序列表,第一项表示服务端偏好的接口
客户端从前向后查找自己支持的 protocolBinding,选中后同时采用该项的 URL、protocolVersion 和可选 tenant;tenant 是服务端给出的不透明路由值,客户端只负责原样携带,不解析租户或分片含义
没有共同绑定就是协商失败;客户端不得猜测 URL,不得执行 Card 未声明的版本回退,也不得绕过 Card 调用碰巧可访问的 HTTP Endpoint
Card 中有两种版本,不能混用
顶层 version 是 Agent 服务的发布版本,接口中的 protocolVersion 是 A2A 协议版本;服务从 2.4.0 升级到 2.5.0,不表示 A2A 协议版本发生变化
公开地址只是发现方式之一,Card 也可以来自私有配置、服务目录或注册中心,但 A2A 不定义统一的注册中心 API
协议只定义 Card 的结构和调用语义;目录怎样收集、审核和检索 Card,属于部署系统的职责
相关定义见 Agent Discovery
生产客户端应缓存 Card,并使用 Cache-Control、ETag 做条件刷新
1.0 支持 Card 的 JWS 签名,签名前按照 RFC 8785 的 JCS 规则规范化 JSON
公开 Card 不宜暴露全部 Skill 时,服务端可以声明 capabilities.extendedAgentCard: true,客户端认证后再调用 Get Extended Agent Card;字段定义见 Agent Card 规范
Message、Task 与 Artifact
运行阶段围绕 Message、Part、Task 和 Artifact 四个对象展开
Message 表示双方的一次交流,可以发起工作,也可以为已有工作补充信息;Part 是 Message 或 Artifact 中的一段内容
Task 由服务端创建,保存工作的身份和生命周期;Artifact 是 Task 的可持久化输出
换成分布式系统术语,Message 接近命令或交互事件,Task 是有状态的远程工作单元,Artifact 是持久化输出
Part
每个 Part 必须且只能设置一种内容:
| 字段 | 内容 | JSON 表示 |
|---|---|---|
text | 文本 | 字符串 |
raw | 原始字节 | Base64 字符串 |
url | 文件或其他内容的地址 | URL 字符串 |
data | 结构化数据 | 任意 JSON 值 |
Part 还可以带 mediaType、filename 和 metadata;结构化输入应直接放进 data:
json
{
"data": {
"topic": "vector database",
"dimensions": ["index", "consistency", "cost"]
},
"mediaType": "application/json"
}不要先把对象转义成 JSON 字符串再放进 text,这种写法要求接收方二次解析,也失去按 MIME 类型校验内容的机会
Part 的字段定义见 Protocol Data Model
Send Message
下例使用 HTTP+JSON 绑定,JSON-RPC 与 gRPC 采用相同的对象语义
http
POST /message:send HTTP/1.1
Host: research.example.com
Authorization: Bearer <access-token>
A2A-Version: 1.0
Content-Type: application/a2a+json
Accept: application/a2a+json
{
"message": {
"messageId": "msg-c75e",
"role": "ROLE_USER",
"parts": [
{
"text": "比较 HNSW 与 IVF 索引,给出适用场景",
"mediaType": "text/plain"
}
]
},
"configuration": {
"acceptedOutputModes": [
"text/markdown",
"application/json"
],
"historyLength": 10,
"returnImmediately": false
}
}A2A-Version 指定本次请求采用的协议语义
acceptedOutputModes 约束客户端能接收的结果格式,historyLength 限制响应中附带的最近消息数;returnImmediately 只控制非流式 Task 调用是否等待,不改变 Agent 内部采用同步还是异步执行
Send Message 的返回类型是 oneof,Message 与 Task 只会出现一个
服务端能够立即给出无状态答复时,可以返回 ROLE_AGENT Message;需要查询、取消、分阶段产出或后续补充输入时,返回 Task:
http
HTTP/1.1 200 OK
Content-Type: application/a2a+json
{
"task": {
"id": "task-9c87",
"contextId": "ctx-4210",
"status": {
"state": "TASK_STATE_COMPLETED",
"timestamp": "2026-08-05T06:31:04.023Z"
},
"artifacts": [
{
"artifactId": "artifact-report",
"name": "HNSW 与 IVF 对比",
"parts": [
{
"text": "# 对比结论\n\nHNSW 以较高内存开销换取低延迟……",
"mediaType": "text/markdown"
}
]
}
]
}
}返回类型取决于调用方是否需要追踪这项工作,不取决于执行时间;十毫秒内创建的后台任务仍应返回 Task,耗时一秒但无需保存状态的答复可以返回 Message
returnImmediately 未设置或为 false 时,非流式请求等到 Task 进入终态或中断态再返回;设为 true 后,服务端创建 Task 即可返回,客户端随后轮询、订阅或等待 Webhook
这个字段只控制当前 RPC 是否保持连接
Task 生命周期
Task ID 由服务端生成;客户端不能为新工作自行指定 Task ID,只能在后续 Message 中引用已经存在的 Task
一份最小 Task 快照如下:
json
{
"id": "task-9c87",
"contextId": "ctx-4210",
"status": {
"state": "TASK_STATE_WORKING",
"timestamp": "2026-08-05T06:30:12.184Z"
},
"artifacts": [],
"history": []
}1.0 定义九个状态,分为进行态、中断态、终态和未确定状态
| 状态 | 生命周期分类 | 协议含义 |
|---|---|---|
TASK_STATE_UNSPECIFIED | 未确定 | 状态未知,不应作为正常业务状态主动使用 |
TASK_STATE_SUBMITTED | 进行中 | 已受理,尚未开始实际处理 |
TASK_STATE_WORKING | 进行中 | 正在处理 |
TASK_STATE_INPUT_REQUIRED | 中断态 | 继续工作还缺少调用方输入 |
TASK_STATE_AUTH_REQUIRED | 中断态 | 继续工作还缺少额外授权 |
TASK_STATE_COMPLETED | 终态 | 成功完成 |
TASK_STATE_FAILED | 终态 | 执行失败 |
TASK_STATE_CANCELED | 终态 | 已取消 |
TASK_STATE_REJECTED | 终态 | Agent 拒绝执行 |
INPUT_REQUIRED 表示可以恢复的中断状态;服务端将缺失信息写入 TaskStatus.message,客户端再用相同 taskId 回复:
json
{
"statusUpdate": {
"taskId": "task-9c87",
"contextId": "ctx-4210",
"status": {
"state": "TASK_STATE_INPUT_REQUIRED",
"message": {
"messageId": "msg-question-01",
"contextId": "ctx-4210",
"taskId": "task-9c87",
"role": "ROLE_AGENT",
"parts": [
{
"text": "请确认对比面向在线检索还是离线批处理",
"mediaType": "text/plain"
}
]
},
"timestamp": "2026-08-05T06:30:20.000Z"
}
}
}客户端的补充消息仍属于这项工作:
json
{
"message": {
"messageId": "msg-reply-01",
"contextId": "ctx-4210",
"taskId": "task-9c87",
"role": "ROLE_USER",
"parts": [
{
"text": "面向在线低延迟检索",
"mediaType": "text/plain"
}
]
}
}AUTH_REQUIRED 的状态转换相同,凭证通道不同
状态消息只说明缺少哪项授权,访问令牌应通过 OAuth、OIDC 或其他带外安全流程交付;不要把令牌写进 Message,否则它可能进入 Task History、日志和后续 Agent 转发链
Context 与 Task
contextId 对相关 Message 和 Task 分组,taskId 标识一项有状态工作
| Message 携带的标识 | 服务端应如何解释 |
|---|---|
| 两者都没有 | 开始新交互,服务端可以生成新 Context |
只有 contextId | 在已有 Context 中开始一项新工作或新交互 |
只有 taskId | 继续已有 Task,由服务端从 Task 推断 Context |
| 两者都有 | 继续指定 Task,两个 ID 必须匹配 |
服务端生成的 ID 都是不透明值,客户端不应从字符串格式推断租户、时间或路由
taskId 与 contextId 不匹配时,服务端必须拒绝请求
终态 Task 不能重新变回 WORKING
若 task-001 已完成,用户又要求“把报告缩短到两页”,协议上应创建一项新的修订工作;新 Message 保留 contextId,并用 referenceTaskIds 指向旧任务:
json
{
"message": {
"messageId": "msg-refine-01",
"contextId": "ctx-4210",
"role": "ROLE_USER",
"parts": [
{
"text": "将上次报告缩短到两页,保留结论与数据来源",
"mediaType": "text/plain"
}
],
"referenceTaskIds": ["task-001"]
}
}服务端为这项修订生成 task-002;两个任务共享 Context,生命周期相互独立
旧任务记录已经结束的事实,新任务记录修订过程,审计和幂等边界也随之分开
Artifact
Message 用于解释进度、追问或澄清,任务结果写入 Artifact;每个 Artifact 在 Task 内有唯一 artifactId,内容由一个或多个 Part 组成:
json
{
"artifactId": "artifact-report",
"name": "研究报告",
"description": "最终版 Markdown 报告",
"parts": [
{
"text": "# 研究结果\n\n……",
"mediaType": "text/markdown"
}
]
}关键输出如果只存在于状态消息中,流断开后可能无法重新取得;Artifact 属于 Task 的可查询状态,适合保存报告、文件和结构化数据
Message 与 Artifact 的边界见 Messages and Artifacts
Task 更新与恢复
流式 A2A 传输协议事件;一个 StreamResponse 只包含以下四种内容之一:Task 快照、直接 Message、TaskStatusUpdateEvent、TaskArtifactUpdateEvent
创建 Task 的流式调用先返回 Task 快照,随后按生成顺序发送状态和 Artifact 更新;Task 进入终态后,服务端关闭流
直接 Message 响应只产生一条 Message 事件
HTTP+JSON 绑定使用 SSE:
http
POST /message:stream HTTP/1.1
Host: research.example.com
Authorization: Bearer <access-token>
A2A-Version: 1.0
Content-Type: application/a2a+json
Accept: text/event-stream
{
"message": {
"messageId": "msg-stream-01",
"role": "ROLE_USER",
"parts": [
{
"text": "生成一份向量索引技术报告",
"mediaType": "text/plain"
}
]
}
}响应中的 Artifact 分两块到达:
text
data: {"task":{"id":"task-9c87","contextId":"ctx-4210","status":{"state":"TASK_STATE_WORKING"}}}
data: {"artifactUpdate":{"taskId":"task-9c87","contextId":"ctx-4210","artifact":{"artifactId":"artifact-report","name":"技术报告","parts":[{"text":"# 向量索引\n\n","mediaType":"text/markdown"}]},"append":false,"lastChunk":false}}
data: {"artifactUpdate":{"taskId":"task-9c87","contextId":"ctx-4210","artifact":{"artifactId":"artifact-report","parts":[{"text":"HNSW 使用多层邻接图……","mediaType":"text/markdown"}]},"append":true,"lastChunk":true}}
data: {"statusUpdate":{"taskId":"task-9c87","contextId":"ctx-4210","status":{"state":"TASK_STATE_COMPLETED","timestamp":"2026-08-05T06:31:04.023Z"}}}客户端按 artifactId 聚合更新
append: false 表示新值或首块,append: true 表示在既有内容后追加;lastChunk: true 只结束当前 Artifact 的分块,不结束 Task
Task 是否结束只由状态决定
同一个 Task 有三种进度交付方式:
| 方式 | 适合的调用 | 恢复与约束 |
|---|---|---|
| Get Task 轮询 | 客户端简单、更新不频繁 | 轮询间隔应退避并加入随机抖动 |
| 流式调用或 Subscribe to Task | 交互界面、频繁增量 | 使用前检查 capabilities.streaming |
| Webhook 推送 | 分钟级或小时级后台任务 | 使用前检查 pushNotifications,接收端必须幂等 |
SSE 连接与 Task 有各自的生命周期;连接中断不会自动取消 Task,流关闭也不表示任务失败
恢复顺序是先调用 Get Task 取得当前快照,Task 尚未终止时再调用 Subscribe to Task;订阅先返回当前 Task 快照,再发送后续增量,以免查询与订阅之间丢失状态变化
终态 Task 不再接受订阅,服务端应返回 UnsupportedOperationError;此时只需 Get Task,因为权威状态和 Artifact 已保存在 Task 中
Webhook 使用与流式响应相同的事件结构,并按至少一次投递;重复投递是协议允许的正常情况,接收方必须按事件或业务键去重
Webhook 负责通知,业务结算前仍要通过 Get Task 核对终态
回调地址本身也是输入
服务端应限制目标协议和网段,检查 DNS 解析与重定向,设置超时、载荷上限和重试次数,防止 SSRF 与流量放大;接收方验证来源、认证信息和 Task ID
具体语义见 Streaming & Asynchronous Operations
Cancel Task 表达取消意图,不保证底层工作立即停止
服务端返回更新后的 Task,任务已经终止或不可取消时,可以返回 TaskNotCancelableError;取消操作必须幂等,重复请求不能产生第二次业务效果
认证与授权
Agent Card 声明认证方案,凭证沿绑定的标准通道传递
HTTP 和 JSON-RPC 通常使用 Authorization Header、API Key Header 或 Cookie,gRPC 使用 Metadata;服务间可以采用 mTLS,授权委托通常使用 OAuth 2.0 或 OIDC
HTTP 生产端点必须使用 HTTPS,gRPC 必须使用 TLS
规范要求见 Authentication and Authorization
入口认证失败与 TASK_STATE_AUTH_REQUIRED 位于不同阶段
入口认证失败发生在合法身份建立之前,一般映射为 HTTP 401 或 gRPC UNAUTHENTICATED;TASK_STATE_AUTH_REQUIRED 发生在 Task 建立之后,例如远端 Agent 执行到一半,需要用户授权访问另一个数据源
Task 状态消息说明授权步骤,秘密凭证仍走带外流程
认证通过只证明调用方身份,不授予读取所有 Task 的权限;Get、List、Subscribe、Cancel 和 Push Config 每次都要执行资源级授权
对于调用方无权访问的 Task,错误不应泄露资源是否存在,服务端通常把不存在与不可见统一处理
url Part 会让接收 Agent 主动访问外部地址,因此它也是输入边界
实现必须检查协议、域名、DNS 解析结果、重定向链、文件大小和 MIME 类型,并隔离扫描不可信的二进制内容;缺少这些检查时,合法的 A2A Message 也可能成为 SSRF 或恶意文件入口
错误、版本与扩展
相同错误在不同绑定中有不同的线格式,协议含义不能变:
| A2A 错误 | JSON-RPC | gRPC | HTTP+JSON |
|---|---|---|---|
| TaskNotFoundError | -32001 | NOT_FOUND | 404 |
| TaskNotCancelableError | -32002 | FAILED_PRECONDITION | 400 |
| PushNotificationNotSupportedError | -32003 | FAILED_PRECONDITION | 400 |
| UnsupportedOperationError | -32004 | FAILED_PRECONDITION | 400 |
| ContentTypeNotSupportedError | -32005 | INVALID_ARGUMENT | 400 |
HTTP+JSON 的专用错误使用 google.rpc.Status 的 JSON 结构,并在 details 中放入 google.rpc.ErrorInfo,因此多个 HTTP 400 仍能精确区分:
json
{
"error": {
"code": 404,
"status": "NOT_FOUND",
"message": "The task does not exist or is not accessible",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "TASK_NOT_FOUND",
"domain": "a2a-protocol.org",
"metadata": {
"taskId": "task-9c87"
}
}
]
}
}客户端控制流应读取结构化状态和 reason,不要匹配英文 message
A2A 协议协商只使用 Major.Minor,例如 1.0;Patch 版本不参与兼容性判断,也不出现在请求协商中
客户端从选中的 Card 接口读取 protocolVersion,并在每次请求中发送 A2A-Version
需要 1.0 特性时,应显式处理 VersionNotSupportedError,不得静默退回 0.3;规范为旧客户端保留兼容行为,空版本按 0.3 解释,新实现仍应发送明确版本
Extension 在既有绑定上增加数据或语义;Agent 用 URI 在 capabilities.extensions 中声明 Extension,客户端通过 A2A-Extensions 选择使用
Custom Binding 定义新的传输方式,例如 WebSocket,并负责给出全部标准操作的调用、认证、错误和流式语义;Extension 或 Custom Binding 发生破坏性变更时,应更换 URI
定义见 Extensions 与 Custom Protocol Bindings
A2A、MCP 与 AG-UI
A2A、MCP 与 AG-UI 的差别在通信边界:
| 协议 | 通信双方 | 主要对象 | 解决的问题 |
|---|---|---|---|
| A2A | Agent 与 Agent | Agent Card、Message、Task、Artifact | 委托并追踪一项远程工作 |
| MCP | Agent 与工具或数据源 | Tool、Resource、Prompt | 调用结构化能力并取得上下文 |
| AG-UI | Agent Backend 与前端 | 事件、状态、消息、前端工具 | 把执行过程传递给用户界面 |
前端通过 AG-UI 与主 Agent 通信,主 Agent 用 A2A 委托研究任务;远端研究 Agent 需要搜索、数据库或文件能力时,在内部调用 MCP Server
研究结果以 A2A Artifact 返回,主 Agent 再把状态和内容转换成前端事件
MCP 工具调用属于 Agent 的内部实现,A2A Task 才是两个独立 Agent 之间的责任边界
A2A 与 MCP 的关系见 A2A and MCP,AG-UI 的事件定义见 AG-UI 文档
实现要求与契约测试
/message:send 返回成功,只能证明端点可以收发 JSON;互操作性测试还要覆盖连接中断、重复投递、补充输入和版本不一致
服务端的最小闭环包括 Agent Card、Send Message、Task 持久化、Get Task 和 Artifact
Streaming、Push Notification、Extended Agent Card 都是可选能力,但 Card 一旦声明支持,就必须实现对应操作
客户端至少要读取 Card、选择接口、处理 Message 与 Task 两种返回、保存 contextId 和 taskId,并用结构化状态和错误驱动控制流
契约测试至少覆盖下列场景:
| 测试 | 应观察到的结果 |
|---|---|
| Card 提供多个绑定 | 客户端按顺序选择自己支持的第一项,不猜测地址 |
| Send Message 分别触发即时与长任务 | 客户端能处理 Message、Task 两种互斥返回 |
| Task 进入 INPUT_REQUIRED | 补充消息使用相同 taskId,任务继续运行 |
taskId 与 contextId 不匹配 | 服务端拒绝请求,不把消息挂到错误上下文 |
| SSE 在 Artifact 分块中途断开 | Get Task 能重新取得权威状态和已有 Artifact |
| Webhook 被重复投递 | 接收方去重,业务结果只提交一次 |
| 越权查询一个真实 Task | 响应不泄露资源是否存在及其所有者 |
发送不支持的 A2A-Version | 返回 VersionNotSupportedError,不静默解释成别的版本 |
还要验证终态 Task 不能继续或重新订阅,未声明的 streaming 与 push 返回相应错误,取消与重复 Message 具有可预测的幂等行为
这些异常路径定义 SDK 与服务端之间的契约边界
0.3 与 1.0 的差异
A2A 1.0 修改了 0.3 的方法名、Part 模型、枚举和接口发现方式;使用旧教程或旧 SDK 示例前,先确认协议版本
| 0.3 常见形式 | 1.0 形式 |
|---|---|
message/send | SendMessage |
message/stream | SendStreamingMessage |
tasks/get | GetTask |
tasks/cancel | CancelTask |
tasks/resubscribe | SubscribeToTask |
Part 带 kind,文件再嵌套一层 | Part 直接使用 text/raw/url/data oneof |
working、user 等小写枚举 | TASK_STATE_WORKING、ROLE_USER |
流事件靠 kind 或 final 判断 | 由 oneof 字段名区分,终态后关闭流 |
| Card 顶层 URL、transport、protocolVersion | 有序 supportedInterfaces |
标准 HTTP 路径带固定 /v1 | 1.0 标准 Endpoint 不含版本前缀 |
1.0 还增加了 List Tasks、接口级 tenant、Card 的 JWS/JCS 处理,并统一推送配置操作的命名;字段级差异见 What's New in v1.0
迁移层先根据 Agent Card 与 A2A-Version 确定协议版本,再进入对应的 0.3 或 1.0 编解码层,最后转换成应用内部的统一 Task 模型
0.3 与 1.0 不应共用一个反序列化类,否则版本判断会散落到业务路径中
互操作性判定
A2A 实现的合格标准是 Task 语义能够跨连接、跨进程恢复
Agent Card 给出调用契约,Message 发起或继续交互,Task 记录生命周期,Artifact 保存正式结果
SSE 断开、Webhook 重复、任务要求补充输入、调用方没有资源权限、双方协议版本不同,这些条件下都必须保持同一套 Task 语义;任何一种情况仍依赖本地约定或自然语言猜测,这个实现就不具备 A2A 互操作性
最低判定标准只有三个问题:当前是哪项任务,任务处于什么状态,最终结果存放在哪里;调用双方必须始终给出一致答案