简介:这份PPT资料面向大模型与人工智能方向的开发者、架构师及技术决策者,系统梳理智能体通信协作领域的三大主流协议——MCP、A2A与ANP。内容从未来智能体互联网对协议的需求切入,逐一剖析MCP的Root、Sampling、Prompt、Resource、Tools等核心概念与初始化、操作、关闭三大流程,A2A基于任务的企业内部智能体协作模式,以及ANP面向数十亿智能体构建开放协作网络的愿景,并对比三者的差异、优缺点与未来角色。资源包为1个pptx文件,约5.23MB,结构清晰、图文并茂,适合用于技术分享、方案选型或团队内部培训。目前已有219人学习下载。通过这份资料,读者可快速建立对智能体协议体系的整体认知,理解数据孤岛、互联互通与标准化三大挑战的应对思路,为后续架构设计与技术选型提供参考。
1. 三份 PPT 拆开看:MCP、A2A、ANP 到底谁管哪一段
上周帮一个做企业知识库的团队做架构评审,他们已经在用 MCP 把内部检索、数据库、工单系统接进了大模型,跑得挺顺。结果老板突然提了个需求:让销售侧的智能体直接去调用供应链侧的智能体,跨部门自动对账。团队第一反应是「再写个 MCP Server 不就行了」,结果卡了两周——因为 MCP 压根不是干这个的。这就是我拿到《深入对比智能体协议:MCP、A2A、ANP.pptx》这份资源时的真实背景。它把三个最容易混淆的智能体协议放在同一张对比表里讲清楚了:MCP 解决的是「智能体怎么调用工具和数据」,A2A 解决的是「智能体之间怎么互相调用」,ANP 解决的是「智能体怎么在网络里被发现、被信任、被组合」。如果你正在做 Agent 落地,分不清这三者的边界,选型阶段就会埋雷。这份 PPT 适合已经上手过至少一个 Agent 框架、需要做协议选型或架构对齐的工程师,也适合想快速建立全局认知的技术负责人。
2. MCP 协议拆解:从工具描述到一次完整调用链
2.1 MCP 的设计动机与核心抽象
MCP 全称 Model Context Protocol,它要解决的核心痛点是:大模型应用每次接一个新工具(数据库、文件系统、API),都要写一套定制化的适配代码。工具多了以后,代码里全是胶水逻辑,换一个模型或换一个框架就得重写。MCP 的做法是把「工具」抽象成标准化的 Server,把「调用方」抽象成 Client,中间用 JSON-RPC 2.0 通信。这样工具提供方只需要实现一次 MCP Server,任何支持 MCP 的 Client 都能直接接入。
PPT 里把 MCP 的核心抽象拆成四层:Resources(资源,类似文件或数据记录)、Tools(可执行函数)、Prompts(预置提示模板)、Sampling(让 Server 反向请求 Client 的模型能力)。实际落地中最常用的是 Tools 和 Resources,Prompts 和 Sampling 用得少但有特定场景。理解这四层的关键在于:Resources 是「读」的语义,Tools 是「做」的语义,两者在权限控制上要分开处理。
2.2 手写一个最小 MCP Server
下面用 Python 写一个最小可用的 MCP Server,暴露一个查询订单状态的工具。这段代码可以直接跑,依赖只有mcp包。
# minimal_mcp_server.py # 依赖: pip install mcp import asyncio from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent app = Server("order-service") # 模拟订单数据 ORDERS = { "ORD-1001": {"status": "shipped", "eta": "2025-06-20"}, "ORD-1002": {"status": "pending", "eta": None}, } @app.list_tools() async def list_tools() -> list[Tool]: """声明本 Server 提供哪些工具,Client 启动时会拉取这个列表""" return [ Tool( name="query_order", description="根据订单号查询订单状态和预计到达时间", inputSchema={ "type": "object", "properties": { "order_id": { "type": "string", "description": "订单号,格式 ORD-XXXX" } }, "required": ["order_id"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: """实际执行工具调用,返回结果给 Client""" if name != "query_order": raise ValueError(f"未知工具: {name}") order_id = arguments.get("order_id", "") order = ORDERS.get(order_id) if not order: return [TextContent(type="text", text=f"订单 {order_id} 不存在")] return [TextContent( type="text", text=f"订单 {order_id}: 状态={order['status']}, 预计到达={order['eta'] or '待定'}" )] async def main(): # 通过 stdio 传输层启动,Client 以子进程方式拉起本 Server async with stdio_server() as (read, write): await app.run(read, write, app.create_initialization_options()) if __name__ == "__main__": asyncio.run(main())逻辑说明:list_tools返回工具清单和 JSON Schema 格式的参数定义,Client 拿到后会把工具描述注入模型的上下文,模型决定是否调用。call_tool是实际执行入口,参数由模型生成、Client 转发。传输层用 stdio 是最简单的本地调试方式,生产环境常见做法是换成 SSE 或 Streamable HTTP。
参数说明:inputSchema必须符合 JSON Schema 规范,required字段决定模型是否必须提供该参数。TextContent的type目前支持text和image,返回图片时传 base64。注意description写得好不好直接影响模型调用准确率——这是血泪经验,描述含糊的工具模型经常不调用或传错参数。
2.3 用 Client 验证调用链
写完 Server 后,用官方提供的 Client 做一次端到端验证:
# 安装 MCP Inspector,可视化调试工具 npx @modelcontextprotocol/inspector python minimal_mcp_server.py启动后浏览器打开 Inspector 界面,能看到工具列表、手动触发调用、查看原始 JSON-RPC 消息。这一步很关键——很多「模型不调用工具」的问题,其实是 Server 返回的 Schema 有问题,用 Inspector 能快速定位是 Server 端还是 Client 端的问题。
如果要在代码里集成,Client 侧大致是这样:
# mcp_client_demo.py from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def run(): params = StdioServerParameters( command="python", args=["minimal_mcp_server.py"] ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() # 拉取工具列表 tools = await session.list_tools() print("可用工具:", [t.name for t in tools.tools]) # 直接调用工具 result = await session.call_tool( "query_order", {"order_id": "ORD-1001"} ) print("调用结果:", result.content[0].text) import asyncio asyncio.run(run())这段代码展示了 MCP 调用的完整生命周期:建立传输连接 → 初始化会话 → 拉取工具列表 → 调用工具 → 拿到结果。实际接入大模型时,中间多一步「把工具列表转成模型能理解的 function calling 格式」,但底层走的还是这套流程。
3. A2A 协议拆解:智能体之间的任务委派怎么落地
3.1 A2A 与 MCP 的本质区别
A2A 全称 Agent-to-Agent Protocol,它和 MCP 最容易混淆,但定位完全不同。MCP 是「智能体 → 工具」的纵向调用,A2A 是「智能体 → 智能体」的横向协作。PPT 里用了一个很准确的类比:MCP 像是给电脑装驱动,A2A 像是两台电脑之间组网。
具体来说,A2A 要解决的是:一个智能体如何发现另一个智能体的能力、如何把任务委派过去、如何追踪任务状态、如何处理长任务和流式返回。它的核心抽象是 Agent Card(能力声明)、Task(任务对象)、Message(消息)和 Artifact(产出物)。Agent Card 是一个 JSON 文件,通常放在/.well-known/agent.json路径下,描述这个智能体的名称、能力、支持的输入输出格式和认证方式。
3.2 定义一个 Agent Card
Agent Card 是 A2A 的入口,没有它别的智能体就找不到你。下面是一个典型的 Agent Card:
{ "name": "supply-chain-agent", "description": "供应链对账智能体,支持订单核对和差异分析", "url": "https://supply.example.com/a2a", "version": "1.0.0", "capabilities": { "streaming": true, "pushNotifications": false }, "skills": [ { "id": "reconcile-orders", "name": "订单对账", "description": "接收销售侧订单列表,与供应链记录比对,返回差异明细", "inputModes": ["application/json"], "outputModes": ["application/json"] } ], "authentication": { "schemes": ["Bearer"] } }逻辑说明:capabilities.streaming表示该智能体支持流式返回中间状态,长任务场景必须开。skills数组列出具体能力,每个 skill 有独立的 id 和输入输出格式声明。authentication声明认证方式,A2A 本身不定义认证协议,只声明要求,具体走 OAuth2 还是 API Key 由实现方决定。
参数说明:url是 A2A 服务的端点,Client 会向这个地址发 JSON-RPC 请求。inputModes和outputModes用 MIME 类型标注,常见的是application/json和text/plain。如果智能体要接收文件,加application/pdf之类的类型。
3.3 发起一次 A2A 任务委派
A2A 的调用流程比 MCP 多一层任务管理。下面用 Python 演示如何向一个 A2A 智能体发起任务:
# a2a_client_demo.py # 依赖: pip install httpx import httpx import uuid AGENT_URL = "https://supply.example.com/a2a" async def send_task(): task_id = str(uuid.uuid4()) payload = { "jsonrpc": "2.0", "id": task_id, "method": "tasks/send", "params": { "id": task_id, "message": { "role": "user", "parts": [ { "type": "text", "text": "请对账以下订单:ORD-1001, ORD-1002, ORD-1003" } ] } } } async with httpx.AsyncClient() as client: resp = await client.post( AGENT_URL, json=payload, headers={"Authorization": "Bearer <token>"}, timeout=60.0 ) result = resp.json() # 任务可能直接完成,也可能返回 working 状态 print("任务状态:", result["result"]["status"]["state"]) return result["result"]["id"] async def poll_task(task_id: str): """长任务需要轮询状态,直到 completed 或 failed""" payload = { "jsonrpc": "2.0", "id": str(uuid.uuid4()), "method": "tasks/get", "params": {"id": task_id} } async with httpx.AsyncClient() as client: resp = await client.post(AGENT_URL, json=payload) return resp.json()["result"] import asyncio task_id = asyncio.run(send_task()) print("任务已提交:", task_id)逻辑说明:A2A 用 JSON-RPC 2.0 作为基础协议,tasks/send提交任务,tasks/get查询状态。任务状态机包括submitted、working、input-required、completed、failed、canceled。input-required是个关键状态——智能体执行到一半需要补充信息时,会暂停并返回这个状态,Client 需要再发一条消息补充输入。
参数说明:message.parts是消息内容数组,支持 text、file、data 三种类型。timeout要设够,跨智能体调用往往比本地工具调用慢。如果 Agent Card 里声明了streaming: true,可以用tasks/sendSubscribe方法建立 SSE 连接,实时接收状态更新,避免轮询。
3.4 A2A 的适用边界
A2A 不是万能的。PPT 里明确列了几个不适合用 A2A 的场景:单智能体内部调用工具(用 MCP)、纯数据管道(用消息队列)、需要严格事务保证的同步调用(用 gRPC)。A2A 最适合的是「多个智能体分属不同团队或不同系统,需要松耦合协作」的场景。比如销售智能体和供应链智能体分属两个部门,各自迭代,通过 A2A 协议对接,谁也不用改谁的代码。
4. ANP 协议拆解:智能体网络里的发现与信任
4.1 ANP 要解决的是什么问题
ANP 全称 Agent Network Protocol,它比 MCP 和 A2A 更上层。MCP 解决工具接入,A2A 解决点对点协作,ANP 解决的是「当网络里有成百上千个智能体时,怎么发现谁、怎么信任谁、怎么组合成更大的能力」。PPT 里把 ANP 的核心归纳为三个机制:去中心化身份(DID)、能力发现(基于语义描述)、信任传递(基于可验证凭证)。
这个定位决定了 ANP 的落地门槛比前两者高。MCP 和 A2A 可以单点接入,ANP 需要整个网络层面的基础设施。但如果你的场景是「构建一个开放的智能体市场」或「跨组织的智能体协作网络」,ANP 是绕不开的。
4.2 DID 与可验证凭证的落地方式
ANP 用 DID 标识每个智能体,用可验证凭证(VC)表达信任关系。下面是一个简化的 DID 文档示例:
{ "@context": "https://www.w3.org/ns/did/v1", "id": "did:example:supply-chain-agent-001", "verificationMethod": [ { "id": "did:example:supply-chain-agent-001#key-1", "type": "Ed25519VerificationKey2020", "controller": "did:example:supply-chain-agent-001", "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" } ], "service": [ { "id": "did:example:supply-chain-agent-001#a2a", "type": "A2AService", "serviceEndpoint": "https://supply.example.com/a2a" } ] }逻辑说明:verificationMethod声明公钥,其他智能体用这个公钥验证该智能体签名的消息。service声明服务端点,这里指向 A2A 端点,说明 ANP 和 A2A 是互补关系——ANP 负责发现和信任,A2A 负责实际通信。
参数说明:publicKeyMultibase是 Multibase 编码的公钥,z前缀表示 base58btc 编码。type字段决定签名算法,Ed25519 是目前主流选择,性能好且密钥短。实际部署时 DID 文档通常托管在区块链或分布式存储上,但也可以先用 HTTPS 托管做原型验证。
4.3 能力发现与语义匹配
ANP 的能力发现基于语义描述,不是简单的关键词匹配。每个智能体在 DID 文档或独立的服务描述里声明自己的能力,其他智能体用语义相似度找到最合适的协作者。常见做法是用向量数据库存能力描述,查询时做相似度检索。
# capability_discovery.py # 依赖: pip install sentence-transformers numpy from sentence_transformers import SentenceTransformer import numpy as np model = SentenceTransformer("all-MiniLM-L6-v2") # 模拟网络中的智能体能力描述 agents = [ {"did": "did:example:agent-001", "capability": "订单对账和差异分析"}, {"did": "did:example:agent-002", "capability": "库存查询和补货建议"}, {"did": "did:example:agent-003", "capability": "物流轨迹追踪和异常预警"}, {"did": "did:example:agent-004", "capability": "财务报表生成和合规检查"}, ] # 预计算能力向量 capability_texts = [a["capability"] for a in agents] capability_vectors = model.encode(capability_texts, normalize_embeddings=True) def find_agent(query: str, top_k: int = 2): """根据自然语言查询找到最匹配的智能体""" query_vec = model.encode([query], normalize_embeddings=True) scores = np.dot(capability_vectors, query_vec.T).flatten() ranked = np.argsort(scores)[::-1][:top_k] return [ {"did": agents[i]["did"], "score": float(scores[i])} for i in ranked ] # 测试:找一个能做对账的智能体 results = find_agent("我需要核对销售订单和供应链记录") for r in results: print(f"{r['did']} 相似度={r['score']:.4f}")逻辑说明:用 Sentence Transformer 把能力描述和查询都编码成向量,做余弦相似度匹配。normalize_embeddings=True让向量归一化,点积直接等于余弦相似度。实际生产环境会把向量存进 FAISS 或 Milvus,支持百万级智能体的毫秒级检索。
参数说明:all-MiniLM-L6-v2是轻量模型,384 维向量,适合原型验证。生产环境可以换更大的模型提升语义匹配精度,但要注意推理延迟。top_k控制返回候选数量,通常取 3 到 5,太少容易漏,太多增加后续验证成本。
5. 避坑与常见问题:协议选型和落地中的真实翻车记录
5.1 用 MCP 做智能体间通信,结果任务状态全丢了
现象:团队用 MCP 的 Tools 机制让智能体 A 调用智能体 B,简单场景能跑通,但一旦 B 执行超过 30 秒,A 就超时了,而且拿不到 B 的中间状态。
原因:MCP 的 Tools 调用是同步语义,设计上就是「调用-返回」的短交互模式。它没有任务状态机,不支持长任务和流式中间状态。A2A 才有working、input-required这些状态。
解决:智能体间通信一律走 A2A,MCP 只用于智能体调用无状态工具。如果暂时不想引入 A2A,至少把长任务拆成「提交任务返回 task_id」+「轮询状态」两步,但这本质是在 MCP 上重新实现 A2A 的任务管理,不如直接用 A2A。
5.2 Agent Card 路径写错,发现机制直接失效
现象:A2A 智能体部署好了,但其他智能体死活发现不了它,日志里全是 404。
原因:A2A 规范约定 Agent Card 放在/.well-known/agent.json,但有些框架默认路径是/.well-known/agent-card.json或/agent.json。不同实现之间路径不统一,导致发现失败。
解决:部署后用curl https://your-domain/.well-known/agent.json验证路径可访问。如果框架默认路径不同,在反向代理层加一条 rewrite 规则统一到标准路径。这个坑很隐蔽,因为本地测试时如果 Client 和 Server 用同一个框架,路径一致就不会暴露问题。
5.3 MCP Server 的工具描述太模糊,模型调用率极低
现象:MCP Server 接入了 10 个工具,但模型实际只调用了其中 2 个,其他工具明明该用却不用。
原因:工具的description写得太笼统,比如「查询数据」「处理请求」这种。模型在选择工具时依赖描述做语义匹配,描述不具体就无法准确判断该用哪个。
解决:每个工具的 description 要写清楚「做什么、输入什么、输出什么、什么场景用」。比如把「查询数据」改成「根据订单号查询订单状态,输入 ORD-XXXX 格式订单号,返回状态和预计到达时间」。另外inputSchema里每个参数的 description 也要写,模型生成参数时同样依赖这些描述。
5.4 ANP 的 DID 解析在离线环境不可用
现象:在内网环境部署 ANP 智能体网络,DID 解析全部失败,智能体之间无法互相发现。
原因:DID 解析通常依赖外部解析器或区块链节点,内网环境访问不了。有些实现虽然支持本地缓存,但首次解析仍然需要外部访问。
解决:内网场景用did:web方法替代did:example,把 DID 文档托管在内网 HTTPS 服务上,解析走标准 HTTP 请求。或者部署本地 DID 解析缓存服务,预热常用 DID 文档。选型阶段就要确认 DID 方法是否支持离线解析,别等部署了才发现。
5.5 三个协议混用时认证体系冲突
现象:MCP Server 用 API Key 认证,A2A 智能体用 OAuth2,ANP 用 DID 签名,三套认证体系混在一起,调用链上认证信息传丢了。
原因:三个协议各自定义认证声明方式,但没有规定互相之间怎么传递认证上下文。MCP 的 API Key 不会自动转成 A2A 的 Bearer Token,ANP 的 DID 签名也无法直接用于 MCP 的认证。
解决:在网关层做认证转换,统一用一套内部认证体系(比如 JWT),各协议端点的认证在网关终止,内部调用携带统一的 JWT。这样每个协议对外保持自己的认证声明,对内统一。别试图让三个协议直接互认认证信息,那是自找麻烦。
6. 协议选型的决策框架与验证清单
选型这件事,PPT 里给了一张对比表,但表格只能看个大概,真正做决策需要落到具体场景。我一般会按下面这个流程走一遍。
第一步,明确交互类型。如果是「智能体调用工具/数据源」,选 MCP。如果是「智能体调用智能体」,选 A2A。如果是「在开放网络中发布和发现智能体」,选 ANP。三者不是互斥关系,一个系统里可以同时用:用 ANP 做发现,用 A2A 做协作,用 MCP 做工具接入。
第二步,确认任务时长和状态需求。短任务(秒级返回)MCP 够用。长任务(分钟级以上、需要中间状态)必须用 A2A。这一步判断错了,后面全是坑。
第三步,评估网络规模。点对点协作(几个到几十个智能体)A2A 足够。开放网络(上百个以上、需要动态发现)才需要 ANP。别为了「看起来先进」上 ANP,它的基础设施成本不低。
第四步,验证认证体系兼容性。把三个协议的认证方式列出来,看是否有冲突。有冲突就在网关层统一,别在协议层硬解。
下面这张表是我自己用的验证清单,每次选型后逐项过一遍:
| 验证项 | MCP | A2A | ANP |
|---|---|---|---|
| 工具/能力描述是否完整 | 检查 inputSchema 和 description | 检查 Agent Card 的 skills | 检查能力向量覆盖度 |
| 长任务支持 | 不支持,需自行封装 | 原生支持状态机 | 依赖底层 A2A |
| 发现机制 | 手动配置 Server 地址 | Agent Card 路径可访问 | DID 解析可用 |
| 认证方式 | API Key / OAuth | Bearer / OAuth2 | DID 签名 + VC |
| 流式返回 | 部分支持 | 支持 SSE | 依赖底层 A2A |
| 离线可用性 | 本地 stdio 可用 | 内网 HTTP 可用 | 需确认 DID 方法 |
最后说一个我自己的习惯:每次做完协议选型,我会写一个最小验证 Demo,把三个协议各跑通一次调用链,确认端到端没问题再进入正式开发。这个 Demo 不用复杂,MCP 跑通一个工具调用,A2A 跑通一次任务委派,ANP 跑通一次 DID 解析和能力发现就行。花半天时间,能省掉后面两周的返工。从那以后我每次做架构评审都强制走一遍这个验证流程,希望帮到你。
本文还有配套的精品资源,点击获取