1. 为什么多 Agent 协作总在“最后一公里”卡住
A2A(Agent2Agent)协议是一套让不同来源、不同框架构建的 AI Agent 之间互相发现、互相派活、互相回传结果的开放通信规范。它要解决的问题很具体:你手上有 Cline 写代码、有 CC Switch 管配置、有独立的检索 Agent、有跑在另一台机器上的数据分析 Agent,它们各自都能干活,但彼此之间没有统一的“对话语言”。A2A 就是给它们定一套基于 HTTP、SSE 和 JSON-RPC 的通用语言,让一个 Agent 能像调用远程服务一样调用另一个 Agent。
它适合谁?适合已经在用 Cline、CC Switch、Claude Code 这类工具,并且开始觉得“一个模型干所有事”不够用的开发者。比如你让 Cline 写后端接口,同时希望它把前端页面的生成任务转交给另一个专门做 UI 的 Agent,最后把两边产物合并——这个“转交”和“合并”的动作,就是 A2A 的典型场景。
但真正落地时,卡住大家的往往不是协议本身,而是三件事:第一,每个 Agent 都要单独配 Key、配 Base URL,配置散落在 settings.json、config.toml、.env 里,改一处漏一处;第二,Agent 之间通信需要稳定的 API 通道,通道一断,任务状态就丢;第三,报错信息不透明,401、local proxy failed、OAuth 失败混在一起,不知道是 Key 的问题还是端点的问题。
我试过把多个 Agent 的接入点统一到一个 Key 下管理,配合 A2A 的 AgentCard 发现机制,配置量能压下来一大半。下面就把这套配置骨架和验证动作拆开讲。
2. TaoToken 统一 Key 作为 A2A 通信底座的前置准备
A2A 协议本身不规定你用哪家模型服务,它只规定 Agent 之间怎么说话。但每个 Agent 在“说话”之前,自己得先能调用模型——这就需要一个稳定的 API 通道。如果你有五个 Agent,每个都去单独申请 Key、单独配额度、单独处理限流,维护成本会迅速超过写业务逻辑的成本。
TaoToken 在这里的角色是统一接入点:一个 Key 覆盖多个模型,Base URL 固定,Agent 无论跑在 Cline、CC Switch 还是自己写的脚本里,都指向同一个通道。这样 A2A 的 AgentCard 里声明的url和authentication字段可以保持稳定,不会因为某个 Agent 换了模型供应商就导致整个协作链路断掉。
前置准备分三步。第一步,拿到统一 Key。访问 https://taotoken.net/api-keys 创建,注意这个 Key 同时用于模型调用和 A2A 端点鉴权,不要混用多个 Key。第二步,确认 Base URL。模型调用统一走 https://taotoken.net/api,A2A 的 AgentCard 托管地址则是在你的 Agent 服务域名下加/.well-known/agent.json。第三步,选一个模型 ID。A2A 的 AgentCard 里defaultInputModes和defaultOutputModes不强制绑定模型,但你的 Agent 实现里需要指定,比如claude-3-5-sonnet或gpt-4o,具体可用列表在 https://taotoken.net/models 查。
这里有个容易踩的坑:很多人把 A2A 的端点地址和模型 API 地址写成同一个。实际上 A2A 的url字段指向的是你的 Agent 服务,不是模型服务。模型服务是 Agent 内部调用的,A2A 只负责 Agent 之间的消息传递。分清楚这两层,后面配 settings.json 才不会乱。
另外,如果你用 Claude Code 做 Agent 的“大脑”,它的配置文件和 Cline 不一样。Claude Code 走的是~/.claude/settings.json,而 Cline 走的是 VS Code 的settings.json。两者都要指向同一个 Base URL 和 Key,但字段名不同。下一节给出可复制的骨架。
3. 可复制的 settings.json 与 config.toml 配置骨架
这一节直接给配置。先明确三件套:Base URL、Key、Model ID。无论哪个工具,这三个值必须一致,否则 A2A 协作时会出现“A Agent 能调通、B Agent 调不通”的诡异现象。
Cline 的配置在 VS Code 的settings.json里,关键字段如下:
{ "cline.apiProvider": "openai", "cline.openAiBaseUrl": "https://taotoken.net/api", "cline.openAiApiKey": "sk-你的统一Key", "cline.openAiModelId": "claude-3-5-sonnet", "cline.a2a.agentCardUrl": "http://localhost:41241/.well-known/agent.json", "cline.a2a.enablePushNotification": true }注意cline.a2a.agentCardUrl指向的是本地 A2A Server 的 AgentCard 地址。如果你把 Agent 部署在远程,换成对应域名即可。enablePushNotification打开后,长任务的结果会通过 SSE 回推,不用轮询。
CC Switch 的配置走 TOML,通常在~/.cc-switch/config.toml:
[provider] base_url = "https://taotoken.net/api" api_key = "sk-你的统一Key" model_id = "claude-3-5-sonnet" [a2a] agent_card_path = "/.well-known/agent.json" server_port = 41241 enable_sse = true push_notification_url = "http://localhost:41241/notify" [a2a.auth] schemes = ["Bearer"] credentials = "sk-你的统一Key"这里[a2a.auth]段对应 A2A 协议里 AgentCard 的authentication字段。schemes写Bearer,credentials填同一个 Key。这样其他 Agent 在发现你的 AgentCard 后,知道用 Bearer Token 来鉴权。
如果你用 Codex 或类似工具,配置在auth.json:
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的统一Key", "model": "claude-3-5-sonnet", "a2a": { "agent_card_url": "http://localhost:41241/.well-known/agent.json", "auth_scheme": "Bearer" } }三份配置的核心逻辑一样:模型调用走统一 Base URL 和 Key,A2A 端点单独声明 AgentCard 地址和鉴权方式。配完后,你的 Agent 既是一个能调模型的“工作者”,也是一个能被其他 Agent 发现的“服务端”。
有个细节要注意:A2A 的 AgentCard 里capabilities.streaming如果设为true,你的服务端必须实现 SSE 端点。Cline 和 CC Switch 都内置了 SSE 支持,但如果你自己写 Agent 服务,记得在/tasks/sendSubscribe路由上返回text/event-stream。
4. 连通性验证:从 AgentCard 拉取到任务派发
配完不等于通。验证分四步,每步都有明确的成功标志。
第一步,拉取 AgentCard。在终端执行:
curl -s http://localhost:41241/.well-known/agent.json | jq .成功的话会返回一个 JSON,包含name、description、url、skills等字段。如果返回 404,说明你的 A2A Server 没启动,或者agent_card_path配错了。如果返回 401,说明 AgentCard 本身需要鉴权,检查[a2a.auth]段是否漏了credentials。
第二步,验证模型通道。用同一个 Key 发一个最小请求:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的统一Key" \ -H "Content-Type: application/json" \ -d '{"model":"claude-3-5-sonnet","messages":[{"role":"user","content":"ping"}]}'返回里有choices字段就说明模型通道正常。这一步和 A2A 无关,但必须过,否则 Agent 内部调模型会失败。
第三步,派发一个 A2A 任务。用 JSON-RPC 格式向/tasks/send发请求:
curl -s http://localhost:41241/tasks/send \ -H "Authorization: Bearer sk-你的统一Key" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tasks/send", "params": { "id": "task-001", "message": { "role": "user", "parts": [{"type": "text", "text": "生成一个二分查找的 Python 函数"}] } }, "id": 1 }'成功返回里会有result.status.state,初始是submitted或working。如果返回-32601 Method not found,说明你的服务端没实现tasks/send方法。如果返回-32001 Task not found,检查id字段是否重复。
第四步,订阅任务状态。用 SSE 端点:
curl -N http://localhost:41241/tasks/sendSubscribe \ -H "Authorization: Bearer sk-你的统一Key" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tasks/sendSubscribe","params":{"id":"task-002","message":{"role":"user","parts":[{"type":"text","text":"写一个快速排序"}]}},"id":2}'你会看到流式输出,先是status: working,然后artifact里出现代码片段,最后status: completed。看到completed就说明整条链路通了:AgentCard 发现、鉴权、任务派发、SSE 回推全部正常。
实测下来,最容易出问题的是第三步和第四步之间的状态同步。如果sendSubscribe返回的final一直是false,检查你的服务端有没有在任务完成后发送TaskStatusUpdateEvent且final: true。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
这一节对照真实报错,给出排查动作。
401 Unauthorized。出现在拉 AgentCard 或派发任务时。先确认Authorization头格式是Bearer sk-xxx,不是Basic。再确认 Key 没有多余空格。如果 Key 正确但仍 401,检查 A2A Server 的authentication.schemes是否包含Bearer。有些实现默认只认Basic,需要手动改。
local proxy failed。这个报错通常出现在 Cline 或 CC Switch 启动时,原因是 Base URL 配成了http://localhost:xxxx但本地没有代理服务。解决动作:把base_url改成https://taotoken.net/api,不要用 localhost。如果你确实需要本地代理,确认代理进程在跑,且端口和配置一致。
reading choices 报错。完整信息类似error reading choices: unexpected end of JSON input。这说明模型 API 返回了空响应或非 JSON 响应。排查顺序:先用第 4 节的 curl 命令直接打模型 API,看返回是否正常。如果 curl 正常但 Agent 报错,检查 Agent 的model_id是否拼写正确。常见错误是把claude-3-5-sonnet写成claude-3.5-sonnet,点号和横杠混了。
OAuth 相关报错。如果你用 Claude Code 且看到OAuth token expired或invalid_grant,说明它走的是 OAuth 流程而不是 API Key。解决动作:在~/.claude/settings.json里显式指定apiKey和baseUrl,覆盖 OAuth 配置。字段名是apiKey不是openAiApiKey,注意区分。
AgentCard 拉取成功但任务派发失败。检查 AgentCard 里的url字段是否和实际服务地址一致。如果 AgentCard 写的是http://localhost:41241但你的服务跑在0.0.0.0:41241,某些客户端会解析失败。统一用localhost或统一用 IP。
SSE 流中断。如果sendSubscribe返回一半就断,检查服务端有没有设置Connection: keep-alive和正确的Content-Type: text/event-stream。另外,Nginx 反代默认会缓冲 SSE,需要在配置里加proxy_buffering off。
排查时记住一个原则:先验证模型通道(curl 打 API),再验证 A2A 通道(curl 拉 AgentCard),最后验证任务链路(curl 派发任务)。三层分开测,比混在一起猜快得多。
6. 把统一 Key 和 A2A 端点接进你的日常工具链
配置和验证都跑通后,日常使用就是把这些端点接进你已有的工具链。如果你主要在 Cline 里写代码,把第 3 节的settings.json片段合并进 VS Code 配置,重启 Cline 即可。如果你用 CC Switch 管理多个 Agent,把config.toml里的[a2a]段复制到每个 Agent 的配置块里,只改server_port避免冲突。
长期跑编码任务或 Agent 协作的话,建议把 Key 和端点集中管理。TaoToken 的 Coding Plan 适合这种场景,一个 Key 覆盖多个 Agent 的模型调用,不用每个 Agent 单独充值。具体方案在 https://taotoken.net/coding-plan 看。
如果你更想先手动验证模型对话是否正常,可以直接在 https://taotoken.net/chat 里发一条消息,确认 Key 和模型 ID 没问题,再回去配 A2A。接入文档在 https://taotoken.net/doc,里面有各工具的完整字段说明。
最后给一个实用技巧:把 AgentCard 的skills字段写详细,包括tags和examples。这样其他 Agent 在发现你的 Agent 时,能通过examples里的自然语言描述判断该不该把任务派给你。比如examples: ["生成二分查找代码", "写一个快速排序"],比只写description有效得多。A2A 的发现机制靠的就是这些元数据,写清楚能省掉大量手动路由的代码。