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使用语义明确的通用标签(如researchanalysis),避免版本号或内部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系统的搭建和运维更加高效。