2025年完整指南:Agent2Agent (A2A) 协议 - AI智能体协作的新标准与TaoToken统一API通道
1. 为什么单智能体越来越不够用从 A2A 协议要解决的真实问题说起如果你最近在折腾 AI 智能体大概率会遇到一个尴尬的场面你写了一个能查天气的 Agent又写了一个能订机票的 Agent还想让它们配合完成“帮我规划一趟东京五日游”结果发现两个 Agent 之间根本没法对话。你要么把逻辑全塞进一个巨型 Prompt 里要么写一堆 if-else 硬编码调用关系。Agent2Agent简称 A2A协议就是冲着这个痛点来的——它是一套让不同团队、不同框架、甚至不同组织开发的 AI 智能体能够互相通信、协商、协作的开放标准。一句话概括A2A 是智能体之间的“普通话”底层用 JSON-RPC 2.0 over HTTP(S) 传输通过 Agent Card 做能力发现通过 Task 做状态化任务管理。它和 MCP 不是竞争关系——MCP 解决的是“模型怎么调用工具”A2A 解决的是“智能体怎么找智能体、怎么把任务委托出去”。你可以把 MCP 理解成给机械师配的扳手和诊断仪A2A 则是店长和机械师、机械师和零件供应商之间的对讲机。这篇文章适合三类人一是正在做多智能体编排、被点对点集成折磨的工程师二是想快速搭一条可运行的 A2A 协作链路、不想啃完整规范的人三是已经在用统一 API 通道调用多家模型、想把 Agent 协作也纳入同一套 Key 体系的人。我会用 TaoToken 的统一 API 通道作为模型调用底座把 A2A 端点的配置、JSON-RPC 请求、连通性验证一步步跑通你照着做就能得到一条能实际发消息、能拿到 Task 结果的协作链路。需要先明确一个边界A2A 本身是通信协议它不负责模型推理。你的智能体背后用哪个模型、走哪条 API 通道是另一层的事。把这两层分开后面配置才不会乱。我试过把模型调用和 A2A 通信混在一起写结果排障时完全分不清是协议层的问题还是模型层的问题这个坑你可以提前避开。2. TaoToken 统一 API 通道给 A2A 智能体一个稳定的模型底座在搭 A2A 链路之前得先解决“智能体的大脑从哪来”。一个 A2A 服务端智能体收到任务后通常要调用大模型做推理、规划、生成回复。如果你每个智能体都单独配一家模型的 Key多智能体一多Key 管理、额度、模型切换就会变成一团乱麻。TaoToken 在这里的角色是统一 API 通道你用一套 Key、一个 Base URL就能调用多家模型A2A 里的每个智能体都能复用这套通道不用各自维护供应商配置。先把关键地址记清楚后面配置会反复用到官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 基址https://taotoken.net/api 这个不加 UTM直接作为 Base URL 用模型对话体验https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodelsCoding Plan长期编码/Agent 场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcodingplan控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentconsoleAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapikeys接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdocClaude Code 接入https://taotoken.net/claudecode?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaudecode为什么 A2A 场景特别需要统一通道因为 A2A 的典型用法是“客户端智能体把任务委托给远程智能体”远程智能体可能跑在另一台机器、另一个容器里。如果每个远程智能体都要单独配 Key你部署三个智能体就要管三套凭证。用 TaoToken 统一通道后所有智能体的模型调用都指向同一个 Base URLKey 也统一部署时只需要注入一次环境变量。这对多智能体编排的运维成本是实打实的降低。这里要强调一个概念区分很多人第一次接触会混淆TaoToken 是模型 API 通道A2A 是智能体通信协议两者是叠加关系。你的 A2A 服务端代码里收到 JSON-RPC 请求后内部再去调用 TaoToken 的模型接口生成回复。链路是“A2A 客户端 → A2A 服务端 → TaoToken API → 模型 → 返回”。把这条链路画清楚后面排障时你就能快速定位问题出在哪一段。关于 Key 的获取直接去 API Keys 页面创建即可创建后复制保存后面配置里用TAOTOKEN_API_KEY这个环境变量承载。模型 ID 的选择上A2A 服务端做任务规划建议用推理能力强的模型做简单回复可以用轻量模型具体可用模型列表在模型对话页面能看到。如果你打算长期跑 Agent 编排Coding Plan 那条通道对高频调用更友好可以按需了解。3. 可复制的 A2A 端点配置Agent Card、JSON-RPC 与 settings 片段这一节是全文最核心的部分我直接把可复制的配置给你。A2A 服务端要对外暴露两个东西一个是 Agent Card智能体名片放在/.well-known/agent.json另一个是 JSON-RPC 端点通常挂在/a2a路径下。客户端先拉 Agent Card 发现能力再往 JSON-RPC 端点发message/send请求。先看 Agent Card 的完整 JSON这是服务端要返回给发现请求的内容{ name: travel-planner-agent, description: 负责旅行规划与任务拆分的 A2A 服务端智能体, provider: TaoToken Demo, url: https://your-agent-host/a2a, version: 1.0.0, capabilities: { streaming: true, pushNotifications: false }, authentication: { schemes: [Bearer] }, defaultInputModes: [text], defaultOutputModes: [text], skills: [ { id: trip-planning, name: 行程规划, description: 根据目的地和天数生成行程草案, inputModes: [text], outputModes: [text] } ] }注意url字段必须和你的 JSON-RPC 端点真实地址一致客户端会拿这个地址发请求。capabilities.streaming设为 true 表示支持 SSE 流式返回如果你的实现暂时不支持设成 false 避免客户端误判。接下来是服务端的模型调用配置。A2A 服务端内部调 TaoToken用环境变量承载凭证配置文件可以写成这样以常见的.env加代码读取为例# .env TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEYsk-你的Key TAOTOKEN_MODEL_ID你的模型ID A2A_HOST0.0.0.0 A2A_PORT8080如果你用的是支持 settings 文件的框架比如某些 Agent 运行时可以写成 TOML[a2a] host 0.0.0.0 port 8080 agent_card_path /.well-known/agent.json rpc_path /a2a [model] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model_id 你的模型ID这里三件套必须齐全Base URL 指向https://taotoken.net/apiKey 走环境变量注入Model ID 明确写死或从环境读取。缺任何一个服务端在收到任务后调模型就会失败。我见过有人只配了 Base URL 和 Key忘了 Model ID结果 A2A 请求能进来、Task 能创建但一直卡在 working 状态最后超时——这就是模型层没配全的典型表现。然后是 JSON-RPC 请求示例。客户端向服务端发message/send请求体结构如下{ jsonrpc: 2.0, id: req-001, method: message/send, params: { message: { role: user, messageId: msg-001, parts: [ { kind: text, text: 帮我规划东京五日游偏好文化类景点 } ] } } }服务端处理完后返回 Task 对象包含id、status、artifacts等字段。如果任务需要多轮状态会先到input-required客户端补充消息后再继续。这个状态机是 A2A 区别于普通 REST 调用的关键配置时要把状态流转逻辑写清楚。4. 验证请求与成功结果用 curl 跑通一次完整协作配置写完必须验证。我习惯先用 curl 打两个请求先拉 Agent Card再发一条 message/send。这样能把“发现”和“通信”两段分开验证出问题好定位。第一步验证 Agent Card 可发现curl -s http://localhost:8080/.well-known/agent.json | python -m json.tool预期返回就是第 3 节那份 JSONname、url、skills都在。如果返回 404说明你的路由没挂对如果返回 HTML说明被前端路由拦截了检查服务端路由优先级。第二步发一条 JSON-RPC 请求curl -s -X POST http://localhost:8080/a2a \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { jsonrpc: 2.0, id: req-001, method: message/send, params: { message: { role: user, messageId: msg-001, parts: [{kind: text, text: 帮我规划东京五日游}] } } } | python -m json.tool成功的话你会拿到类似这样的返回{ jsonrpc: 2.0, id: req-001, result: { id: task-abc123, status: { state: completed }, artifacts: [ { name: trip-plan, parts: [ { kind: text, text: 第一天浅草寺、上野公园…… } ] } ] } }看到state: completed和artifacts里有内容说明整条链路通了A2A 请求进来 → 服务端调 TaoToken → 模型返回 → 封装成 Artifact 返回。如果state是working一直不变多半是模型调用卡住或超时如果是failed看返回里的错误信息通常是模型层报错。第三步验证流式。如果你的服务端开了streaming可以用 curl 带 SSE 头curl -N -X POST http://localhost:8080/a2a \ -H Content-Type: application/json \ -H Accept: text/event-stream \ -d {jsonrpc:2.0,id:req-002,method:message/stream,params:{message:{role:user,messageId:msg-002,parts:[{kind:text,text:继续补充第二天行程}]}}}你会看到分块返回的data:行每块是一个增量 Part。流式验证通过说明你的 A2A 服务端支持增量输出前端体验会更好。实测下来最容易出问题的不是协议本身而是模型层的连通性。建议在写 A2A 服务端之前先用一段最小代码单独验证 TaoToken 通道能通import os, requests resp requests.post( f{os.environ[TAOTOKEN_BASE_URL]}/v1/chat/completions, headers{Authorization: fBearer {os.environ[TAOTOKEN_API_KEY]}}, json{ model: os.environ[TAOTOKEN_MODEL_ID], messages: [{role: user, content: ping}] }, timeout30 ) print(resp.status_code, resp.json()[choices][0][message][content])这段先跑通再去接 A2A排障范围能缩小一半。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth这一节按真实报错来我把踩过的和读者反馈最多的几类整理出来对照着查。401 Unauthorized。这个最常见出现在两个位置一是 A2A 端点本身的鉴权二是服务端调 TaoToken 时的鉴权。先确认你 curl 时带的Authorization头是否正确再确认服务端环境变量TAOTOKEN_API_KEY有没有真正注入。很多人本地.env写了但容器启动时没挂载进程里读到的是空字符串结果调模型就 401。排查方法在服务端启动日志里打印 Key 的前 6 位别打全确认非空。local proxy failed / connection refused。这个报错通常和网络层有关不是 A2A 协议问题。检查你的TAOTOKEN_BASE_URL是不是写成了带路径的完整地址正确值是https://taotoken.net/api不要多加/v1或结尾斜杠。另外确认服务端所在环境能正常发起 HTTPS 出站请求有些沙箱环境默认禁出站需要放行。reading choices of undefined。这是典型的模型返回结构不符合预期。原因一般是请求体里model字段为空或写错或者返回的其实是错误对象而不是正常 completion。排查时先把原始resp.text打出来别直接取choices。如果返回里是{error: ...}那就是模型层报错按错误信息处理如果返回是空检查请求是否真的发出去了。OAuth / Bearer 混用导致鉴权失败。A2A 的 Agent Card 里authentication.schemes声明了用 Bearer但有些实现会误配成 OAuth 流程客户端拿不到 token。如果你只是内部协作用 Bearer 静态 Key 最简单别一上来就上 OAuth。等链路跑通、需要多租户时再升级鉴权方案。Task 一直 input-required 不推进。这不是报错是状态机没写对。A2A 允许服务端在需要补充信息时把状态置为input-required等客户端再发一条 message 续上。如果你的服务端逻辑里没有处理“续接同一 Task”的分支就会一直卡住。检查你的 Task 存储是否按taskId关联了多轮消息。Agent Card 拉到了但 url 字段指向错误。客户端会拿 Agent Card 里的url去发 JSON-RPC如果这个字段写的是localhost而客户端在另一台机器就会连接失败。部署时把url配成对外可达的地址别图省事写死 localhost。排障时记住一个原则先分层再定位。A2A 链路分四层——发现层Agent Card、协议层JSON-RPC 格式、模型层TaoToken 调用、网络层出站连通性。哪一层报错就查哪一层别混着改。我见过有人一报错就同时改协议格式和模型配置结果越改越乱。6. 把 A2A 协作链路接进你的统一通道走到这里你已经有了 Agent Card、JSON-RPC 端点、模型调用配置和一套排障对照表。接下来最实际的动作是把这条链路接到你日常用的统一通道上让 A2A 智能体的模型调用和你的其他 AI 应用共用一套 Key。具体怎么做先去 API Keys 页面创建或复用你的 Key把它注入到 A2A 服务端的环境变量里Base URL 统一用https://taotoken.net/apiModel ID 按你的场景选规划类任务选推理强的回复类选轻量的。接入文档里有各语言的调用示例照着改 Base URL 和 Key 就能迁移。如果你打算长期跑多智能体编排、调用频率高Coding Plan 那条通道值得看一下对 Agent 场景的额度更友好。验证模型是否可用可以直接在模型对话页面手动发一条消息确认通道正常再去跑 A2A 请求。这样能把“模型通道”和“A2A 协议”两段分开验证出问题时定位更快。最后给一个实用建议多智能体协作最容易失控的地方不是协议而是上下文传递。A2A 的 Task 支持多轮但你要自己决定哪些上下文放进 message、哪些放进 Artifact。我的做法是——指令和追问放 message结构化结果放 Artifact长文档放 FilePart。这样客户端和服务端的职责清晰后续加智能体也不用重构消息格式。链路跑通只是开始把消息边界设计好这套协作才能长期维护下去。