1. 从一次多 Agent 联调失败说起:A2A 协议到底解决什么问题
如果你正在做多智能体协作,大概率遇到过这种场景:一个负责检索的 Agent 和一个负责写作的 Agent 各自跑得好好的,一旦要让它们串起来干活,就得手写一堆 HTTP 胶水代码,字段对不上、状态不同步、认证各搞一套。A2A(Agent-to-Agent Protocol)就是 Google 针对这个问题推出的开源协议,它给 Agent 之间的通信定了一套标准:能力怎么声明、任务怎么下发、状态怎么流转、结果怎么回传。简单说,A2A 让「Agent 调用 Agent」变得像调用一个规范化的 REST 服务,而不是每次重新发明轮子。
它适合谁?如果你在做编排型应用(一个主控 Agent 调度多个专业 Agent)、跨团队共享 Agent 能力、或者想把内部 Agent 暴露成可被发现的服务,A2A 就是那层你迟早要补上的协议。它和 MCP 是互补关系:MCP 管「模型怎么调工具和数据源」,A2A 管「Agent 之间怎么协作」。一个典型的完整技术栈是上层用 A2A 做 Agent 编排,下层用 MCP 接工具。
我试过把两个自研 Agent 用裸 HTTP 对接,光是任务状态机就写了两百多行还漏洞百出。换成 A2A 的 Agent Card + 任务生命周期模型后,协议层的事情基本不用自己操心了。这篇就按「概念 → 配置 → 联调 → 排障 → 凭证统一管理」的顺序,把可复制的片段都给你,重点放在能直接跑起来的部分。
核心检索词先明确:A2A 协议是什么、能做什么、适合谁。A2A 是 Agent-to-Agent 的标准化通信框架,核心产物是 Agent Card(能力声明 JSON)和任务(Task)模型,适合多智能体协作场景。下面所有配置都围绕这两个概念展开。
2. TaoToken 统一 Key 通道:多 Agent 调用凭证的前置准备
多 Agent 协作有个容易被忽略的痛点:每个 Agent 背后都要调大模型,如果每个 Agent 各配一套 Key,凭证管理会迅速失控——轮换、限额、审计全乱套。TaoToken 在这里的角色是统一 Key/API 通道,把多个 Agent 的模型调用凭证收敛到一处集中管理。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api (这个不加 UTM)。
为什么要在 A2A 场景里先讲这个?因为 A2A 的 Agent Card 里有一块authentication字段,声明的是 Agent 之间怎么认证;而 Agent 内部调模型用的是另一套凭证。这两层要分开管:Agent 间认证用 A2A 自己的 bearer/oauth2,模型调用统一走 TaoToken 的 Key。这样你换模型、加 Agent、做限额,都只动一个地方。
前置准备分三步。第一步,拿到统一 Key:登录后在控制台创建 API Key,路径是 console 页面下的 api-keys 管理。第二步,确认你要用的模型 ID,比如做编排的主控 Agent 用推理强的模型,做格式化的子 Agent 用轻量模型,模型 ID 在模型对话页面能查到。第三步,把 Base URL 和 Key 写进各 Agent 的环境变量,不要硬编码进 Agent Card。
这里有个关键区分要讲清楚:A2A 协议里的authentication.schemes是给「别的 Agent 来调我这个 Agent」用的,不是给「我调模型」用的。很多人第一次配会混。正确的分层是——Agent Card 声明对外认证方式(bearer token),Agent 内部代码用 TaoToken 的 Base URL + Key + Model ID 去请求模型。两层各管各的,互不干扰。
如果你打算长期跑多 Agent 编排或 Agent 类编码任务,可以考虑 Coding Plan,它更适合持续性的 Agent 调用场景;只是临时验证模型连通性,用模型对话就够了。接入细节和字段说明看接入文档,避免自己猜参数。
3. 可复制的 A2A 服务端配置片段
这一节给可直接粘贴的配置。先看 Agent Card,这是 A2A 的核心,用 JSON 描述能力、端点、认证和技能。下面这份是服务端要暴露的agent-card.json,路径放在服务根目录,由/.well-known/agent.json对外提供:
{ "name": "EmailAnalyzerAgent", "description": "邮件内容分析与摘要生成 Agent", "url": "http://localhost:8080", "version": "1.0.0", "capabilities": { "streaming": true, "pushNotifications": false, "stateTransitionHistory": true }, "authentication": { "schemes": ["bearer"] }, "defaultInputModes": ["text"], "defaultOutputModes": ["text", "structured"], "skills": [ { "id": "email_summarization", "name": "邮件摘要", "description": "提取邮件关键信息和行动项", "inputSchema": { "type": "object", "properties": { "emailContent": { "type": "string" } }, "required": ["emailContent"] } } ] }注意url字段:本地联调写http://localhost:8080,上线换成真实域名。authentication.schemes只写bearer,表示别的 Agent 调你时带 Bearer Token。
接着是 Agent 内部调模型的配置。用 TOML 写一份agent-config.toml,把 TaoToken 的 Base URL、Key、Model ID 三件套集中管理:
[model] base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" model_id = "your-model-id" timeout_seconds = 60 max_retries = 3 [a2a] agent_card_path = "./agent-card.json" listen_host = "0.0.0.0" listen_port = 8080 auth_token = "${A2A_BEARER_TOKEN}" [task] max_concurrent = 10 state_history = true三件套对应关系要记牢:Base URL 是https://taotoken.net/api,Key 从环境变量TAOTOKEN_API_KEY注入,Model ID 填你在模型对话里确认过的那个。auth_token是 A2A 层对外认证用的,和模型 Key 完全独立。
如果你用 Claude Code 或类似工具做 Agent 开发,配置通常落在settings.json里,结构类似:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "${TAOTOKEN_API_KEY}", "ANTHROPIC_MODEL": "your-model-id" } }这里同样三件套齐全:Base URL、Key、Model ID。用 Cline 或带 MCP 的客户端时,MCP 配置里也要把这三件套写全,否则会出现「连上了但模型不响应」的情况。Codex 用户如果走auth.json,字段名可能是base_url/api_key/model,本质还是这三样。
配置写完,启动服务前先做一次静态检查:Agent Card 的 JSON 能不能被解析、TOML 里的环境变量有没有真的注入、端口有没有被占用。这三步能挡掉后面一大半报错。
4. 本地联调验证:从发任务到拿到结果
配置就绪后,联调分四步:起服务、拉 Agent Card、发任务、查状态。先起服务,假设你用 Python 的 HTTP transport:
export TAOTOKEN_API_KEY="你的Key" export A2A_BEARER_TOKEN="本地联调用的token" python -m your_agent.server --config ./agent-config.toml服务起来后,第一件事是验证 Agent Card 能被发现:
curl -s http://localhost:8080/.well-known/agent.json | python -m json.tool预期返回就是第 3 节那份 JSON,name、skills、capabilities字段都在。如果这里返回 404,说明 Agent Card 的暴露路径没配对,检查服务端路由。
第二步,发一个任务。A2A 的任务下发走POST /tasks/send:
curl -s -X POST http://localhost:8080/tasks/send \ -H "Authorization: Bearer 本地联调用的token" \ -H "Content-Type: application/json" \ -d '{ "id": "task-001", "message": { "role": "user", "parts": [ { "type": "text", "text": "请分析这封邮件的情感倾向" } ] }, "metadata": { "action": "email_summarization", "trace_id": "trace-001" } }' | python -m json.tool预期返回里status.state先是submitted或working,任务完成后变completed,artifacts里带结果。如果开了 streaming,会先收到若干 chunk 再收到 complete 信号。
第三步,查任务状态:
curl -s -X POST http://localhost:8080/tasks/get \ -H "Authorization: Bearer 本地联调用的token" \ -H "Content-Type: application/json" \ -d '{"id": "task-001"}' | python -m json.tool预期state字段在submitted → working → completed之间流转,stateTransitionHistory为 true 时还能看到完整转换记录。
第四步,验证模型调用真的通了。这一步最容易出问题,因为 A2A 层通了不代表模型层通了。单独打一次模型请求:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-id", "messages": [{"role": "user", "content": "ping"}] }' | python -m json.tool预期返回choices数组,里面有模型回复。如果这一步失败,问题在模型凭证层,跟 A2A 无关,先修这里。四步都过,说明 A2A 协议层和模型调用层都通了,可以开始接第二个 Agent 做真正的多 Agent 协作。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
联调阶段报错集中在四类,逐个对照。
401 Unauthorized。两种可能:A2A 层的 bearer token 不对,或者模型层的 Key 不对。区分方法——如果/.well-known/agent.json能拉到但/tasks/send返回 401,是 A2A 层 token 问题,检查A2A_BEARER_TOKEN和请求头是否一致;如果 A2A 全通但模型请求 401,是 TaoToken Key 问题,检查TAOTOKEN_API_KEY是否注入、有没有多余空格。注意 Key 不要写进 Agent Card,那是给别的 Agent 看的,不是放密钥的地方。
local proxy failed。这个报错通常出现在客户端配置了本地代理但代理没起来,或者 Base URL 写成了本地地址。检查你的base_url是不是https://taotoken.net/api,别写成http://localhost之类。如果客户端有代理相关配置项,确认它指向的是正确的 API 基址,而不是一个不存在的本地端口。
reading choices 相关报错(类似cannot read property 'choices' of undefined)。这是模型返回体结构不符合预期,常见原因是 Model ID 写错导致返回了错误对象,或者请求根本没到模型层。排查顺序:先确认 Model ID 和模型对话页面里的一致,再确认 Base URL 结尾没有多余斜杠,最后看返回体原始内容——如果返回的是{"error": ...},说明请求被拒,不是解析问题。
OAuth 相关报错。A2A 的authentication.schemes如果声明了oauth2,但服务端没实现对应的 token 校验,就会在握手阶段失败。本地联调建议先用bearer简化,等协议层跑通再上 OAuth。如果必须用 OAuth,检查 clientId、clientSecret、scopes 三件套是否齐全,scopes 要和 Agent Card 里声明的一致。
排查通用动作:把请求的原始返回体打出来看,别只看封装后的异常信息。A2A 的错误经常被客户端包装过,原始体里才有真正的 error_code。另外,任务卡在working不动的,多半是模型调用超时,把timeout_seconds调大或检查网络到 API 基址的连通性。
6. 把凭证收敛到一处:多 Agent 场景的长期做法
多 Agent 跑起来之后,凭证管理会变成主要矛盾。假设你有五个 Agent,每个都调模型,如果每个 Agent 各配一套 Key,轮换一次要改五处,限额也没法统一看。正确做法是所有 Agent 的模型调用都走同一个 TaoToken 通道,Key 只在环境变量里注入一次,Agent Card 里只声明 A2A 层的认证,不碰模型 Key。
具体落地:每个 Agent 的agent-config.toml里base_url和api_key都指向同一套,model_id按 Agent 职责区分。这样你换模型只改配置,轮换 Key 只改环境变量,审计时所有调用都从一个出口走。Agent 之间用 A2A 的 bearer token 互相认证,和模型凭证彻底解耦。
验证模型连通性用模型对话页面,长期跑 Agent 编排或编码任务用 Coding Plan,接入参数和字段说明查接入文档,Key 的创建和轮换在 api-keys 管理。这套组合下来,你的多 Agent 系统在凭证层就是收敛的,不会随着 Agent 数量增长而失控。
最后给一个实用技巧:给每个 Agent 的请求都带上trace_id,从 A2A 任务层一路透传到模型调用层。这样出问题时,你能从一条 trace 串起「哪个 Agent 发的任务 → 任务状态怎么流转 → 模型调用返回了什么」,排查效率比翻多个日志文件高得多。A2A 的metadata字段就是干这个用的,别浪费。