1. 从一份「越写越水」的报告说起:多 Agent 协作到底卡在哪
你大概遇到过这种场面:给一个 AI 助手丢一句「帮我做份 AI 编程工具竞品分析,要行业趋势、技术对比、商业模式和 SWOT」,它开头写得行云流水,越往后越飘,写 SWOT 时几乎忘了前面分析过什么。这不是模型不聪明,而是它的「工作台」太小了。
一个 Agent 的本质可以拆成三样东西:一个大模型、一组工具、一段上下文窗口。这三样各自都有天花板。工具数量上,你不可能给一个 Agent 挂 100 个工具,模型在调用时会效率骤降、频繁混乱;上下文窗口上,128K tokens 听着多,但搜索结果、中间草稿、反思记录会迅速塞满它;专业能力上,让同一个 Agent 既做代码审查又做市场分析,效果往往不如两个各自专精的 Agent。
于是很自然的解法出现了:把任务拆开,交给不同的专业 Agent 并行处理,最后由一个「调度 Agent」汇总。这就是多智能体(Multi-Agent)协作的由来。但多智能体有个绕不开的问题——它们怎么互相认识?Agent A 要把任务委托给 Agent B,前提是它得先知道 B 能干什么。最笨的办法是写死配置,在 A 的代码里硬编码「B 能做竞品分析」,可 B 的能力一变,A 的代码就得跟着改,脆弱且不可维护。
更聪明的做法是让 B 主动「发名片」,声明自己的能力,A 来查询。这就是 A2A 协议里 Agent Card(智能体名片)的设计思路。而与此同时,另一个常被拿来和 A2A 比较的协议 MCP(Model Context Protocol),解决的是完全不同方向的问题。很多人把 A2A 当成 MCP 的竞品或替代品,这是最常见也最要命的误解。这篇就聚焦 A2A 与 MCP 在 Agent 协作中的分工差异,给出可复制的 MCP 服务端配置与 A2A Task 调用示例,并演示通过 TaoToken 统一 Key/API 通道完成一次端到端验证。
先给结论:MCP 解决的是「单个 Agent 怎么连工具和数据」,方向是向下;A2A 解决的是「多个 Agent 之间怎么分工协作」,方向是向外。一个是纵向连接,一个是横向连接,各管一层,谈不上谁替代谁。打个比方,MCP 像是公司里每个员工的「工具箱」,决定这个人能用什么工具干活;A2A 则是公司里的「协作流程」,决定不同岗位的人怎么分工、怎么交接任务。工具箱和协作流程是两码事,缺了哪个都不行。
| 维度 | MCP (Model Context Protocol) | A2A (Agent-to-Agent) |
|---|---|---|
| 连接方向 | 纵向连接(向下) | 横向连接(向外) |
| 核心解决 | 单个 Agent 连接外部工具、API 与数据源 | 多个 Agent 之间的服务发现、任务外包与协同 |
| 形象比喻 | 员工手中的「专业工具箱」 | 公司跨部门的「业务协作流程」 |
| 核心交互协议 | JSON-RPC 规范 | HTTP + Agent Card (.json) + Task 状态机 |
| 典型调用单位 | Tool / Resource / Prompt | Task(带状态机) |
在一个复杂的多智能体系统里,这两者通常同时在用:MCP 负责每个 Agent 与工具之间的纵向连接,A2A 负责 Agent 之间的横向协作,合在一起才能支撑起真正复杂的 Agent 系统。下面我们就把这两层都跑通一遍。
2. TaoToken 统一 Key 通道:给多 Agent 系统一个稳定的模型入口
多 Agent 系统跑起来之后,你会发现一个很现实的问题:调度 Agent、调研 Agent、写作 Agent、代码审查 Agent,每个都要调模型。如果每个 Agent 各自配一套 Key、各自记一套 Base URL,配置会迅速失控,排查问题时你甚至不知道是哪个 Agent 的哪套凭证出了问题。
我试过把模型入口统一收口到 TaoToken 的 API 通道上,思路很简单:所有 Agent 的模型调用都指向同一个 Base URL,用同一把 Key,模型 ID 按需切换。这样多 Agent 协作时,模型这一层是稳定的、可观测的,出问题只可能是协议层或业务层,排查范围一下子缩小了。
TaoToken 在这里扮演的角色是「统一 Key/API 通道」:它提供兼容 OpenAI 风格的接口,你不需要为每个 Agent 单独申请凭证,也不需要改代码里的调用逻辑,只要把 Base URL 和 Key 换成统一的即可。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api (这个不加 UTM)。
具体来说,你需要准备三件套:
- Base URL:
https://taotoken.net/api - API Key:在控制台创建,形如
sk-xxxx - Model ID:按你实际要用的模型填,比如
claude-sonnet-4-5、gpt-4o之类,以控制台实际可用的为准
这三件套在后面的 MCP 服务端配置和 A2A Task 调用里都会用到。为什么要强调「统一」?因为 A2A 的调度 Agent 在派任务时,接收方 Agent 内部可能用 MCP 调工具、调模型,如果每个 Agent 的模型入口都不一样,你很难判断一次 Task 失败到底是协议问题还是某个 Agent 的模型凭证过期了。统一通道之后,模型层的问题基本可以一次性排除。
创建 Key 的入口在控制台的 API Keys 页面,路径是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。拿到 Key 之后先别急着写代码,用一条 curl 验证通道是否通,这一步能省掉后面大量「到底是配置错还是网络错」的纠结。
curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "claude-sonnet-4-5", "messages": [ {"role": "user", "content": "只回复两个字:通了"} ] }'如果返回里能看到choices数组和正常的content,说明通道没问题。这一步的返回结构和你后面在 Agent 里拿到的结构是一致的,所以先在这里确认字段名,能避免在 Agent 代码里反复猜。
注意:Base URL 填
https://taotoken.net/api,具体请求路径是/v1/chat/completions。有些客户端要求 Base URL 带/v1,有些要求不带,以你用的 SDK 文档为准,但根地址始终是https://taotoken.net/api。
3. 可复制配置:MCP 服务端 + A2A Task 调用示例
这一节是全文的核心,我们把 MCP 服务端配置和 A2A Task 调用都写成可直接复制的片段。先明确分工:MCP 服务端负责把「工具」暴露给 Agent,A2A 负责把「任务」在 Agent 之间传递。两者配置的格式完全不同,别混在一起。
3.1 MCP 服务端配置(JSON 片段)
MCP 服务端通常以 stdio 或 HTTP 两种方式运行。下面是一个 stdio 方式的 MCP 服务端配置,放在客户端的 MCP 配置文件里(不同客户端路径不同,Claude Desktop 一般是claude_desktop_config.json,Cline 在设置里直接填)。这里我们让 MCP 服务端本身去调用模型时也走 TaoToken 统一通道:
{ "mcpServers": { "taotoken-tools": { "command": "npx", "args": ["-y", "@your-scope/mcp-server-demo"], "env": { "OPENAI_BASE_URL": "https://taotoken.net/api", "OPENAI_API_KEY": "sk-你的Key", "OPENAI_MODEL": "claude-sonnet-4-5" } } } }这段配置里三件套齐全:Base URL、Key、Model ID 都在env里。MCP 服务端启动后会通过 stdio 和客户端通信,客户端(也就是 Agent)就能看到这个服务端暴露出来的工具列表。如果你用的是 HTTP 方式的 MCP 服务端,配置会变成"url": "http://localhost:3000/mcp"这种形式,但env里的三件套逻辑不变。
3.2 A2A Agent Card(JSON 片段)
A2A 的「发名片」机制,规范推荐路径是/.well-known/agent-card.json。一个最小的 Agent Card 长这样:
{ "name": "research-agent", "description": "负责行业调研与竞品分析", "url": "http://localhost:8080/a2a", "version": "1.0.0", "capabilities": { "streaming": true, "pushNotifications": true }, "skills": [ { "id": "competitor-analysis", "name": "竞品分析", "description": "输入一个产品名,输出行业趋势、技术对比、商业模式与 SWOT", "examples": ["分析 AI 编程工具的竞争格局"] } ] }名片里最关键的是skills列表,每个 Skill 描述一类能力并附带示例输入。调度 Agent 就是靠这些描述做路由决策:「这个任务和哪个 Agent 的哪个 Skill 最匹配?」这套机制让多智能体系统变得可插拔——新增一个 Agent,只要发布它的名片,调度 Agent 就能自动发现并使用它,无需改动任何代码。
3.3 A2A Task 调用示例(Python)
A2A 中协作的基本单位是 Task。调度 Agent 把一段活委托出去,就是创建一个 Task;接收方执行;完成后把结果作为 Task 的产出(artifacts)返回。Task 有一套完整的状态机:刚创建时是submitted,接收方开始执行后变为working,最终进入completed或failed。
下面是一个用 Python 发起 A2A Task 的示例,注意接收方 Agent 内部调模型时同样走 TaoToken 统一通道:
import requests import time A2A_ENDPOINT = "http://localhost:8080/a2a" TAOTOKEN_BASE = "https://taotoken.net/api" TAOTOKEN_KEY = "sk-你的Key" # 1. 先取名片,确认对方能力 card = requests.get("http://localhost:8080/.well-known/agent-card.json").json() print("发现 Agent:", card["name"], "技能:", [s["id"] for s in card["skills"]]) # 2. 提交一个 Task task_payload = { "jsonrpc": "2.0", "id": "task-001", "method": "tasks/send", "params": { "skillId": "competitor-analysis", "input": {"text": "分析 AI 编程工具的竞争格局"} } } resp = requests.post(A2A_ENDPOINT, json=task_payload).json() task_id = resp["result"]["id"] print("Task 已提交:", task_id, "状态:", resp["result"]["status"]) # 3. 轮询状态,直到 completed 或 failed while True: status_payload = { "jsonrpc": "2.0", "id": "task-001-status", "method": "tasks/get", "params": {"id": task_id} } status = requests.post(A2A_ENDPOINT, json=status_payload).json()["result"] print("当前状态:", status["status"]) if status["status"] in ("completed", "failed"): break time.sleep(2) # 4. 取 artifacts if status["status"] == "completed": for artifact in status.get("artifacts", []): print("产出:", artifact)这段代码把 A2A 的核心流程走了一遍:取名片 → 提交 Task → 轮询状态 → 取产出。从调度 Agent 的视角看,整个过程干净利落:提交一个 Task,隔段时间查一下状态,等到completed了去取 artifacts。至于对方内部用了什么工具、调了几次大模型,完全不可见,是彻底的黑盒。这正是解耦的意义。
提示:A2A 是专为长任务设计的。一个竞品分析可能要跑好几分钟,调度 Agent 不可能同步傻等,所以提交任务后可以转头去干别的,通过轮询状态、或者接收方在完成时主动回调(Push Notification)来得知结果。上面的示例用的是轮询,生产环境里如果接收方支持
pushNotifications,优先用回调。
3.4 把两层串起来
现在把 MCP 和 A2A 串起来看:接收方 Agent(research-agent)内部通过 MCP 连接搜索工具、数据库、文件系统,这些是它的「工具箱」;它对外通过 A2A 暴露competitor-analysis这个 Skill,这是它的「名片」。调度 Agent 不需要知道 research-agent 内部用了哪些 MCP 工具,只需要看名片、派 Task、收结果。
而模型这一层,两个 Agent 都指向https://taotoken.net/api,用同一把 Key。这样整个系统的模型入口是统一的,协议层是分层的,排查问题时边界清晰。
4. 端到端验证:一次请求跑通 MCP 工具调用与 A2A 任务外包
配置写完,最关键的是验证。很多人配完就以为通了,结果第一次真实调用才发现字段名不对、状态机没走完、artifacts 是空的。这一节我们做一次端到端验证,把 MCP 工具调用和 A2A 任务外包都跑一遍。
4.1 验证 MCP 服务端是否被正确加载
先确认 MCP 服务端能被客户端识别。以 Cline 为例,配置好之后打开 MCP 面板,应该能看到taotoken-tools这个服务端,展开后能看到它暴露的工具列表。如果看不到,先检查command和args是否能手动执行成功:
npx -y @your-scope/mcp-server-demo --help如果这条命令报错,说明是服务端本身的问题,和 MCP 配置无关。如果命令能跑但客户端里看不到,多半是配置文件路径不对或者 JSON 格式有误。JSON 里多一个逗号都会导致整个配置加载失败,建议用python -m json.tool校验一下:
python -m json.tool claude_desktop_config.json4.2 验证 A2A 名片可访问
A2A 的第一步是取名片。用 curl 直接访问名片路径:
curl http://localhost:8080/.well-known/agent-card.json返回的 JSON 里应该有name、skills等字段。如果返回 404,检查你的 A2A 服务端是否真的在/.well-known/agent-card.json这个路径上暴露了名片——规范推荐这个路径,但有些实现会放在别处,以你的服务端文档为准。
4.3 验证 Task 状态机走完
跑一遍 3.3 的 Python 示例,观察输出。正常情况下你会看到状态从submitted变成working,最后变成completed,然后打印出 artifacts。如果状态一直卡在submitted,说明接收方没有开始处理,可能是skillId不匹配,或者接收方内部调模型时卡住了。
这里就是 TaoToken 统一通道发挥作用的地方。如果接收方内部调模型失败,你会在接收方的日志里看到模型调用的错误,而不是 A2A 协议层的错误。因为模型入口是统一的,你可以直接用 3.1 里的 curl 命令验证通道是否正常,快速排除模型层问题。
4.4 验证模型调用确实走了统一通道
想确认 Agent 内部真的走了 TaoToken 通道,最直接的办法是在接收方 Agent 的日志里打印实际使用的 Base URL。或者在 TaoToken 控制台的用量页面看调用记录,路径是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。如果一次 A2A Task 跑完,用量页面能看到对应的调用记录,说明模型层确实走了统一通道。
如果你更想先在对话界面里手动验证模型是否可用,可以打开模型对话页面 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,选一个模型发一句话,确认返回正常。这一步和 Agent 里的调用是同一套通道,能通就说明凭证没问题。
4.5 一次完整的成功结果长什么样
把上面几步串起来,一次成功的端到端验证应该是这样的:
- MCP 面板里能看到
taotoken-tools及其工具列表; curl http://localhost:8080/.well-known/agent-card.json返回包含competitor-analysis的名片;- Python 脚本提交 Task 后,状态依次经过
submitted→working→completed; - artifacts 里能看到竞品分析的文本产出;
- TaoToken 控制台用量页面能看到对应的模型调用记录。
这五步都过了,说明 MCP 的纵向连接和 A2A 的横向协作都通了,模型层也统一了。任何一步没过,就按下一节的排查思路定位。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
配置和验证过程中,报错基本集中在几个固定位置。这一节按真实报错来对照排查,每个都给出定位思路。
5.1 401 Unauthorized
这是最常见的。出现 401 基本就是 Key 的问题,分几种情况:
- Key 复制时带了空格或换行。重新从控制台复制一次,注意首尾不要有空白字符。
- Key 已经失效或被删除。去控制台 API Keys 页面确认 Key 状态,路径是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
- 请求头格式不对。必须是
Authorization: Bearer sk-xxxx,Bearer和 Key 之间有一个空格,别写成Bearer: sk-xxxx。
如果你在 MCP 服务端的env里配了 Key,但服务端代码里读的是别的环境变量名,也会导致 401。检查服务端文档里要求的变量名,常见的是OPENAI_API_KEY或API_KEY,别想当然。
5.2 local proxy failed
这个报错通常出现在客户端尝试连接 MCP 服务端或 A2A 服务端时。字面意思是本地连接失败,实际原因往往是:
- 服务端根本没启动。先手动跑一遍服务端启动命令,确认它能起来。
- 端口被占用。换个端口,或者把占用端口的进程关掉。
- 地址写错。
localhost和127.0.0.1在大多数情况下等价,但如果服务端只监听了 IPv6 的::1,用127.0.0.1就连不上。反过来也一样。
排查这类问题,先用curl直接访问服务端地址,能通说明服务端没问题,问题在客户端配置;不能通说明服务端本身没起来或地址不对。
5.3 reading choices 相关报错
这个报错通常出现在解析模型返回时。典型信息是「cannot read property 'choices' of undefined」或类似。原因是返回结构和你预期的不一样,常见情况:
- 请求根本没成功,返回的是一个错误对象,里面没有
choices字段。先打印完整返回体,看error字段说了什么。 - Base URL 配错,请求打到了别的路径上,返回了 HTML 或 404 页面。确认 Base URL 是
https://taotoken.net/api,请求路径是/v1/chat/completions。 - 模型 ID 写错,服务端返回错误。确认 Model ID 和控制台里可用的一致。
处理这类问题的通用办法是:在解析choices之前,先把原始返回打印出来。多打一行日志,能省半小时猜测。
5.4 OAuth 相关报错
如果你用的是 Claude Code 这类工具,可能会遇到 OAuth 相关的报错。这类工具通常有自己的登录流程,但如果你要走统一 Key 通道,需要在配置里显式指定 Base URL 和 Key,而不是走 OAuth 登录。以 Claude Code 为例,配置里需要写全三件套:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }注意这里的变量名是ANTHROPIC_前缀,因为 Claude Code 用的是 Anthropic 风格的接口。如果你把它和 OpenAI 风格的OPENAI_BASE_URL混用,就会出问题。不同工具的变量名不同,以工具文档为准,但三件套的逻辑是一样的:Base URL、Key、Model ID。
注意:出现 OAuth 报错时,先确认你是不是同时配了 OAuth 登录和 API Key。两者只能选一个,同时配会冲突。走统一 Key 通道就不要再走 OAuth 登录流程。
5.5 状态机卡住不动
A2A Task 提交后状态一直不变,也是高频问题。除了前面说的skillId不匹配,还有一个常见原因是接收方 Agent 内部调模型超时了,但错误没有正确传播到 Task 状态上。这时候去看接收方的日志,如果里面有模型调用的超时或错误,说明问题在模型层,不在 A2A 协议层。用 3.1 的 curl 验证通道,确认模型入口正常。
排查的核心思路始终是:先分层,再定位。模型层用 curl 验证,MCP 层看工具列表,A2A 层看名片和状态机。三层各自独立验证,比混在一起猜要快得多。
6. 把统一通道接进你的多 Agent 工作流
回到开头那个问题:为什么单 Agent 写长报告会越写越水?因为工具、上下文、专业能力三样都有天花板。解法是把任务拆开,让专业 Agent 并行处理,调度 Agent 汇总。而要让这套协作跑起来,你需要两层协议:MCP 负责每个 Agent 与工具的纵向连接,A2A 负责 Agent 之间的横向协作。
这两层配好之后,模型入口用 TaoToken 统一 Key 通道收口,整个系统的边界就清晰了:模型层稳定可观测,协议层各司其职,业务层专注在任务拆分和结果汇总上。出问题时按层排查,不用在「到底是 Key 错了还是协议错了」之间反复横跳。
如果你准备把这套接进自己的多 Agent 工作流,建议的起步顺序是:先用 curl 验证 TaoToken 通道,再把 MCP 服务端配好并确认工具列表可见,然后跑通 A2A 的名片获取和 Task 状态机,最后把两层串起来做一次端到端验证。每一步都单独验证,别跳步。
长期跑编码类或 Agent 类任务的话,可以关注一下 Coding Plan 相关的入口 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。先把这篇里的 MCP 配置和 A2A Task 示例跑通,再按文档把三件套填进你实际用的工具里,基本就能把多 Agent 协作的骨架搭起来了。