从“断流”到“长流”:A2A 协议如何用 SSE 与推送让 AI 任务永不下线
关键词:A2A 协议、Server-Sent Events、Push Notification、长任务、实时推送、Webhook、SSRF、JWT、微服务
开场 3 行说清楚
- 还在用轮询看 AI 任务跑完没?又慢又费钱。
- A2A 协议把「长任务」拆成两条路:
- SSE 流式——实时吐结果,像追番;
- 推送通知——离线也能收快递,像点外卖。
- 今天一文带你配好这两条“高速公路”,附赠防 SSRF、JWT 旋转全套安全秘籍。
1. 场景速写:当你的 AI 任务需要“马拉松”
| 场景 | 耗时 | 体验痛点 |
|---|---|---|
| 生成长文档 | 几分钟 | 用户盯空白页,心态炸裂 |
| 视频摘要 | 十几分钟 | 移动端切后台,WebSocket 断 |
| 金融风控模型 | 几小时 | 函数计算 15 min 超时,直接被杀 |
A2A 协议给出的答案:
「让客户端决定是挂电话(推送)还是保持通话(SSE)。」
2. SSE:把“等结果”变成“边跑边看”
2.1 建立一条永不打烊的单向流
POST /rpc/message/stream HTTP/1.1
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 101,
"method": "message/stream",
"params": {
"prompt": "请给我 10 万字的《三体》同人小说",
"stream": true
}
}
服务器立刻回:
HTTP/1.1 200 OK
Content-Type: text/event-stream
event: message
data: {"jsonrpc":"2.0","id":101,"result":{"type":"TaskStatusUpdateEvent","state":"working","message":"正在思考黑暗森林法则..."}}
随后每生成一段就吐一段,直到:
{"type":"TaskStatusUpdateEvent","state":"completed","final":true}
客户端即可 close(),优雅结束。
2.2 断线自动续命
| 断网场景 | 客户端动作 | Server 策略 |
|---|---|---|
| 地铁进隧道 | tasks/resubscribe | 可选重放丢失事件 |
| 浏览器刷新 | 同上 | 仅推送新事件 |
小贴士:在 Agent Card 里把
capabilities.streaming: true亮出来,客户端就知道你能“追剧”。
3. Push Notification:让服务器做“外卖小哥”
3.1 配好地址与暗号
客户端在一次普通请求里夹带私货:
"pushNotification": {
"url": "https://my-callback.example.com/a2a/webhook",
"token": "task-xyz-42",
"authentication": {
"type": "Bearer",
"tokenEndpoint": "https://auth.example.com/oauth2/token"
}
}
服务器把任务状态变化 POST 到 url,附赠:
X-A2A-Notification-Token: task-xyz-42
Authorization: Bearer <JWT>
3.2 收到快递后,客户端再取货
- 服务端回调:任务已完成
- 客户端立即
GET /rpc/tasks/get?id=task-xyz-42拉完整结果。 - 移动端可把这条消息再转成本地推送,用户甚至没打开 App。
4. 安全攻防:别让 Webhook 变成 SSRF 炮灰
4.1 服务端:别乱敲门
- 域名白名单:只允许
.example.com、.mycompany.cn - 挑战-应答:首次配置时
GET ?validationToken=uuid,必须回显 uuid - 出口防火墙:限制 A2A Server 只能访问 443 端口且目标域名经过解析校验
4.2 客户端:验明正身
| 校验维度 | 实现示例 |
|---|---|
| 身份 | 校验 JWT iss, aud,用 JWKS 动态拉公钥 |
| 时效 | 拒绝 iat 超过 5 min 的旧通知 |
| 去重 | jti 写入 Redis SET,TTL 30 min |
| 授权 | 对比 X-A2A-Notification-Token 与本地任务 token |
示例代码(Node.js):
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
const client = jwksClient({ jwksUri: 'https://a2a-server.example.com/.well-known/jwks.json' });
const cert = await client.getSigningKey(kid);
jwt.verify(token, cert.getPublicKey(), {
issuer: 'a2a-server.example.com',
audience: 'my-webhook.example.com',
maxAge: '5m'
});
5. 场景选型速查表
| 场景 | 推荐模式 | 原因 |
|---|---|---|
| Web 端实时聊天 | SSE | 双向流量小,延迟 <1 s |
| 移动 App 视频摘要 | Push | 避免长连接费电 |
| Serverless 批处理 | Push | 15 min 超时限制 |
| 企业内网长任务 | SSE + mTLS | 内网稳定,双向证书更可信 |
6. 5 分钟跑通 Demo
6.1 启动 A2A 兼容 Server(Python 示例)
pip install a2a-protocol[examples]
export A2A_WEBHOOK_ALLOWLIST="https://*.example.com"
a2a-server --streaming --push
6.2 客户端订阅 SSE
curl -N -H "Accept:text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"message/stream","params":{"prompt":"写首诗"}}' \
http://localhost:8080/rpc/message/stream
6.3 再试推送
curl -X POST http://localhost:8080/rpc/message/send \
-d '{"jsonrpc":"2.0","id":2,"method":"message/send","params":{"prompt":"写首诗","pushNotification":{"url":"https://webhook.site/unique-id"}}}'
7. 结语:让长任务像短视频一样顺滑
A2A 协议把「长任务」从同步阻塞的泥潭里捞出来:
- 有网就 SSE,像追番;
- 没网就推送,像外卖。
746

被折叠的 条评论
为什么被折叠?



