ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

智能体通信协议MCP/A2A/ANP选型与落地实践指南

智能体通信协议MCP/A2A/ANP选型与落地实践指南 简介智能体通信正成为AI应用互联的关键支撑这份资料围绕MCP、A2A、ANP三种主流协议展开适合AI研究人员、开发者以及关注智能体网络演进的技术管理者阅读。内容梳理了智能体相关协议的多方格局与发展背景系统对比三者设计理念MCP以模型为中心连接外部工具与数据A2A采用点对点架构聚焦企业内部复杂协作ANP以智能体为中心解决身份、描述、发现等问题目标成为智能体互联网时代的HTTP。读者可借此理解协议选型边界也可从ANP分层架构、身份认证、交互流程与开源Manus接入案例中了解落地路径。资源为单份PDF电子文档大小8.14MB图文与规范说明集中便于完整阅读和留存。已有583人浏览学习适合希望在智能体互联方向上快速建立全局认知的读者。1. 智能体通信协议 MCP、A2A、ANP 被放在一起比较先判断你在解决哪一层的问题过去半年凡做智能体落地的人几乎都被问过一句“你们用 MCP 还是 A2A要不要上 ANP”。这三个词常被当成同一类东西实际它们解决的是三层不同的问题MCP 把“模型调用工具和数据”标准化A2A 把“智能体之间互相派活、收结果”标准化ANP 把“智能体入网后的身份、寻址和可信协作”标准化。选错协议层的团队不在少数最典型的翻车是先搭了一整套 ANP 网络回头发现最缺的只是一个能稳定读内部数据库的 MCP server。这篇笔记按“最小可用、按需扩展、最后入网”的顺序讲清楚三层协议各自的价值、可复现的落地方案和踩坑点适合准备把多智能体协作从 demo 推向生产环境的一线工程师。2. 把 MCP 跑通是最小代价的入局路径本地 server 与 client 的最小可运行配置2.1 先分清 MCP 的三种运输方式stdio、HTTPSSE、streamable HTTPMCP 的核心不是传输协议本身而是工具能力的标准化。一个 MCP 会话的基本流程是client 启动后先发 initialize 握手再发 tools/list 拿到工具清单模型根据任务描述选择合适的工具client 发 tools/call 执行。全程走 JSON-RPC 2.0方法名固定为这几个真正有差异的是底层传输方式。stdio 模式适合本地进程client 拉起一个 python 子进程请求从 stdin 进、响应从 stdout 出stderr 直接当日志通道用调试非常直观。缺点是要管理好子进程生命周期server 不能自己常驻多 client 共享时每个 client 拿到的都是独立进程。HTTPSSE 模式是 server 以独立服务方式常驻client 用 POST 发请求事件通过 SSE 通道推回来适合跨机器部署但这个模式在网关后面特别容易断连因为 SSE 长连接会被代理层按空闲超时掐掉。现在官方推荐的是 streamable HTTP它把请求通道和事件通道收进同一条 HTTP 连接避免老方案里 POST 与 SSE 分开带来的会话状态问题。选型依据就一条这个 server 要不要独立部署、要不要被多个 client 共享本地单机用 stdio服务化用 streamable HTTP。顺便澄清一个高频混淆RAG 和 MCP 不是竞争关系。RAG 解决“模型不知道的信息怎么查出来灌进上下文”MCP 解决“模型决定要做什么之后怎么去执行”。一个典型混合场景是先 RAG 查内部文档再通过 MCP 调报销系统 API 把单据提交掉两者各管一段。2.2 用 Python 30 行写一个 MCP server工具定义与调用约定现在生态里 Playwright MCP、Figma MCP 这类封装好的 server 已经很多日常开发往往只需要把内部接口包成工具。最常见做法是用官方 SDK 的 FastMCP 入口把函数定义直接变成工具描述。# 依赖pip install mcp # 运行python stock_server.py from mcp.server.fastmcp import FastMCP # 创建名为 stock 的 MCP serverclient 端显示的名称 mcp FastMCP(stock) mcp.tool() def get_stock_price(symbol: str) - str: 查询指定股票代码的最新行情返回演示行情快照。 # 真实场景这里替换为内部行情 API 调用 return fmock price of {symbol}: 10.25 2025-06-20 15:00 CST if __name__ __main__: mcp.run()逻辑说明FastMCP 启动时会自动把 get_stock_price 的函数签名映射成 tools/list 返回的 inputSchemadocstring 变成工具描述client 端模型正是靠这两段信息决定“什么时候调用、传什么参数”。symbol 被声明为 strSDK 会自动标记为必填。返回值统一被包装成 TextContent所以函数最好是返回字符串结构化的数据可以直接 return json.dumps(...) 后再让模型解析。参数说明mcp FastMCP(stock) 里的名字是工具的命名空间mcp.tool() 默认把函数名当作工具名docstring 别写太短模型选择工具时 description 的匹配权重非常高。生产环境里建议给每个工具加明确的错误提示比如“查不到该代码”而不是直接抛异常否则模型会把异常理解成“工具不可用”而绕开。本地运行后可以用 codex 或 Claude Desktop 这类现成 client 直接连也可以先用命令行验证进程不崩、日志正常输出再接 client避免把问题混在一起排查。2.3 用 Codex 与 Claude Desktop 分别接同一个 MCP server配置文件写法差异同一个 stdio 的 MCP server在不同 client 里的接入写法略有差别但底层都是拉起子进程后走 JSON-RPC 握手。下面以 Codex 和 Claude Desktop 两种常见客户端为例说明。# Codex 命令行注册一个名为 stock 的 MCP server codex mcp add stock -- python /workspace/stock_server.py逻辑说明-- 后面是完整的启动命令codex 会维护一个全局配置把 stock 这个名字映射到这条命令。每次启动 codex 时它都会拉起这个 python 进程进程退出则连接断开。参数说明命令里的 python 必须是能 import 到 mcp 包的解析器如果使用 uv 创建的隔离环境这里要写绝对路径的 python否则子进程启动时找不到依赖表现为连接后立刻失败。{ mcpServers: { stock: { command: python, args: [/workspace/stock_server.py] } } }这是 Claude Desktop 和不少编辑器的通用配置结构。command 是启动程序args 是参数数组可以用 env 字段注入环境变量比如内部 API 的 token。远程场景则不用 command/args直接写 url 字段指向一个 streamable HTTP 端点。逻辑说明两种 client 的配置差异只在接入层协议层一致所以同一个 server 可以同时注册给多个 client。需要注意stdio 模式下每个 client 拿到的都是独立进程所以不要在 server 内保存全局 session 状态HTTP 模式下多个 client 共享一个进程必须自己做并发和鉴权token 不要再通过环境变量硬编码。血的教训是有人把生产库的只读账号写进 stdio 配置结果任何能读到配置文件的同事都能直接拉起一个 server 查全库。3. A2A 与 ANP 的选型逻辑点对点协作与入网治理的两种价值观3.1 A2A 的轻量假设AgentCard、Task 对象与 OAuth 2.0 授权A2AAgent-to-Agent是面向智能体之间协作的开放协议草案核心假设是“每个 agent 都是一个可寻址的 HTTP 服务”。当一个 agent 想找另一个 agent 协作时先访问对方的 AgentCard也就是一个 JSON-LD 描述文件里面写清楚这个 agent 会什么技能、是否支持流式返回、推送通知走什么通道。{ context: https://a2a-api.com/schema/v1, name: data-agent, description: 负责数据库查询与报表生成, url: https://agent.internal.example.com, skills: [ { id: sql_query, name: SQL 查询, description: 执行只读 SQL 并返回结果集 } ], streaming: false, pushNotifications: true }逻辑说明AgentCard 里的 skills 不是给大模型看的工具描述而是给对端 agent 看的“能力招贴”。url 是任务接收端点后面所有 A2A 请求都 POST 到这个地址。pushNotifications 为 true 表示任务完成时会主动回调为 false 时对端只能轮询。参数说明streaming 关闭时任务进度只能靠轮询或 webhook 感知skills 的 id 在协作时作为能力标识被引用。A2A 规范里对传输安全没有发明新东西就是标准 OAuth 2.0所以两个内部系统对接时可以直接复用现有 IdP。这套设计的优点是很轻适合双方都愿意改代码、规模在小几十个 agent 之内的场景。3.2 ANP 的可信入网DID 身份、网络寻址与代币机制ANPAgent Network Protocol的思路和 A2A 不同不是两个 agent 互相发消息而是所有 agent 先“入网”网络层负责身份、寻址、路由和信用。可以把它理解成给智能体建一张运营商网络入网先拿一张 SIM 卡这张卡就是 DID去中心化身份。一个节点入网时生成公私钥、构造 DID 文档、发布服务端点网络返回一个可路由的 agent 地址之后所有消息都套一层网络信封。{ envelope: { from: did:anp:node_a, to: did:anp:node_b, session_id: c7f1a9b2, signature: 0x1f2e3d..., timestamp: 1750410000 }, payload: { type: a2a/task, task_id: t_001, action: submit } }这是一个示意结构各团队内部实现可能有差异但关键字段一定是这三类身份标识、路由信息、防篡改签名。signature 证明这个信封确实来自 from 字段声明的 DIDsession_id 用于把多轮消息关联成一次会话timestamp 防止重放攻击。逻辑说明ANP 的 payload 层不关心业务语义所以完全可以把 A2A 的 Task JSON 塞进 payload 里传输这也解释了为什么 ANP 和 A2A 不是替代关系而是叠加关系。区别在信任模型A2A 默认“你认识我我才跟你聊”ANP 默认“你入网了我就知道你是谁、能找得到你、你干过什么事有据可查”这对跨团队、跨组织的智能体互联网络尤其关键。3.3 一张对比表决定你的部署边界什么场景不该上 A2A/ANP维度MCPA2AANP通信单元智能体到工具/数据智能体到智能体智能体到智能体网络信任模型client 本地配置即信任双方协商加 OAuth 2.0DID 注册加网络背书寻址方式不负责寻址HTTP URL 直连网络路由按 DID 寻址典型规模单 agent 的工具层小规模 agent 协作跨团队/跨组织的 agent 网络当前成熟度生态最广落地最多规范草案demo 成熟早期适合先试点选型判断其实很直接如果只是单个 agent 调几个内部 API上 A2A 是过度设计如果合作方只有两三家且大家都能改代码A2A 直连比 ANP 简单得多只有当目标是把几十个团队、上百个 agent 挂进一个统一可信网络需要身份、审计、寻址这些治理能力时才轮到 ANP。我见过最可惜的投入是一开始就照着 ANP 搭架子结果业务方只是要一个能查订单的机器人先上 MCP 两周就能交付。4. 一份可抄的多智能体协作消息流设计从 A2A Task 到 ANP 信封的映射4.1 用 JSON 定义 A2A 任务状态机消息字段与状态迁移A2A 把一次协作建模成一个 Task 对象状态机是六个状态submitted、working、input-required、completed、failed、canceled。消息字段设计直接决定对端能不能正确还原上下文。{ task_id: t_20250620_001, status: working, context_ids: [session_42], messages: [ { role: agent, message_id: m_1, payload: { type: text, text: 请统计华东区上月回款 } } ], artifacts: [ { artifact_id: a_1, name: report.csv, mime_type: text/csv } ] }逻辑说明status 是执行 agent 写入的当前状态messages 是对话历史artifacts 是产物清单。对端拿到这个对象后不需要额外查询历史记录就能渲染出任务全貌。context_ids 用来关联多轮子任务比如一个报表任务拆成三次查询三次查询共享同一个 context。状态迁移规则如下表编排层按这张表做校验即可事件状态迁移触发方创建任务进入 submitted发起 agent开始处理submitted 到 working执行 agent缺信息working 到 input-required执行 agent补充信息input-required 到 working发起 agent全部完成working 到 completed执行 agent异常终止working 到 failed执行 agent主动取消任意到 canceled发起 agent实际联调中最重要的两点一是 task_id 必须幂等对端重复收到同一个 task_id 的 submit 请求时不能重复执行直接返回现有状态二是轮询要有上限别让发起方无限等下去一般超过 5 分钟就退回做人工确认。4.2 ANP 消息信封的结构与路由字段把 A2A 包进 ANP 网络上一节的 Task JSON 在 ANP 网络里不能裸奔需要先包一层网络信封。信封提供的是传输层能力签名验身份、路由找目标、会话做聚合。一个常见映射关系是A2A 的 task_id 映射进信封的 payloadDID 映射进 from/toagent 的能力标识映射进路由字段。{ envelope: { from: did:anp:finance_planner, to: did:anp:data_service, session_id: session_42, routing: { skill: sql_query, priority: 5, timeout_sec: 120 }, signature: 0x9a8b7c... }, payload: { type: a2a/task/submit, task: { task_id: t_20250620_001, status: submitted, messages: [] } } }逻辑说明routing.skill 对应 AgentCard 里声明的技能 ID网络网关拿到这个字段后做能力路由不匹配直接拒绝省得业务层处理无效请求。timeout_sec 告诉网络这条消息最多等多久超时网关会主动向发起方回一个失败事件避免调用方永久挂起。参数说明priority 是优先级字段真实生产里不要全局配置成同一个值否则高优任务和低优任务混在一个队列里谁也跑不快建议只对“用户直接感知”的任务设高优先级。签名算法按实现方的要求来但签名覆盖范围必须包含 from、to、timestamp 三个字段否则只签 payload 的话信封字段可以被中间人篡改。4.3 一个最小协作场景MCP 取数、A2A 派单、ANP 做身份审计把三层协议组在一起跑的最小闭环大概是这样的用户端 agent A 负责理解用户诉求查到订单数据后派给报表 agent B 生成一份 CSV 报告。A 先通过自己的 MCP 连接读取订单库这是第一层工具调用然后构造成 A2A Task 提交给 B这条派单消息在发送前走 ANP 网关网关校验 DID、查 B 的地址、签名后转发给 B。B 收到任务后自己也通过 MCP 调报表模板服务最后把产物写进 Task 的 artifacts 字段。这个设计的好处是每一层都能独立替换。MCP 层想从 MySQL 换到 ClickHouse改 A 的 MCP server 配置即可A2A 层想从直连换成消息队列改任务提交方式即可ANP 层要换身份服务商DID 签发和验签逻辑独立在网关里。三层之间只通过消息体耦合A 完全不 care B 内部用的什么模型、什么工具、什么数据库。在团队内部落地时我一般建议先只上 MCP把单个 agent 的工具调用全部稳定下来等到第二个 agent 出现、需要互相派活时再上 A2A当第三个团队也要接入且对方说你没法直接连我的内网时才引入 ANP 统一入网。每加一层都必须有明确的新能力收益否则就是给系统叠复杂度。5. 智能体通信协议落地避坑指南从超时、鉴权到消息风暴的实测排查5.1 MCP client 超时codex 配置里最常见的一行翻车现象codex mcp add 注册成功后第一次调用工具直接报 timed out after 30 secondsserver 侧日志显示进程启动了但没有任何请求进来。原因stdio 模式启动的 python 子进程如果初始化要拉下载、连数据库、装插件30 秒根本不够还有一种情况是 server 内部初始化代码抛异常进程退了但 client 误以为还在等。解决先手动跑一遍 python stock_server.py 确认进程能否在 3 秒内就绪把重型资源初始化改成懒加载所有连接放到第一次 tools/call 时建立最后在 client 配置里按文档找到 startup_timeout 这类参数调大。注意不要靠无限调大超时掩盖问题server 启动超过 10 秒基本就是代码有问题。5.2 A2A 回调地址写了内网 IP对端永远收不到完成事件现象任务状态停在 working 半天不动执行 agent 日志显示任务早完成了但发起方收不到 completed 回调。原因AgentCard 的 url 或 pushNotifications 回调地址配置成了 127.0.0.1 或 10.x 内网地址。局域网内测试没问题一旦对端部署在公网或另一个 VPC请求根本到不了。解决回调地址一律用公网可达的 HTTPS 域名再在前面挂一层反向代理。本地联调阶段可以用带公网入口的代理工具把本地端口暴露出去但生产环境必须走正式的 API 网关。5.3 ANP 身份与工具权限脱节拿到 token 不等于拿到数据权限现象ANP 网络里两个 agent 的 DID 校验全部通过信封签名也合法但被调 agent 的 MCP 工具执行时一直报 403 无权限。原因DID 身份校验只证明了“你是谁”业务权限系统关心的是“你能干什么”。两边没有打通token 在协议层有效但在数据层无效。解决在 ANP 网关里做一层身份到业务角色的映射把 did 或 session_id 翻译成业务权限标签再向数据服务申请临时凭据。临时凭据的过期时间设短一点不要给整个 agent 发长期 key。5.4 agent 互相派单导致消息风暴死循环比想象的更容易出现现象一个日报自动生成流程上线后消息量几十倍增长最后网关被打挂。查日志发现 A 缺数据派给 BB 处理时发现缺另一块数据又派回 A两边互相喂需求。原因任务派发没有终止条件。每个 agent 都把“补数据”当成一次新任务而没有任何限制“一个任务最多派生几个子任务”。解决在 A2A Task 里强制加 max_depth 字段B 收到任务时先检查深度超过直接拒绝再给整个协作会话设一个总 deadline到点强制置为 failed。排查这种问题时给每条消息加 trace_id 是必须的否则根因根本没法追溯。5.5 JSON-RPC 错误码兼容墙不同 SDK 对同一错误理解不同现象python 写的 MCP server 接 Java client 时工具偶尔调用成功、偶尔报 method not found但方法名明明是对的。原因MCP 在 JSON-RPC 2.0 之外对部分字段做了追加约束不同语言的 SDK 对这些约束的实现程度不一致。比较典型的是对 progress token、采样回调这类可选字段的处理差异。解决跨语言联调前先各自跑一遍 tools/list 和 initialize 的样例报文把两边的请求响应对齐参数里不要带实验性字段比如某些 SDK 自动加的 _meta。遇到看不懂的错误先抓原生报文别急着猜。6. 验证智能体协议栈的最后一公里用模拟客户端压测和抓包检查消息完整性6.1 用 Python 模拟一个 A2A 客户端验证任务状态迁移协议栈搭完后第一件事不是写业务逻辑而是用一个最小客户端把协议链路打通。下面这段脚本模拟发起方先拉 AgentCard再提交任务然后轮询状态直到终态。import requests import time AGENT_URL https://agent.internal.example.com # 1. 拉取 AgentCard确认对端有哪些技能 card requests.get(AGENT_URL /.well-known/agent-card, timeout5).json() print(skills:, [s[id] for s in card[skills]]) # 2. 提交一个最小任务 task requests.post(AGENT_URL /task, json{ task_id: t_test_001, status: submitted, messages: [{ role: agent, message_id: m1, payload: {type: text, text: ping} }] }, timeout5).json() # 3. 轮询状态最多 10 次每次间隔 0.5 秒 for _ in range(10): time.sleep(0.5) task requests.get( f{AGENT_URL}/task/{task[task_id]}, timeout5 ).json() print(task[status]) if task[status] in (completed, failed, canceled): break逻辑说明脚本第一步验证 AgentCard 可达第二部验证任务提交第三步验证状态迁移。真正要盯的是状态顺序必须按 submitted、working、completed 走直接跳到 completed 说明对端缓存了旧状态卡在 input-required 说明任务缺参数回看 messages 里对端的补充提问。参数说明timeout5 是每次 HTTP 请求的超时轮询间隔 0.5 秒对演示足够生产环境轮询间隔建议 2 到 5 秒太频繁会压垮回调接口。6.2 抓包检查 MCP 的 JSON-RPC 报文三个必看字段MCP 出问题时的黄金排错手段是抓进程的实际报文在本地直接看 server 的 stdout、stderr再配合 tcpdump 看 HTTP 模式下的请求内容。# 抓取本机 3000 端口上的 MCP 请求只看前 20 个包 tcpdump -i lo port 3000 -A -c 20拿到报文后只核对三个字段jsonrpc 必须是 2.0method 必须落在 initialize、tools/list、tools/call 这几个白名单里tools/call 的 params.arguments 与 server 端实际收到的 arguments 必须一致。逻辑说明第三个字段最常翻车。client 端模型在生成参数时会出现幻觉比如工具要求 symbol 传字符串模型却传了 {symbol: {code: 000001}} 这种嵌套结构server 端严格校验时直接报类型错误但报错信息容易让人误以为接口不通。抓包对比两边 JSON 就能一眼看出是模型生成参数的问题还是网络传输的问题。就我个人习惯这套验证脚本会进 CI每次改 agent 能力描述或工具 schema 都跑一遍防止某次提示词调整把工具描述改坏导致模型不再调用。协议这东西文档写得再漂亮不如在真实报文里确认一次字段完全对得上。希望帮到你。本文还有配套的精品资源点击获取
返回列表