用 A2A 把工单分析交给专长 Agent:一次完整的任务交接
一个客服系统里有两个 Agent:协调 Agent 面向用户,会判断"这张工单该给谁";工单分析 Agent 是专长 Agent,擅长定位根因并给出处理建议。它们之间用 A2A 交接任务。工单数据在哪里、工具怎么调、权限怎么批,发生在专长 Agent 内部(那里用的是 MCP,见文末边界)——A2A 管的是两个 Agent 之间的事:发现、任务状态、消息、产出物和恢复。
前置阅读:状态与消息语义见Task 运行时指南 ,幂等与恢复模式见任务幂等与恢复 。这里把它们放进同一个场景走一遍。
走查总览
sequenceDiagram
participant U as 用户
participant C as 协调 Agent(A2A 客户端)
participant S as 工单分析 Agent(A2A 服务端)
U->>C: "这张工单什么问题?"
C->>S: 读取 /.well-known/agent-card.json(发现)
C->>S: message/send(分析请求,messageId=m1)
S-->>C: Task(SUBMITTED)
S-->>C: Task(WORKING)
S-->>C: Task(INPUT_REQUIRED):缺复现步骤
C->>S: message/send(补充信息,messageId=m2,同 contextId)
S-->>C: Task(WORKING)
S-->>C: Artifact:结构化分析报告(分块,lastChunk)
S-->>C: Task(COMPLETED) + 结论 Message
C-->>U: 根因与建议
1. 发现:按技能选,不只看名字
协调 Agent 从 /.well-known/agent-card.json 读取卡片,用三条信息做决定:
| 看什么 | 本场景的判定 |
|---|---|
skills | 有没有"工单 / 根因分析"相关技能;技能的 tags 比名字更可靠 |
capabilities | streaming 或 pushNotifications 至少一个为 true,长时间分析才不会盲等 |
securitySchemes / securityRequirements | 自己有没有对应的凭据去调用 |
发现机制与卡片字段见智能体发现 与Agent Card 实现指南 。协调 Agent 应当缓存卡片并尊重其缓存窗口,而不是每次交接都重新发现。
2. 发起:把幂等键放进第一条消息
{
"jsonrpc": "2.0",
"id": "req-101",
"method": "message/send",
"params": {
"message": {
"role": "role_user",
"parts": [{ "kind": "text", "text": "分析工单 TCK-4821:客户报告结账后订单状态未更新" }],
"messageId": "coord-4f21-m1",
"contextId": "ctx-tck4821"
}
}
}两个决定此时做出,之后不再改:
messageId含上游标识(工单号):超时重发时原样重发同一个值,服务端用它与(contextId)一起识别重复,不会重新分析一遍;contextId用工单号命名:这张工单后续所有任务(重新分析、补充材料、升级处理)都在同一上下文里,对话历史与归属可查。
服务端返回 Task(SUBMITTED 或 WORKING),记下 taskId——它是后续所有操作的对象。
3. 跟踪:每个状态对应协调 Agent 的一个动作
| 任务状态 | 协调 Agent 做什么 |
|---|---|
SUBMITTED / WORKING | 等待;已订阅事件流或推送则被动接收,否则按退避 GetTask |
INPUT_REQUIRED | 向用户要信息,拿到后作为新 messageId 的消息发回同一任务 |
AUTH_REQUIRED | 按任务状态消息说明的授权去完成(联系审批人或带外授权),见安全实现 第 4 节 |
COMPLETED | 读取 Artifact 与最终 Message,交给用户 |
FAILED / CANCELED / REJECTED | 按原因决定:重试(新任务同 contextId)、换 Agent 或上报 |
本场景在 INPUT_REQUIRED 停了一次:分析 Agent 要复现步骤。协调 Agent 向用户取回后在同一个任务上继续:
{
"jsonrpc": "2.0",
"id": "req-102",
"method": "message/send",
"params": {
"message": {
"role": "role_user",
"parts": [{ "kind": "text", "text": "复现步骤:下单后 30 秒内刷新两次订单页" }],
"messageId": "coord-4f21-m2",
"taskId": "task-9c31",
"contextId": "ctx-tck4821"
}
}
}messageId 是新的(这是新输入,不是重发),taskId 与 contextId 保持不变。
4. 接收:报告是 Artifact,结论是 Message
分析结果分两层到达:
- Artifact(结构化报告):根因、置信度、受影响订单清单、建议动作。流式交付时分块到达,以
lastChunk: true结束;协调 Agent 按artifactId聚合,不假设块数; - Message(最终说明):一段给协调 Agent 转述给用户的自然语言结论。
{
"jsonrpc": "2.0",
"id": "req-103",
"method": "tasks/get",
"params": { "taskId": "task-9c31" }
}Task.artifacts 里的报告与 Task.status.message 里的结论一起构成完整交付。字段细节见 Artifact 对象页
与Message 对象页
。
5. 恢复:协调 Agent 的核对清单
走查中任何一步都可能断,逐项核对:
| 观察 | 动作 |
|---|---|
message/send 超时,不知是否送达 | 原样重发(同 messageId);服务端幂等返回首次结果 |
| 事件流中途断开 | SubscribeToTask 重连;不支持续传时对重复事件按序号去重 |
| 只能轮询 | GetTask 退避轮询直到终态;不把流断开当任务失败 |
WORKING 超过工单时限 | CancelTask,然后在同 contextId 下发新任务(终态任务不可重启) |
| 交接链上还要授权 | 把自己的任务转 AUTH_REQUIRED 向上委托,凭据绑定发起方 |
| 分析 Agent 不可用 | 用缓存卡片里的其他接口重试一次,仍失败则按发现机制换 Agent,并在新 contextId 记录交接原因 |
恢复的完整决策树与探针见任务幂等与恢复 ;推送通道的加固见推送接收方加固 。
边界:MCP 那一侧
工单分析 Agent 内部用 MCP 读取工单系统的数据、调用受控工具(退款查询、订单状态 API),并把权限失败映射为 A2A 的 AUTH_REQUIRED 或 FAILED。这些属于 MCP 的职责边界:MCP Server / Client、工具与资源、最小权限、调用失败与可观察结果,见 MCP 中文站的对应实践
。两个协议分工的总览见A2A 与 MCP
。
相关页面
- Task 运行时指南 :状态规则与事件流校验
- 任务幂等与恢复 :本场景引用的幂等与恢复模式
- 智能体发现 :卡片发现机制
- A2A 与 MCP:详细对比 :两个协议的边界总览
版本与验证说明
对齐 A2A v1.0.1。消息、任务与产出物字段以数据结构
为准;序列图与核对清单由本场景的消息流组成,可直接作为验收清单逐项核对。messageId、contextId 的取值模式是本站建议,协议只要求由发送方生成。