MCP 解决了 Agent ↔ 工具谁来解决 Agent ↔ Agent上一篇讲了 MCP一个 Agent 通过标准协议连接工具服务。工具是被动的——它等待被调用执行返回结果。但有些场景里你需要委托的不是一个工具而是另一个有自主决策能力的 Agent你有一个研究型 Agent擅长收集和分析技术资料你有一个写作型 Agent擅长把分析结论转化成可读文档你有一个代码审查 Agent擅长发现安全问题当这三个 Agent 需要协作时它们之间怎么沟通谁知道谁的存在怎么传递工作这就是A2AAgent-to-Agent协议要解决的问题。MCP Agent ←→ 工具/数据源垂直集成Agent 主动调工具 A2A Agent ←→ Agent 水平协作Agent 委托给 AgentA2A 的三个核心概念AgentCardAgent 的名片每个 Agent 发布一张AgentCard描述它能做什么froma2a.typesimportAgentCard,AgentSkilldefmake_skill(skill_id,name,description,tags):sAgentSkill()s.idskill_id s.namename s.descriptiondescription s.tags.extend(tags)returns research_cardAgentCard()research_card.nameresearch-agentresearch_card.descriptionGathers factual background on technical topicsresearch_card.skills.append(make_skill(research,Research,Collect key facts on a topic,[research,facts]))AgentCard 的关键字段name、description、skills每个 skill 有tags用于发现。这就像是 OpenAPI Spec 的 Agent 版本——机器可读的能力声明。Task工作单元Agent 间传递的不是函数调用而是Taskfroma2a.typesimportTask,TaskState,TaskStatus,Message,Part,Role taskTask()task.idstr(uuid.uuid4())task.status.stateTaskState.TASK_STATE_SUBMITTED# 输入User 角色的 MessagemsgMessage()msg.roleRole.ROLE_USER partPart();part.textShould I use Python or Go?msg.parts.append(part)task.history.append(msg)Task有生命周期状态SUBMITTED → WORKING → COMPLETED / FAILED。完成时Agent 把结果追加为ROLE_AGENT的 Message。RegistryAgent 的黄页AgentRegistry存储所有注册的 AgentCard支持按 tag 发现classAgentRegistry:defregister(self,card:AgentCard,handler:Callable[[Task],Task])-None:self._agents[card.name]AgentEntry(cardcard,handlerhandler)defdiscover(self,tag:str)-list[AgentCard]:返回所有 skill 包含指定 tag 的 Agent...defdelegate(self,agent_name:str,input_text:str)-Task:创建 Task 并通过注册的 handler 执行...Demo 1直接调用——简单但耦合没有协议时orchestrator 直接调用三个 Python 函数defdirect_orchestrator(question:str)-str:researchresearch_agent_fn(question)# 硬依赖analysisanalysis_agent_fn(research)# 硬依赖answerwriting_agent_fn(analysis)# 硬依赖returnanswer实测结果→ 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 在另一个服务里就是跨服务改代码。Demo 2A2A AgentCard 注册表注册三个 Agent每个带不同的 skill tag[registry] registered: research-agent [registry] registered: analysis-agent [registry] registered: writing-agent发现测试researchersregistry.discover(research)# → Found: research-agent — Gathers factual background on technical topicswritersregistry.discover(writing)# → Found: writing-agent — Composes clear technical prose from analysis outputorchestrator 完全不写 Agent 名字只按 tag 发现defa2a_orchestrator(question:str)-str:researchersregistry.discover(research)t1registry.delegate(researchers[0].name,question)analystsregistry.discover(analysis)t2registry.delegate(analysts[0].name,task_output(t1))writersregistry.discover(writing)t3registry.delegate(writers[0].name,task_output(t2))returntask_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带同样的writingtagorchestrator 立刻可以发现并使用它——零代码改动。Demo 3LLM 驱动的 Agent 路由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-agent Final answer: Choose Python for rapid development; Go for high-throughput...这是 A2A 的终态不需要预先配置 orchestratorLLM 根据任务需求和 AgentCard 描述在运行时自主规划协作链路。MCP vs A2A vs ANP协议选型矩阵维度 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 风格设计 ChecklistAgentCard 设计description用一句话描述 Agent 擅长什么LLM 会读它来决策skill.tags用语义明确的标签research、analysis、writing不用版本号或 IDAgentCard应该是机器可读、人类也能理解的参考 OpenAPI 风格Task 设计Task.id用 UUID便于追踪和幂等重试用historyMessage 链传递上下文而不是在 part.text 里拼接所有历史区分ROLE_USER输入和ROLE_AGENT输出的 MessageRegistry 与发现一个 tag 可以对应多个 Agent负载均衡、A/B 测试支持按 tag 筛选也支持按 name 精确查找生产环境用持久化 Registry数据库或服务注册中心而非内存字典LLM 驱动路由Agent catalog 要简洁name description skill tags不要把整个 AgentCard JSON 塞给 LLM解析 LLM 输出时做校验agent_name not in registry给出兜底路径记录 LLM 生成的执行计划便于事后分析和调试总结五个核心结论A2A 和 MCP 不竞争互补MCP 是 Agent 调工具A2A 是 Agent 委托 Agent一个系统里可以同时用两种协议AgentCard 是 A2A 的核心它让 Agent 变成可被发现、可被组合的服务单元而不是硬编码的依赖Task 是比函数调用更丰富的工作单元有生命周期状态支持异步可以携带结构化历史直接调用 vs A2A 的分界线同一团队、同一代码库 → 直接调用跨服务、需要解耦 → A2ALLM 驱动路由是 A2A 的最高形态Agent 根据任务描述自主规划协作链路无需预先配置 orchestrator下一篇Agent 评估框架—— 怎么系统地测试 Agent用什么指标衡量好坏DeepEval 怎么用参考资料A2A Protocol 官方规范A2A Python SDKANPAgent Network Protocol本系列完整 Demo 代码agent-10-a2a更多实用知识和有趣产品欢迎访问我的个人主页
Agent 系列(11):A2A 协议——Agent 与 Agent 如何协作
发布时间:2026/6/3 22:16:04
MCP 解决了 Agent ↔ 工具谁来解决 Agent ↔ Agent上一篇讲了 MCP一个 Agent 通过标准协议连接工具服务。工具是被动的——它等待被调用执行返回结果。但有些场景里你需要委托的不是一个工具而是另一个有自主决策能力的 Agent你有一个研究型 Agent擅长收集和分析技术资料你有一个写作型 Agent擅长把分析结论转化成可读文档你有一个代码审查 Agent擅长发现安全问题当这三个 Agent 需要协作时它们之间怎么沟通谁知道谁的存在怎么传递工作这就是A2AAgent-to-Agent协议要解决的问题。MCP Agent ←→ 工具/数据源垂直集成Agent 主动调工具 A2A Agent ←→ Agent 水平协作Agent 委托给 AgentA2A 的三个核心概念AgentCardAgent 的名片每个 Agent 发布一张AgentCard描述它能做什么froma2a.typesimportAgentCard,AgentSkilldefmake_skill(skill_id,name,description,tags):sAgentSkill()s.idskill_id s.namename s.descriptiondescription s.tags.extend(tags)returns research_cardAgentCard()research_card.nameresearch-agentresearch_card.descriptionGathers factual background on technical topicsresearch_card.skills.append(make_skill(research,Research,Collect key facts on a topic,[research,facts]))AgentCard 的关键字段name、description、skills每个 skill 有tags用于发现。这就像是 OpenAPI Spec 的 Agent 版本——机器可读的能力声明。Task工作单元Agent 间传递的不是函数调用而是Taskfroma2a.typesimportTask,TaskState,TaskStatus,Message,Part,Role taskTask()task.idstr(uuid.uuid4())task.status.stateTaskState.TASK_STATE_SUBMITTED# 输入User 角色的 MessagemsgMessage()msg.roleRole.ROLE_USER partPart();part.textShould I use Python or Go?msg.parts.append(part)task.history.append(msg)Task有生命周期状态SUBMITTED → WORKING → COMPLETED / FAILED。完成时Agent 把结果追加为ROLE_AGENT的 Message。RegistryAgent 的黄页AgentRegistry存储所有注册的 AgentCard支持按 tag 发现classAgentRegistry:defregister(self,card:AgentCard,handler:Callable[[Task],Task])-None:self._agents[card.name]AgentEntry(cardcard,handlerhandler)defdiscover(self,tag:str)-list[AgentCard]:返回所有 skill 包含指定 tag 的 Agent...defdelegate(self,agent_name:str,input_text:str)-Task:创建 Task 并通过注册的 handler 执行...Demo 1直接调用——简单但耦合没有协议时orchestrator 直接调用三个 Python 函数defdirect_orchestrator(question:str)-str:researchresearch_agent_fn(question)# 硬依赖analysisanalysis_agent_fn(research)# 硬依赖answerwriting_agent_fn(analysis)# 硬依赖returnanswer实测结果→ 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 在另一个服务里就是跨服务改代码。Demo 2A2A AgentCard 注册表注册三个 Agent每个带不同的 skill tag[registry] registered: research-agent [registry] registered: analysis-agent [registry] registered: writing-agent发现测试researchersregistry.discover(research)# → Found: research-agent — Gathers factual background on technical topicswritersregistry.discover(writing)# → Found: writing-agent — Composes clear technical prose from analysis outputorchestrator 完全不写 Agent 名字只按 tag 发现defa2a_orchestrator(question:str)-str:researchersregistry.discover(research)t1registry.delegate(researchers[0].name,question)analystsregistry.discover(analysis)t2registry.delegate(analysts[0].name,task_output(t1))writersregistry.discover(writing)t3registry.delegate(writers[0].name,task_output(t2))returntask_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带同样的writingtagorchestrator 立刻可以发现并使用它——零代码改动。Demo 3LLM 驱动的 Agent 路由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-agent Final answer: Choose Python for rapid development; Go for high-throughput...这是 A2A 的终态不需要预先配置 orchestratorLLM 根据任务需求和 AgentCard 描述在运行时自主规划协作链路。MCP vs A2A vs ANP协议选型矩阵维度 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 风格设计 ChecklistAgentCard 设计description用一句话描述 Agent 擅长什么LLM 会读它来决策skill.tags用语义明确的标签research、analysis、writing不用版本号或 IDAgentCard应该是机器可读、人类也能理解的参考 OpenAPI 风格Task 设计Task.id用 UUID便于追踪和幂等重试用historyMessage 链传递上下文而不是在 part.text 里拼接所有历史区分ROLE_USER输入和ROLE_AGENT输出的 MessageRegistry 与发现一个 tag 可以对应多个 Agent负载均衡、A/B 测试支持按 tag 筛选也支持按 name 精确查找生产环境用持久化 Registry数据库或服务注册中心而非内存字典LLM 驱动路由Agent catalog 要简洁name description skill tags不要把整个 AgentCard JSON 塞给 LLM解析 LLM 输出时做校验agent_name not in registry给出兜底路径记录 LLM 生成的执行计划便于事后分析和调试总结五个核心结论A2A 和 MCP 不竞争互补MCP 是 Agent 调工具A2A 是 Agent 委托 Agent一个系统里可以同时用两种协议AgentCard 是 A2A 的核心它让 Agent 变成可被发现、可被组合的服务单元而不是硬编码的依赖Task 是比函数调用更丰富的工作单元有生命周期状态支持异步可以携带结构化历史直接调用 vs A2A 的分界线同一团队、同一代码库 → 直接调用跨服务、需要解耦 → A2ALLM 驱动路由是 A2A 的最高形态Agent 根据任务描述自主规划协作链路无需预先配置 orchestrator下一篇Agent 评估框架—— 怎么系统地测试 Agent用什么指标衡量好坏DeepEval 怎么用参考资料A2A Protocol 官方规范A2A Python SDKANPAgent Network Protocol本系列完整 Demo 代码agent-10-a2a更多实用知识和有趣产品欢迎访问我的个人主页