流式传输与异步操作
A2A 协议明确面向可能无法立即完成的任务而设计。许多 AI 驱动的操作耗时较长、包含多个步骤、产生增量结果,或需要人工介入。A2A 提供管理这类异步交互的机制,确保无论客户端保持连接还是断开连接,都能有效收到更新。
基于 SSE 的流式传输
对于产生增量结果(如生成长文档、流式媒体)或持续提供状态更新的任务,A2A 支持使用服务器发送事件(SSE)进行实时通信,适合客户端可以保持活跃 HTTP 连接的场景。
- 服务端能力声明:A2A 服务器必须在 Agent Card 中设置
capabilities.streaming: true,表明支持流式传输。 - 发起流:客户端使用
SendStreamingMessage发送初始消息(例如提示词或命令),同时订阅该任务的更新。 - 服务端响应与连接:订阅成功时,服务器返回 HTTP 200 以及
Content-Type: text/event-stream,该连接保持打开,由服务器向客户端推送事件。 - 事件结构与类型:每个事件携带一个
StreamResponse,其载荷是以下四种之一:task(Task):任务当前状态的快照;message(Message):智能体返回的消息;statusUpdate(TaskStatusUpdateEvent):任务生命周期状态的变化(例如从 working 变为 input-required 或 completed),也可携带智能体的中间消息;artifactUpdate(TaskArtifactUpdateEvent):任务产生的新增或更新的产出物,可用于分块流式传输大文件或大型数据结构,并通过append、lastChunk等字段帮助重新组装。
- 流的终止:当任务进入终态或中断状态(如
TASK_STATE_COMPLETED、TASK_STATE_FAILED、TASK_STATE_CANCELED、TASK_STATE_REJECTED或TASK_STATE_INPUT_REQUIRED)时,服务器关闭流,不再发送更新。 - 重新订阅:如果任务仍在进行而 SSE 连接意外中断,客户端可以通过
SubscribeToTask尝试重新连接到该流。
事件在不同协议绑定中的封装方式有所不同:
| 绑定 | 流式传输方式 | 每个事件的内容 |
|---|---|---|
| JSON-RPC 2.0 | SSE(text/event-stream) | data 字段是一个 JSON-RPC 响应对象,其 result 为 StreamResponse |
| HTTP+JSON/REST | SSE(text/event-stream) | data 字段直接是 StreamResponse JSON 对象 |
| gRPC | 服务端流式 RPC | 每条流消息是一个 StreamResponse |
下面是 HTTP+JSON 绑定下的 SSE 响应示例:
HTTP/1.1 200 OK
Content-Type: text/event-stream
data: {"task": {"id": "task-uuid", "contextId": "context-uuid", "status": {"state": "TASK_STATE_WORKING"}}}
data: {"artifactUpdate": {"taskId": "task-uuid", "contextId": "context-uuid", "artifact": {"parts": [{"text": "# Climate Change Report\n\n"}]}}}
data: {"statusUpdate": {"taskId": "task-uuid", "contextId": "context-uuid", "status": {"state": "TASK_STATE_COMPLETED"}}}何时使用流式传输
- 实时监控长任务的进度;
- 增量接收大型结果(产出物);
- 需要即时反馈或部分响应的交互式、对话式场景;
- 需要智能体低延迟更新的应用。
面向断开连接场景的推送通知
对于耗时非常长的任务(几分钟、几小时甚至几天),或者客户端无法或不愿保持持久连接(如移动端、无服务器函数)的场景,A2A 支持通过推送通知进行异步更新:在任务发生重要变化时,A2A 服务器主动通知客户端提供的 Webhook。
- 服务端能力声明:A2A 服务器必须在 Agent Card 中设置
capabilities.pushNotifications: true。 - 配置:客户端向服务器提供一个
TaskPushNotificationConfig,可以在初始的SendMessage/SendStreamingMessage请求中携带,也可以针对已有任务单独调用CreateTaskPushNotificationConfig。配置包含url(HTTPS Webhook 地址)、可选的token(供客户端校验)以及可选的authentication(A2A 服务器向 Webhook 认证所用,包含scheme与credentials)。 - 触发时机:由 A2A 服务器决定何时发送,通常在任务发生重要状态变化时(例如进入终态、
input-required或auth-required)。 - 通知载荷:HTTP 请求体是一个
StreamResponse对象,与流式操作使用的格式一致,包含task、message、statusUpdate、artifactUpdate之一。 - 客户端动作:收到推送通知并验证其真实性后,客户端通常用通知中的
taskId调用GetTask,取回包含新产出物的完整、最新的Task。
何时使用推送通知
- 可能持续数分钟、数小时甚至数天的超长任务;
- 无法或不愿保持持久连接的客户端,如移动应用或无服务器函数;
- 只需要在重要状态变化时被通知,而不需要持续更新的场景。
客户端的推送通知服务
TaskPushNotificationConfig.url 指向客户端一侧的推送通知服务,负责接收 A2A 服务器发来的 HTTP POST 通知,并完成认证、相关性校验,再把通知或其内容转交给相应的客户端应用逻辑。
推送通知的安全注意事项
推送通知是异步且由服务器主动向外发起的,因此安全至关重要,A2A 服务器(发送方)和客户端 Webhook(接收方)都要承担关键职责。
A2A 服务器(向客户端 Webhook 发送通知时)
- 校验 Webhook URL:服务器不应盲目信任并向客户端提供的任意 URL 发送 POST 请求。恶意客户端可能提供指向内部服务或无关第三方系统的 URL,导致服务器端请求伪造(SSRF),或被用作 DDoS 放大器。缓解措施包括:域名白名单、归属权验证(如挑战-应答机制)、网络控制(如出站防火墙)。
- 向客户端 Webhook 认证:A2A 服务器必须按
TaskPushNotificationConfig.authentication指定的方案向客户端 Webhook URL 证明自己的身份。常见方案包括 Bearer 令牌(OAuth 2.0)、API Key、HMAC 签名或双向 TLS(mTLS)。
客户端 Webhook(接收通知时)
- 认证 A2A 服务器:Webhook 端点必须严格验证通知请求的真实性,确保来自合法的 A2A 服务器而非冒充者。验证方式包括校验签名或令牌(例如用 A2A 服务器受信任的公钥验证 JWT 签名、HMAC 签名或 API Key),若提供了
TaskPushNotificationConfig.token,还应校验该令牌。 - 防止重放攻击:通知应包含时间戳,Webhook 应拒绝过旧的通知;对关键通知,可考虑使用唯一的一次性标识(如 JWT 的
jti声明或事件 ID),避免重复处理。 - 密钥的安全管理与轮换:实施安全的密钥管理,尤其是定期轮换加密密钥;JWKS(JSON Web Key Set)等协议便于非对称密钥的轮换。
非对称密钥流程示例(JWT + JWKS)
- 客户端创建
TaskPushNotificationConfig,指定authentication.scheme: "Bearer",并可约定 JWT 预期的issuer或audience。 - A2A 服务器发送通知时:用私钥签发 JWT,包含
iss、aud、iat、exp、jti和taskId等声明;JWT 头部标明签名算法和密钥 ID(kid);服务器通过 JWKS 端点公开公钥。 - 客户端 Webhook 收到通知后:从 Authorization 头提取 JWT;检查头部中的
kid;从 A2A 服务器的 JWKS 端点获取对应公钥(建议缓存);用公钥验证 JWT 签名;校验iss、aud、iat、exp、jti等声明;若提供了TaskPushNotificationConfig.token,同时校验。
这种分层的安全设计有助于保证推送通知真实、完整、及时,同时保护发送方 A2A 服务器和接收方客户端 Webhook 的基础设施。