MCP协议解决了Agent与工具、数据源之间的标准化连接问题,让Agent能够通过统一协议调用被动的工具服务。但在复杂的AI应用场景中,我们往往需要让多个具备自主决策能力的Agent协同工作——比如擅长技术资料收集分析的研究型Agent、能将结论转化为专业文档的写作型Agent、专注于代码安全审查的检测型Agent。当这些不同能力的Agent需要配合完成任务时,它们之间该如何沟通、如何发现彼此、如何传递工作?这正是A2A(Agent-to-Agent)协议要解决的核心问题。
简单来说,MCP实现的是Agent与工具的垂直集成(Agent主动调用工具),而A2A实现的是Agent与Agent的水平协作(Agent委托任务给其他Agent),二者互为补充,共同构建完整的Agent生态交互体系。
A2A协议的三个核心概念
1. AgentCard:Agent的"能力名片"
每个Agent都会发布一张机器可读的AgentCard,相当于Agent的能力声明,类似于OpenAPI Spec对于API服务的作用。它清晰描述了Agent的身份、核心能力和技能标签,是其他Agent发现和调用它的基础。
from a2a.types import AgentCard, AgentSkill
def make_skill(skill_id, name, description, tags):
s = AgentSkill()
s.id = skill_id
s.name = name
s.description = description
s.tags.extend(tags)
return s
research_card = AgentCard()
research_card.name = "research-agent"
research_card.description = "Gathers factual background on technical topics"
research_card.skills.append(
make_skill("research", "Research", "Collect key facts on a topic", ["research", "facts"])
)
AgentCard的关键字段包括name(唯一标识)、description(能力概述)和skills(技能列表),其中每个技能的tags字段是实现Agent自动发现的关键。
2. Task:标准化的工作单元
Agent之间传递的不是简单的函数调用,而是带有完整生命周期的Task对象。Task封装了任务输入、执行历史、状态信息和最终结果,支持异步执行和上下文传递。
from a2a.types import Task, TaskState, TaskStatus, Message, Part, Role
import uuid
task = Task()
task.id = str(uuid.uuid4())
task.status.state = TaskState.TASK_STATE_SUBMITTED
# 输入:User角色的Message
msg = Message()
msg.role = Role.ROLE_USER
part = Part(); part.text = "Should I use Python or Go?"
msg.parts.append(part)
task.history.append(msg)
Task拥有完整的生命周期状态流转:SUBMITTED(已提交)→ WORKING(执行中)→ COMPLETED(已完成)/ FAILED(执行失败)。任务完成后,执行Agent会将结果以ROLE_AGENT角色的Message追加到Task的历史记录中。
3. Registry:Agent的"服务黄页"
AgentRegistry是A2A协议的服务注册与发现中心,存储了所有已注册Agent的AgentCard信息,支持按技能标签批量发现符合要求的Agent,也支持按名称精确调用。
class AgentRegistry:
def register(self, card: AgentCard, handler: Callable[[Task], Task]) -> None:
self._agents[card.name] = AgentEntry(card=card, handler=handler)
def discover(self, tag: str) -> list[AgentCard]:
"""返回所有skill包含指定tag的Agent"""
...
def delegate(self, agent_name: str, input_text: str) -> Task:
"""创建Task并通过注册的handler执行"""
...
A2A协议的三种实践模式
模式1:直接调用(简单但高耦合)
没有标准化协议时,我们通常会在编排器中硬编码各个Agent的调用逻辑,直接调用对应的函数。
def direct_orchestrator(question: str) -> str:
research = research_agent_fn(question) # 硬依赖
analysis = analysis_agent_fn(research) # 硬依赖
answer = writing_agent_fn(analysis) # 硬依赖
return answer
这种方式虽然实现简单,但存在严重的耦合问题:替换任何一个Agent都需要修改编排器代码,跨服务场景下维护成本极高。
模式2:基于AgentCard注册表的解耦调用
通过A2A的Registry机制,编排器不再硬编码Agent名称,而是通过技能标签动态发现符合要求的Agent,实现了调用方与执行方的解耦。
首先将三个Agent注册到Registry并标注对应的技能标签:
[registry] registered: research-agent
[registry] registered: analysis-agent
[registry] registered: writing-agent
编排器通过标签发现并委托任务:
def a2a_orchestrator(question: str) -> str:
researchers = registry.discover("research")
t1 = registry.delegate(researchers[0].name, question)
analysts = registry.discover("analysis")
t2 = registry.delegate(analysts[0].name, task_output(t1))
writers = registry.discover("writing")
t3 = registry.delegate(writers[0].name, task_output(t2))
return task_output(t3)
这种模式的核心优势在于零代码升级:当我们注册一个带有相同writing标签的writing-agent-v2时,编排器会自动发现并使用新版本,无需修改任何代码。
模式3:LLM驱动的自主路由(A2A的终态)
A2A协议最强大的能力,是让LLM读取AgentCard目录,根据任务需求自主决定调用哪些Agent、按什么顺序执行,完全无需预先编写编排逻辑。
向LLM展示精简后的Agent目录:
Available agents:
research-agent: Gathers factual background [skills: Research(research, facts)]
analysis-agent: Analyzes research notes [skills: Analysis(analysis, tradeoffs)]
writing-agent: Composes technical prose [skills: Writing(writing, prose)]
LLM会自动生成执行计划:
["research-agent", "analysis-agent", "writing-agent"]
系统按照LLM生成的计划自动执行任务,最终返回结果。这种模式实现了真正的动态协作,Agent系统能够根据任务复杂度自主调整协作链路。
协议选型对比与场景推荐
MCP vs A2A核心差异
| 维度 | MCP协议 | A2A协议 |
|---|---|---|
| 解决问题 | Agent ↔ 工具/数据源 | Agent ↔ Agent |
| 发现机制 | list_tools()(工具目录) | discover()(Agent注册表) |
| 工作单元 | Tool call(同步) | Task(异步就绪) |
| 耦合方式 | Agent直接使用工具 | Orchestrator委托给Agent |
| 另一端性质 | 被动的工具服务 | 有自主逻辑的Agent |
| 跨服务支持 | 工具为独立进程 | Agent为独立服务 |
全场景协作方式选型
| 适用场景 | 推荐方案 |
|---|---|
| 同一代码库,调用关系确定 | 直接函数调用 |
| Agent需要调用外部工具 | MCP协议(tools as service) |
| Agent委托任务给专业Agent | A2A协议(agents as service) |
| 跨组织大规模Agent网络 | ANP(去中心化发现,Web3风格) |
A2A协议生产落地设计Checklist
AgentCard设计
-
description用一句话清晰描述Agent核心能力,确保LLM能准确理解 -
skill.tags使用语义明确的通用标签(如research、analysis),避免版本号或内部ID - 保持AgentCard机器可读且人类易懂,参考OpenAPI规范的设计风格
Task设计
- 使用UUID作为
Task.id,便于全链路追踪和幂等重试 - 通过
history(Message链)传递上下文,避免在文本中拼接所有历史信息 - 严格区分
ROLE_USER(输入)和ROLE_AGENT(输出)的Message类型
Registry与发现
- 支持一个标签对应多个Agent,实现负载均衡和A/B测试
- 同时提供按标签筛选和按名称精确查找两种能力
- 生产环境使用数据库或专业服务注册中心实现持久化Registry,避免内存字典
LLM驱动路由
- 向LLM提供精简的Agent目录(名称+描述+技能标签),避免传入完整JSON
- 对LLM输出的执行计划做合法性校验,提供兜底执行路径
- 完整记录LLM生成的执行计划,便于事后分析和调试
总结
A2A协议与MCP协议并非竞争关系,而是构建完整Agent生态的互补技术:MCP负责Agent与工具的垂直连接,A2A负责Agent之间的水平协作,一个成熟的多Agent系统可以同时使用这两种协议。
AgentCard是A2A协议的核心,它将Agent转化为可被发现、可被组合的标准化服务单元;Task作为更丰富的工作单元,支持异步执行和结构化上下文传递;而LLM驱动的自主路由则是A2A协议的最高形态,让Agent系统能够根据任务需求动态规划协作链路,无需预先配置编排逻辑。
在实际落地多Agent系统时,还可以搭配TreeRouter(API中转站) 进一步优化架构。TreeRouter能够统一管理Agent与工具、Agent与Agent之间的所有API请求。无论是基于A2A的Agent委托调用,还是基于MCP的工具服务调用,TreeRouter都能提供无缝的技术支持,让多Agent系统的搭建和运维更加高效。




