1873 字
9 分钟
A2A、ACP 与 MCP 不在同一层

搭多 Agent 系统的时候,A2A、ACP、MCP 会一起冒出来。名字都像通信协议,我一开始也把它们当成同一类东西。把文档摊开对照之后才发现,它们根本不在同一层。

我现在是这样记的:

  • A2A:Agent 和 Agent 之间如何协作
  • ACP:客户端或编排器如何控制 Coding Agent
  • MCP:Agent 如何连接工具、数据与外部系统

三个协议叠着用来,不是三选一。

一张表看懂核心区别#

协议全称连接双方主要用途
A2AAgent2Agent ProtocolAgent ↔ Agent能力发现、任务委派、状态跟踪与成果交付
ACPAgent Client ProtocolClient/IDE ↔ Coding Agent会话控制、流式输出、工具状态、权限与 diff
MCPModel Context ProtocolAI Application/Agent ↔ Tool/Data连接文件、数据库、浏览器、搜索和工作流

如果硬要比:A2A 是团队之间怎么交接任务,ACP 是我怎么操作一个 Coding Agent,MCP 是这个 Agent 手里有什么工具。

A2A:Agent 对 Agent#

A2A 是用于 AI Agent 互操作与协作的开放标准。项目最初由 Google 发起,随后贡献给 Linux Foundation 管理。

一个典型的软件开发流程可能是:

主管 Agent A:
“请完成用户认证模块”
A → B:实现后端
A → C:设计测试
B/C → A:报告进度
A → D:整合结果
D → E:最终验收

重点不在遥控对方的终端。它们用同一套语义交换任务、进度和成果就行。根据 A2A 规范,核心对象有:

  • AgentCard:描述 Agent 的身份、能力、技能、接口和安全要求
  • Task:可跟踪、可中断、可能持续很久的工作单元
  • Message:任务上下文中的沟通内容
  • Artifact:代码、报告、文件或结构化数据等产物
  • TaskStatus:任务当前状态及相关消息

任务可以处于已提交、执行中、需要输入、完成、失败、取消或拒绝等状态。协议同时支持普通请求、流式事件和异步推送,适合跨进程、跨服务甚至跨组织的长任务。

A2A 1.0 定义了 JSON-RPC、gRPC 和 HTTP+JSON/REST 等绑定。Agent 之间不必共享内部 prompt、记忆、模型或私有工具,只需通过 AgentCard 声明对外能力,并以消息与产物完成协作。内部怎么跑仍然自己说了算,对外只暴露卡片、消息和产物,安全边界也跟着收小。

A2A 不等于 CLI 遥控协议#

A2A 不能直接让任意两个现有 Coding Agent CLI 自动互联。以 Codex CLI 和 Claude Code 为例,除非产品本身提供 A2A 接口,否则仍需要:

  1. 原生实现 A2A client/server;或者
  2. 在 CLI 外增加 adapter,将其会话和结果映射成 A2A 对象。

因此,A2A 更适合表达「把什么任务交给谁、任务进行到哪里、最后交付了什么」,而不是直接驱动终端输入输出。

ACP:控制 Coding Agent#

这里说的 ACP 指 Agent Client Protocol。行业中还存在同样缩写的 Agent Communication Protocol,看资料时得对一下上下文。

ACP 标准化了代码编辑器、IDE 或编排器与 Coding Agent 之间的通信,定位类似 Coding Agent 领域的 LSP:客户端不需要为每个 Agent 单独解析一套 JSONL、PTY 输出和会话格式。

编辑器或编排器 ── ACP ── Coding Agent

ACP 覆盖的典型能力包括:

  • 初始化 Agent 并协商能力
  • 创建、恢复和管理会话
  • 发送用户 prompt
  • 接收流式文本与执行计划
  • 展示工具调用状态、文件修改和 diff
  • 处理权限请求
  • 取消任务
  • 协商终端、文件系统与 MCP 能力

本地 Agent 通常作为客户端的子进程运行,通过 JSON-RPC over stdio 保持双向长连接。远程 Agent 可以使用 HTTP 或 WebSocket,不过 ACP 官方文档仍将完整的远程支持标注为持续完善中的能力。

这让一个 Rust 编排器可以同时管理多个 ACP Agent:

let codex = start_acp_agent("codex");
let claude = start_acp_agent("claude");
let opencode = start_acp_agent("opencode");
let pi = start_acp_agent("pi");

这段代码表达的是统一接口的目标,而不是声称四个命令都原生实现了 ACP。按照 ACP Agent 列表,OpenCode 提供 ACP 接入,而 Codex CLI、Claude Agent 和 Pi 等可以通过相应 adapter 接入。真正接进去时,启动命令、能力范围和会话恢复方式仍应以各 adapter 为准。

MCP:让 Agent 使用工具和数据#

MCP 是连接 AI 应用与外部系统的开放标准。它不管另一个 Agent 怎么规划任务,只管当前这个 Agent 怎么拿上下文、调动作、用现成工作流。

常见 MCP 能力包括:

  • 读取本地文件或知识库
  • 查询数据库
  • 调用搜索引擎和浏览器
  • 操作 Git、工单或云服务
  • 使用服务端提供的资源与提示模板

MCP server 暴露能力,MCP client 负责发现并调用这些能力。对 Agent 来说,数据库查询、文件读取和浏览器操作通常是边界清晰的工具调用;如果对端具备自主规划、多轮协商和长任务状态,我更愿意把它建成 A2A Agent,而不是随手包成一个 MCP 工具。

ACP 与 MCP 也可以直接配合。ACP 客户端可以把用户配置的 MCP server 信息交给 Agent,让 Agent 直接连接;客户端若要暴露自己的能力,也可以提供 MCP server,而不需要把 ACP 和 MCP 硬塞进同一条连接。

放进多 Agent 系统#

三个协议叠起来,我实际会排成这样:

flowchart TD
O["Rust 编排器"] -->|"ACP"| A["主管 Coding Agent"]
O -->|"ACP"| B["执行 Agent"]
O -->|"ACP"| C["审查 Agent"]
A <-->|"A2A 任务与消息"| B
A <-->|"A2A 任务与消息"| C
B -->|"MCP"| T["文件、Git、测试与数据工具"]
C -->|"MCP"| T

各层职责可以进一步划分为:

ACP:启动并控制 Codex、Claude、OpenCode、Pi 等会话
A2A:表达 Agent 之间的任务委派、状态和成果
MCP:让每个 Agent 使用文件、Git、数据库等外部能力
调度器:管理 DAG、并发、超时、重试、权限与持久化

协议只负责定义交互边界。谁先执行、失败后是否重试、多个结果如何合并、哪些操作需要人工批准,仍然是调度器的职责。

延迟差在哪#

对于本机实时控制,ACP 的 stdio 长连接通常比以下间接方式更直接:

  • SQLite 轮询
  • 文件邮箱
  • Hook 定期检查
  • 模拟终端键盘输入
  • MQTT 跨设备转发

但 ACP 只解决「客户端如何控制 Agent」。它不会保证任何 Agent 都能在模型生成途中接受任意消息。能否立即 steer、排队、取消或中断,最终仍取决于 Agent 及其 ACP 实现暴露了哪些能力。

A2A 位于更高层,重点是可靠、可追踪的任务协作,尤其适合长任务和跨服务通信,并不以本机最低延迟为首要目标。MCP 的延迟则主要取决于具体工具、传输和外部服务。

对我这种以 Rust 为核心的多 Coding Agent 系统,通道是这样分的:

本机实时控制:ACP
Agent 任务语义:A2A
工具与数据能力:MCP
持久化和 DAG:Rust 调度器

控 harness 走 ACP。任务交给谁、进行到哪、交付了什么,走 A2A。文件、Git、数据库走 MCP。A2A 不负责驱动终端。

参考资料#

A2A、ACP 与 MCP 不在同一层
https://fuwari.vercel.app/posts/a2a-acp-mcp/
作者
Hachi
发布于
2026-08-08
许可协议
CC BY-NC-SA 4.0
Linux 打包后视频壁纸零帧:WebKitGTK 不走自定义协议
Codex 指令速查表