通信协议 本节摘要:说不同语言的 Agent 不是团队,是互不相识的陌生人朝虚空喊话。本节深入 2026 年四大 Agent 协议——MCP(工具访问)、A2A(Agent 之间)、ACP(企业审计)、ANP(去中心化信任)。我们会读真实的线格式:A2A 的 Agent Card 与九态任务生命周期、ACP 的 TrajectoryMetadata 审计轨迹、ANP 的 did:wba 身份与元协议协商。然后用 TypeScript 从零把四者织成一个统一网关:用 ANP 验身份、用 A2A 发现并派发任务、用 ACP 包审计轨迹。读完本节,你能为给定系统选出正确的协议组合,而不是被「基础性协议」的营销话术裹挟。协调的工程化,从一份可审计、可发现、可信任的通信契约开始。
本节摘要:说不同语言的 Agent 不是团队,是互不相识的陌生人朝虚空喊话。本节深入 2026 年四大 Agent 协议——MCP(工具访问)、A2A(Agent 之间)、ACP(企业审计)、ANP(去中心化信任)。我们会读真实的线格式:A2A 的 Agent Card 与九态任务生命周期、ACP 的 TrajectoryMetadata 审计轨迹、ANP 的 did:wba 身份与元协议协商。然后用 TypeScript 从零把四者织成一个统一网关:用 ANP 验身份、用 A2A 发现并派发任务、用 ACP 包审计轨迹。读完本节,你能为给定系统选出正确的协议组合,而不是被「基础性协议」的营销话术裹挟。协调的工程化,从一份可审计、可发现、可信任的通信契约开始。
阅读完本节,你应当能够:
你把系统拆成了多个 Agent:研究员、程序员、评审员。它们各自干得不错,但现在需要它们真正互相对话。
第一次尝试显然:传字符串。研究员返回一坨文本,程序员尽力去解析。直到程序员误读了研究摘要,或两个 Agent 互相等待而死锁,或不同团队写的 Agent 要协作——「就传字符串」就崩了。
这就是通信协议问题。没有 Agent 交换信息的共享契约,多智能体系统脆弱、不可审计、无法扩展到你个人写的几个 Agent 之外。
四者是分层而非竞争关系:ANP 解决信任,A2A 解决协作,ACP 解决审计,MCP 解决工具。一个真实的企业系统会同时用上多个。
Google 主导(现归 Linux 基金会 lf.a2a.v1,规范 v1.0.0)。解决:自主 Agent 如何协作、协商、互相委派任务。每个 Agent 在知名 URL 发布 Agent Card,其他 Agent 据此发现、协商、派活。
Agent Card 的关键字段:skills(每个有 id、tags、支持的输入/输出 MIME)、supportedInterfaces(一个 Agent 可同时讲 JSON-RPC、REST、gRPC)、securitySchemes(调用前就知道需要什么认证)。
任务生命周期有 9 个状态(submitted、working、input-required、auth-required、completed、failed、canceled、rejected,加一个 UNPECIFIED 哨兵)。终态不可变;后续要在同一 contextId 下创建新任务。线格式是 JSON-RPC 2.0,流式用 SSE。
IBM/BeeAI 出,基于 OpenAPI 3.1.1 的 REST/JSON,正在并入 A2A。它的差异化在于 TrajectoryMetadata:每条 Agent 响应都能携带产生该响应的完整推理链与工具调用日志。
{ "role": "agent/researcher", "parts": [{ "content_type": "text/plain", "content": "旧金山天气 72 华氏度,晴。", "metadata": { "kind": "trajectory", "message": "我需要查这个地点的天气", "tool_name": "weather_api", "tool_input": { "location": "San Francisco, CA" }, "tool_output": { "temperature": 72, "condition": "sunny" } } }] }
对受监管行业这是金子:每个答案都带可证明的推理链——调了哪个工具、什么输入、什么输出。没有黑盒。ACP 还支持 CitationMetadata 做来源归属,并提供 sync/async/stream 三种 Run 模式。
社区开源(创始人 GaoWei Chang)。解决:不同组织的 Agent 如何在无中心权威下互信。用 W3C DID(did:wba 方法)做密码学身份,用 HPKE(RFC 9180)做端到端加密。
关键设计:密钥分离——签名用 secp256k1、加密用 X25519;humanAuthorization 要求高风险操作(如资金划转)需人类显式批准;信任是双边逐次验证的(域名级 TLS + DID 签名 + 最小权限),不用信任网或背书图。最具新意的是元协议协商:两个陌生 Agent 用自然语言提议各自支持的格式,最多 10 轮,达成一致后动态生成代码处理该格式。
| MCP | A2A | ACP | ANP | |
|---|---|---|---|---|
| 主创 | Anthropic | Google/Linux Foundation | IBM/BeeAI | 社区 |
| 规范格式 | JSON-RPC | JSON-RPC/REST/gRPC | OpenAPI 3.1(REST) | JSON-RPC |
| 主要用途 | Agent↔工具 | Agent↔Agent | Agent↔Agent | Agent↔Agent |
| 身份 | 隐式(本地) | 安全方案(OAuth/mTLS) | 服务器级 | W3C DID + E2EE |
| 审计轨迹 | 无 | 基础(任务历史) | TrajectoryMetadata | 未正式规定 |
| 独特能力 | 工具 schema | Agent Card + Skills | 轨迹审计 | 元协议协商 |
| 最适合 | 工具与数据 | 动态协作 | 受监管行业 | 跨组织信任 |
下面用 TypeScript 从零搭出四协议的最小骨架(完整代码见原课程 code/main.ts)。
多模态消息,带轨迹条目(对应 ACP):
type MessagePart = | { kind: "text"; text: string } | { kind: "data"; data: unknown; mediaType: string } | { kind: "file"; name: string; url: string; mediaType: string }; type TrajectoryEntry = { reasoning: string; toolName?: string; toolInput?: unknown; toolOutput?: unknown; timestamp: number }; type AgentMessage = { id: string; role: "user"|"agent"; parts: MessagePart[]; trajectory?: TrajectoryEntry[]; replyTo?: string; timestamp: number };
按技能标签、按输入 MIME、按名发现:
class AgentRegistry { private cards = new Map<string, AgentCard>(); register(card: AgentCard) { this.cards.set(card.name, card); } discoverBySkillTag(tag: string): AgentCard[] { return [...this.cards.values()].filter(c => c.skills.some(s => s.tags.includes(tag))); } resolve(name: string) { return this.cards.get(name); } }
九态状态机,终态不可变;handler 是异步生成器,产出 statusUpdate/artifactUpdate 事件,对应 SSE 流式模型:
const TERMINAL = ["completed","failed","canceled","rejected"]; class TaskManager { private tasks = new Map<string, Task>(); async sendMessage(agentName, message, contextId?) { const task = this.createTask(contextId); task.history.push(message); task.status = { state: "submitted", timestamp: Date.now() }; this.processTask(task, this.handlers.get(agentName), message); // 异步 return task; } private async processTask(task, handler, message) { task.status = { state: "working", timestamp: Date.now() }; try { for await (const ev of handler(task, message)) { if (TERMINAL.includes(task.status.state)) break; // 终态后停止 if (ev.kind === "statusUpdate") task.status = ev.status; if (ev.kind === "artifactUpdate") task.artifacts.push(ev.artifact); } } catch (err) { task.status = { state: "failed", timestamp: Date.now() }; } } }
设计要点:终态检查放在循环里——handler 在
completed后再 yield 产物会被静默丢弃或抛错。A2A 规范之所以规定终态不可变,正是为了让任务的最终结果可被安全缓存与重放。
每次 Agent 执行产出完整审计条目(输入、输出、轨迹),可按 Agent、按会话、按 run 查询:
class AuditableRunner { private log: AuditEntry[] = []; async run(agentName, input, sessionId?): Promise<AuditEntry> { const entry: AuditEntry = { runId: uuid(), agentName, input: structuredClone(input), output: [], trajectory: [], status: "created", startedAt: Date.now(), sessionId }; this.log.push(entry); entry.status = "in-progress"; const result = await this.handlers.get(agentName)(input); entry.output = structuredClone(result.output); entry.trajectory = structuredClone(result.trajectory); entry.status = "completed"; entry.completedAt = Date.now(); return entry; } }
DID 文档分离 authentication / keyAgreement / humanAuthorization 三类密钥;验证即用 DID 文档里的公钥校验签名:
class IdentityRegistry { verify(did, signature, payload): boolean { const doc = this.documents.get(did); const authKeys = doc.verificationMethod.filter(vm => doc.authentication.includes(vm.id)); return authKeys.some(k => crypto.verify(null, Buffer.from(payload), publicKeyFromDer(k.publicKeyDer), Buffer.from(signature, "hex"))); } }
一次调用串起四协议:ANP 验身份 → A2A 发现目标 Agent → ACP 包审计 → A2A 创建任务:
class ProtocolGateway { async delegateTask(fromDid, signature, targetAgent, message, sessionId?) { if (!this.identityRegistry.verify(fromDid, signature, message.id)) return { error: "身份验证失败" }; if (!this.registry.resolve(targetAgent)) return { error: `未找到 Agent ${targetAgent}` }; const audit = await this.auditRunner.run(targetAgent, [message], sessionId); const task = await this.taskManager.sendMessage(targetAgent, message); return { task, audit }; } }
application/json,但 schema 跨版本变了,B 解析旧格式得到垃圾。修复:给 skill 与输出 schema 做版本化(A2A 的 Agent Card 支持 version)。completed 后还想 yield 产物,任务已不可变。修复:yield 前查终态。GET /agents。修复:Agent Card 带 TTL 缓存、错峰发现、改用推送注册。选型决策树:
| 协议 | 成熟度 | 何时选 |
|---|---|---|
| MCP | 稳定,生态最广 | 任何「Agent 调工具」场景 |
| A2A | 稳定 v1.0,Google/LF 维护 | 动态发现与协作的起点 |
| ACP | 并入 A2A 中 | 受监管行业需要轨迹审计时,用其模式即便传输用 A2A |
| ANP | 实验性,值得跟踪 | 跨组织、无中心权威的 Agent 部署 |
💡 心法:MCP 接工具,A2A 接 Agent,ACP 留审计,ANP 管信任。 别指望一个协议包打天下,真实系统是四者的组合。
code/main.ts:四协议模式的完整 TypeScript 实现。outputs/prompt-protocol-selector.md:一个决策提示,输入系统需求(工具/协作/审计/跨组织),输出协议组合建议。TaskManager,让一个 Agent handler 能向其他 Agent 委派子任务。研究员收到任务后,把「搜索」与「总结」拆给两个专职 Agent,等两者完成后合并进自己的 artifacts。AuditableRunner 改成流式,用异步生成器实时 yield 审计快照,而非等完整结果。IdentityRegistry 加密钥轮换——Agent 发布带 previousDid 的新 DID 文档,验证者在宽限期内接受新旧两套密钥的签名。protocolNegotiation 消息(候选格式:JSON-RPC vs REST),最多 3 轮达成一致或超时。RateLimitedRegistry,模拟 100 个 Agent 启动时互相发现,对比有无限速的差别。did:wba 做密码学身份、密钥分离、人类授权;元协议协商让陌生 Agent 用自然语言商定格式。下一节,我们抽象出一个最小可用的「多智能体原语模型」——把本节的消息、任务、身份收敛成一组可复用的核心数据结构与生命周期。