上一篇讲了 MCP:一个 Agent 通过标准协议连接工具服务。工具是被动的——它等待被调用,执行,返回结果。

但有些场景里,你需要委托的不是一个工具,而是另一个有自主决策能力的 Agent:
当这三个 Agent 需要协作时,它们之间怎么沟通?谁知道谁的存在?怎么传递工作?
这就是 A2A(Agent-to-Agent)协议 要解决的问题。
MCP: Agent ←→ 工具/数据源(垂直集成,Agent 主动调工具)
A2A: Agent ←→ Agent (水平协作,Agent 委托给 Agent)
每个 Agent 发布一张 AgentCard,描述它能做什么:
from a2a.types import AgentCard, AgentSkilldef make_skill(skill_id, name, description, tags):
s = AgentSkill()
s.id = skill_id
s.name = name
s.description = description
s.tags.extend(tags)
return sresearch_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(每个 skill 有 tags 用于发现)。
这就像是 OpenAPI Spec 的 Agent 版本——机器可读的能力声明。
Agent 间传递的不是函数调用,而是 Task:
from a2a.types import Task, TaskState, TaskStatus, Message, Part, Roletask = 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。
AgentRegistry 存储所有注册的 AgentCard,支持按 tag 发现:
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 执行"""
...
没有协议时,orchestrator 直接调用三个 Python 函数:
def direct_orchestrator(question: str) -> str:
research = research_agent_fn(question) # 硬依赖
analysis = analysis_agent_fn(research) # 硬依赖
answer = writing_agent_fn(analysis) # 硬依赖
return answer
实测结果:
→ calling research_agent (direct)
→ calling analysis_agent (direct)
→ calling writing_agent (direct)Answer: Choose Python if you need rapid development with broad libraries.
Select Go if performance and concurrency are critical...
功能没问题。问题是:orchestrator 里写死了三个函数名。替换任何一个 Agent,需要修改 orchestrator 代码。如果 orchestrator 在另一个服务里,就是跨服务改代码。
注册三个 Agent,每个带不同的 skill tag:
[registry] registered: research-agent
[registry] registered: analysis-agent
[registry] registered: writing-agent
发现测试:
researchers = registry.discover("research")
# → Found: research-agent — Gathers factual background on technical topicswriters = registry.discover("writing")
# → Found: writing-agent — Composes clear technical prose from analysis output
orchestrator 完全不写 Agent 名字,只按 tag 发现:
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)
实测执行:
→ delegating to research-agent (discovered via tag)
→ delegating to analysis-agent (discovered via tag)
→ delegating to writing-agent (discovered via tag)Answer: Choose Python for rapid development; Go for high-throughput performance...
关键差别:orchestrator 代码里没有出现 research-agent、writing-agent 这些名字。新注册一个 writing-agent-v2(带同样的 writing tag),orchestrator 立刻可以发现并使用它——零代码改动。
A2A 最强大的用法:LLM 读取 AgentCard catalog,自己决定调用哪些 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"]
按计划执行:
Executing 3 agents:
→ delegating to research-agent
→ delegating to analysis-agent
→ delegating to writing-agentFinal answer: Choose Python for rapid development; Go for high-throughput...
这是 A2A 的终态:不需要预先配置 orchestrator,LLM 根据任务需求和 AgentCard 描述,在运行时自主规划协作链路。
维度 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 风格)
AgentCard 设计
description 用一句话描述 Agent 擅长什么,LLM 会读它来决策skill.tags 用语义明确的标签(research、analysis、writing),不用版本号或 IDAgentCard 应该是机器可读、人类也能理解的(参考 OpenAPI 风格)Task 设计
Task.id 用 UUID,便于追踪和幂等重试history(Message 链)传递上下文,而不是在 part.text 里拼接所有历史ROLE_USER(输入)和 ROLE_AGENT(输出)的 MessageRegistry 与发现
LLM 驱动路由
agent_name not in registry),给出兜底路径五个核心结论:
下一篇:Agent 评估框架 —— 怎么系统地测试 Agent?用什么指标衡量好坏?DeepEval 怎么用?
更多实用知识和有趣产品,欢迎访问我的个人主页