上一篇讨论了 Agent 之间如何交接工作。
一个 Agent 完成任务后,可以通过 Message 沟通过程信息,通过 Task 表达正在处理的工作,再通过 Artifact 交付正式结果。
解决了“传什么”,本文继续讨论 Agent 和外部能力之间,以及 Agent 之间,具体应以什么方式协作。
比如,一个 Agent 要查询数据库,可以直接调用 API,也可以通过 MCP 使用数据库工具;如果它无法独立完成任务,还可能把工作交给另一个专业 Agent。
这几种情况看起来都是“调用”,实际面对的问题并不相同。
一、Agent 系统的三类交互方式
先看 Agent 系统中最常见的三种情况。
第一种是直接调用已有服务:
Agent
|
| REST / RPC
v
业务服务
例如客服 Agent 查询订单:
GET /orders/{id}
如果服务地址固定、接口明确,直接使用 REST 或 RPC 已经足够。
第二种是 Agent 使用外部工具:
Agent
|
| MCP
v
MCP Server
|
v
数据库 / 搜索 / 文件 / 业务系统
这里 Agent 关心的是:
当前有哪些工具
每个工具有什么用途
需要哪些参数
会返回什么结果
这属于 MCP 主要解决的范围。
第三种是两个独立 Agent 之间协作:
Agent A
|
| A2A
v
Agent B
Agent A 面对的已经不是一个简单工具,而是另一个可以独立完成任务的 Agent。
它可能有自己的模型、Prompt、工具和运行状态,甚至由另一个团队开发和部署。
此时需要了解的是:
对方具备哪些能力
怎样提交任务
任务当前是什么状态
最终能够得到什么结果
这属于 A2A 主要解决的范围。
A2A(Agent2Agent Protocol)是由 Google 发起、现由 Agentic AI Foundation 推进的开放标准,用于让不同厂商、框架和语言实现的 AI Agent 能够发现彼此能力、交换消息、委派和跟踪任务,并交付结构化结果,从而实现跨系统的 Agent 协作与互操作。
因此,REST/RPC、MCP 和 A2A 面向的是不同场景,不需要互相替代。
二、MCP 的工具接入机制
假设我们正在开发一个客服 Agent,它需要:
查询客户资料
查询订单
搜索知识库
创建工单
读取退款记录
传统做法通常是分别调用各个系统的 API,再在 Agent 中维护相应的函数和参数定义。
调用工具较少时,这种方式没有问题。
随着工具越来越多,会变得越来越不易维护。
每个工具怎样描述自己的用途?参数格式放在哪里?不同 Agent 是否都要重复开发适配代码?模型怎样知道当前有哪些工具可用?
MCP 为这些问题提供了一套统一方式。
外部系统可以通过 MCP Server 暴露能力,Agent 一侧通过 MCP Client 获取并使用这些能力。
其调用流程如下:
Agent
|
MCP Client
|
| MCP
v
MCP Server
|
+-- Tool A
+-- Tool B
+-- Tool C
其中最值得关注的是 Tool。
一个 Tool 通常需要说明:
工具名称
工具用途
输入参数
返回结果
例如,一个查询发票的工具可以描述为:
{
"name": "get_invoice",
"description": "根据发票编号查询发票信息",
"inputSchema": {
"type": "object",
"properties": {
"invoice_id": {
"type": "string"
}
},
"required": ["invoice_id"]
}
}
这里的 name 是工具名称,description 说明用途,inputSchema 定义参数结构。
Agent 获取这些信息后,就能知道当前有哪些工具,以及调用时应该提供什么参数。
因此,MCP 能够让 Agent 以统一方式认识和使用外部能力。
至于 Tool 背后调用 PostgreSQL、REST API,还是企业内部服务,并不是 Agent 必须了解的内容。
三、A2A 的 Agent 协作机制
假设客服 Agent 收到用户的问题:
我的退款已经申请五天了,为什么还没有到账?
Customer Agent 可以处理普通客服问题,但退款调查由 Billing Agent 负责。
于是任务会转交给 Billing Agent:
Customer Agent
|
| A2A
v
Billing Agent
Customer Agent 不需要知道 Billing Agent 使用什么模型,也不需要了解它内部有哪些 Prompt 和工具。
它更关心:
Billing Agent 是否能处理退款问题
任务应该怎样提交
当前处理到哪一步
结束后会返回什么
A2A 主要解决的正是这类 Agent 之间的协作问题。
其中有几个核心概念:
Agent Card
Task
Message
Artifact
它们分别解决能力描述、任务状态、过程沟通和结果交付等问题。
四、Agent Card 的能力描述
A2A 使用 Agent Card 描述 Agent 对外提供的信息和能力。
可以把它理解为 Agent 的服务说明。
例如:
{
"name": "Billing Resolution Agent",
"description": "处理账单和退款相关问题",
"skills": [
{
"name": "refund_investigation"
},
{
"name": "invoice_query"
}
]
}
其中,skills 表示这个 Agent 对外提供的能力。
真实的 Agent Card 还可以包含访问地址、支持的交互方式和安全相关信息。
这样,系统面对一个新任务时,可以先确认:
有哪些 Agent
各自擅长什么
哪个 Agent 能处理当前任务
确定目标之后,再进入具体的任务交互。
五、Task 的任务状态管理
在 Agent 内部,Tool 调用通常比较直接:
get_invoice("INV-1001")
↓
返回发票信息
但 Agent 接到的往往是一项需要持续处理的工作。
例如:
调查这笔退款为什么迟迟没有到账,
检查支付记录、退款状态和客服历史,
最后给出处理结果。
Billing Agent 可能需要连续访问多个系统,中途还可能等待新的信息。
因此,A2A 使用 Task 表示一项正在处理的任务。
一个 Task 可能经历类似这样的状态变化:
submitted
|
v
working
|
v
completed
有些任务还可能进入等待输入、失败或取消等状态。
这里体现了 Agent 与普通函数调用的一个明显区别。
函数通常关注:
请求
↓
结果
Agent 协作还需要知道:
任务是否已经开始
当前进行到哪一步
是否需要额外信息
最终是否完成
对于耗时较长的任务,系统还可以通过 Streaming、订阅状态变化或通知机制持续获得进展,而不必一直等待一个同步请求返回。
六、Artifact 的结果形态
任务完成之后,还需要交付结果。
如果只是简单回复:
退款正在处理中
Message 已经足够。
但 Agent 的正式产出可能是一份报告、一段结构化数据,甚至一个文件。
例如 Billing Agent 最终生成:
Refund Investigation Report
- 退款申请时间
- 支付渠道状态
- 当前退款状态
- 异常原因
- 建议处理方式
这类可以继续被其他系统使用的正式结果,可以通过 Artifact 表达。
因此,上述几个概念的职责如下:
Agent Card
描述“我具备什么能力”
Task
表示“当前正在处理什么工作”
Message
承载任务过程中的沟通
Artifact
保存任务产生的正式结果
这也与上一篇中介绍的 Agent 交付内容完全一致。
上一篇关注 Agent 之间交接什么,这里进一步关注这些内容怎样在独立 Agent 之间流转。
七、MCP 与 A2A 的组合结构
MCP 和 A2A 并不冲突。
它们很可能同时出现在一个系统中。
继续使用前面的客服场景:
Customer Agent
|
| A2A
v
Billing Resolution Agent
|
+---- MCP ----> CRM
|
+---- MCP ----> Invoice Database
|
+---- MCP ----> Ticket System
用户询问退款问题后,Customer Agent 判断自己无法完成完整调查,于是通过 A2A 把任务交给 Billing Resolution Agent。
Customer Agent 关心:
Billing Agent 擅长什么
怎样提交 Task
当前处理到哪一步
最终返回什么 Artifact
Billing Agent 接到任务后,需要查询客户资料、发票和客服工单。
这时它通过 MCP 使用对应工具:
get_customer()
get_invoice()
search_tickets()
Billing Agent 关心:
有哪些 Tool
每个 Tool 需要哪些参数
调用后返回什么数据
所以,同一个系统中,两种协议承担的是不同职责:
Agent
|
| A2A
| Agent 之间的任务协作
v
Agent
|
| MCP
| Agent 对外部能力的使用
v
Tool / Data / API
八、不同交互方式的适用边界
实际工程中,我们应根据不同场景选择不同的调用方式。
| 场景 | 适合方式 | 主要原因 |
|---|---|---|
| 同一程序中的固定逻辑 | 函数 / 模块调用 | 简单直接,没有网络交互 |
| 已知的内部业务服务 | REST / RPC | 地址和接口稳定 |
| Agent 使用搜索、数据库、文件 | MCP | 工具可以统一描述和使用 |
| 独立 Agent 之间的任务委托 | A2A | 需要能力描述和任务状态 |
| 跨团队的 Agent 协作 | A2A | 双方无需了解内部实现 |
| Agent 内部使用多个外部工具 | MCP | 工具可以独立接入和复用 |
如果当前对象提供一个明确、清晰的能力,例如:
查询订单
搜索文档
创建工单
读取数据库
它应该以 Tool 的方式实现。
如果当前对象能够:
接收完整任务
自行组织执行过程
调用多个工具
维护任务状态
返回完整结果
它应以 Agent 形式实现。
总结
Agent 系统中常见三种交互方式:直接调用 API、通过 MCP 使用工具,以及通过 A2A 与另一个 Agent 协作。
MCP 更关注工具和资源接入。它让 Agent 知道有哪些能力、需要哪些参数,以及调用后能够得到什么结果。
A2A 面向独立 Agent 之间的协作。Agent Card 描述能力,Task 表示正在处理的工作,Message 负责过程沟通,Artifact 承载正式结果。
在完整的 Multi-Agent 系统中,两者往往同时存在:
Agent A
|
A2A
|
Agent B
|
MCP
|
Tools / Data / APIs
因此,系统设计中首先需要分清的是:当前对象是供 Agent 使用的一项能力,还是一个能够独立接收并完成任务的 Agent。边界确定后,就能够确定适合的交互方式。
社区讨论
参与讨论
有问题或想法?欢迎继续讨论。