
1. 多代理协作里A2A 和 MCP 到底谁管什么如果你正在搭一个智能代理系统大概率会遇到一个很具体的困惑我让一个主代理去调度几个子代理子代理又要去查数据库、调天气接口、读本地文件这套东西到底该用 A2A 还是 MCP我一开始也纠结过后来发现这俩根本不是二选一的关系而是分工不同。简单说MCP 管的是「代理怎么用工具」。它把工具、API、数据源包装成模型能理解的结构化描述代理通过 MCP 去调用一个计算器、查一次数据库、读一个文件本质上是「使用能力」请求-响应事务性强行为可预测。A2A 管的是「代理怎么和代理合作」。它让两个独立的代理互相发现对方的能力通过 Agent Card协商交互方式管理一个有状态的、可能跑很久的共享任务本质上是「协作」多轮、动态、带上下文。放到一个真实场景里你有一个客服主代理用户说「帮我查一下上个月的账单为什么多扣了钱」。主代理自己不会查账单它通过 A2A 把任务委托给一个专门的账单代理同时把用户上下文带过去。账单代理接到任务后需要去查数据库、调计费规则接口这些动作它通过 MCP 完成。查完把结果通过 A2A 回传给主代理主代理再组织语言回复用户。你看A2A 负责代理之间的「对话和委托」MCP 负责代理对工具的「调用和执行」两者在一条链路上各司其职。所以这篇要交付的就是一套能跑起来的配置骨架用 settings.json 描述 A2A 的代理注册与协作关系用 config.toml 描述 MCP 的工具接入然后通过 TaoToken 的统一 Key 和 API 通道把模型调用收敛到一个入口最后给你几个具体的检查动作确认代理间协议通信真的生效了而不是配置写完看着像对、跑起来没反应。适合谁看已经在写 Agent 编排逻辑、手里有不止一个代理需要互相调度的开发者或者你刚接触 A2A/MCP想找一个能直接复制、改改就能用的配置起点。下面所有配置都以「可复制、可验证」为标准不堆概念。2. 前置准备用 TaoToken 统一 Key 收敛模型调用入口在写 A2A 和 MCP 配置之前先把模型调用的入口统一掉。原因很实际多代理系统里主代理、子代理、甚至某些工具内部都可能要调模型如果每个代理各配一套 Key 和 endpoint后面排查问题会非常痛苦——你分不清是协议没通还是 Key 配错了。用 TaoToken 做统一通道所有代理的模型请求都走同一个 API 地址和同一把 Key出问题时排查面小很多。TaoToken 在这里的角色是模型调用的统一入口它提供兼容常见接口规范的 API 通道你不需要在每个代理里分别维护不同的供应商配置。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意 API 地址不带 UTM 参数配置里填这个就行。你需要先拿到一把 API Key。进入控制台创建https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面生成https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。生成后先复制存好后面 settings.json 和 config.toml 里都要引用它。建议用环境变量注入不要硬编码进配置文件尤其是这个配置文件要提交到仓库的时候。# 把 Key 放进环境变量配置里用 ${TAOTOKEN_API_KEY} 引用 export TAOTOKEN_API_KEYsk-你的实际key # 验证环境变量生效 echo $TAOTOKEN_API_KEY | head -c 8这里有个容易踩的坑很多人把 Key 直接写进 settings.json 然后提交了后面轮换 Key 的时候要满仓库找。用环境变量引用配置骨架可以放心分享和复用。另外如果你后面要跑长期编码类或 Agent 类的任务可以了解下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合持续性的代理工作负载这里先不展开配置骨架是通用的。3. 可复制配置settings.json 与 config.toml 骨架这一节是核心给你两份能直接改的配置。settings.json 负责 A2A 层面的代理注册、协作关系和模型通道config.toml 负责 MCP 层面的工具服务器接入。两份配置通过同一个 TaoToken Key 和 API 基址关联起来。先看 settings.json。它的结构分三块model 段定义统一模型通道agents 段注册参与协作的代理a2a 段定义代理间的协作规则。{ model: { provider: taotoken, base_url: https://taotoken.net/api, api_key: ${TAOTOKEN_API_KEY}, default_model: claude-sonnet-4-20250514, timeout_seconds: 120 }, agents: [ { id: orchestrator, name: 主调度代理, role: orchestrator, agent_card: { skills: [task_delegation, context_management, result_aggregation], input_modes: [text, structured], output_modes: [text, structured] }, endpoint: http://127.0.0.1:8100/a2a }, { id: billing_agent, name: 账单查询代理, role: worker, agent_card: { skills: [query_billing, explain_charge], input_modes: [text, structured], output_modes: [structured] }, endpoint: http://127.0.0.1:8101/a2a } ], a2a: { discovery: { enabled: true, registry: local, refresh_interval_seconds: 30 }, task: { max_rounds: 12, context_ttl_seconds: 3600, state_store: memory }, transport: { protocol: http, content_type: application/json } } }几个关键点解释一下。model 段的 base_url 填 https://taotoken.net/api api_key 用环境变量引用这样所有代理共享同一个模型通道。agents 段里每个代理都有一张 agent_card这是 A2A 发现机制的核心——主代理通过读取子代理的 card 知道它会什么、接受什么输入、返回什么输出。a2a 段的 discovery 开启本地注册表发现task 段限制最大协作轮数和上下文存活时间防止一个任务无限循环。再看 config.toml这是 MCP 工具服务器的接入配置。它定义代理能用哪些工具以及这些工具怎么启动。# MCP 工具服务器配置骨架 [mcp] version 1.0 default_timeout_ms 30000 # 模型通道同样指向 TaoToken保持与 settings.json 一致 [mcp.model] base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} model claude-sonnet-4-20250514 # 工具服务器一数据库查询 [[mcp.servers]] name db_query command npx args [-y, modelcontextprotocol/server-sqlite, --db, ./data/billing.db] transport stdio enabled true # 工具服务器二本地文件读取 [[mcp.servers]] name file_reader command npx args [-y, modelcontextprotocol/server-filesystem, ./data] transport stdio enabled true # 工具服务器三HTTP 接口调用用于外部 API [[mcp.servers]] name http_tools command npx args [-y, modelcontextprotocol/server-fetch] transport stdio enabled true # 工具权限控制哪些代理能用哪些工具 [mcp.permissions] orchestrator [file_reader] billing_agent [db_query, http_tools]config.toml 里每个 [[mcp.servers]] 就是一个 MCP 工具服务器transport 用 stdio 表示通过标准输入输出通信这是本地工具最常见的接入方式。mcp.permissions 段做权限隔离——主调度代理只能读文件账单代理才能查数据库和调外部接口这样即使某个代理被诱导也不会越权操作。两份配置的关联点在于settings.json 的 model 段和 config.toml 的 mcp.model 段都指向同一个 TaoToken 基址和同一把 Key。这样无论请求来自 A2A 协作链路还是 MCP 工具调用链路模型调用都走同一个通道日志和用量也集中在一处。4. 验证请求确认代理间协议通信真的生效配置写完不代表通了。这一节给你三个具体的检查动作从下到上验证MCP 工具能不能被调起来、A2A 代理能不能被发现、端到端的协作任务能不能跑完。第一个检查MCP 工具服务器是否正常启动。用一个最小的 MCP 客户端去列工具列表。# check_mcp.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): params StdioServerParameters( commandnpx, args[-y, modelcontextprotocol/server-sqlite, --db, ./data/billing.db], ) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools await session.list_tools() for t in tools.tools: print(f工具名: {t.name} | 描述: {t.description}) asyncio.run(main())跑通的话你会看到类似工具名: query | 描述: Run a read-only SQL query的输出。如果这里报错说明 MCP 服务器本身没起来先别往下查 A2A把工具服务器的问题解决掉。第二个检查A2A 代理发现是否生效。启动你的代理服务后用 curl 去拉主代理的 agent card确认它能被注册表发现。# 拉取主代理的 agent card curl -s http://127.0.0.1:8100/a2a/.well-known/agent-card | python -m json.tool # 预期输出包含 skills 列表和 endpoint # { # id: orchestrator, # skills: [task_delegation, context_management, result_aggregation], # endpoint: http://127.0.0.1:8100/a2a # }如果返回 404 或空检查你的代理服务有没有把 agent card 暴露在/.well-known/agent-card路径下这是 A2A 发现的标准路径。很多框架默认不暴露需要手动注册路由。第三个检查端到端协作任务。发一个需要主代理委托子代理、子代理调 MCP 工具的任务看整条链路是否闭环。# 向主代理发起一个需要协作的任务 curl -s -X POST http://127.0.0.1:8100/a2a/tasks \ -H Content-Type: application/json \ -d { task: 查询用户 U12345 上个月的账单总额, context: {user_id: U12345, period: last_month}, max_rounds: 6 } | python -m json.tool预期返回里应该能看到任务状态从submitted变成working再到completed并且 result 里包含账单金额。如果卡在working不动大概率是 A2A 的 task 轮数限制或上下文 TTL 配得太小回到 settings.json 的 a2a.task 段调大 max_rounds 和 context_ttl_seconds 再试。这三个检查按顺序做能帮你快速定位问题出在哪一层MCP 层、A2A 发现层、还是协作执行层。别跳步我见过太多人一上来就调端到端结果报错信息混在一起根本分不清。5. 本篇常见错排查配置跑不起来八成是下面这几个问题。我按出现频率排一下你对照着查。第一个Key 没生效报 401 或 403。最常见的原因是环境变量没导出或者配置文件里写的是${TAOTOKEN_API_KEY}但运行环境读不到。检查方法在启动代理的同一个 shell 里echo $TAOTOKEN_API_KEY确认有值。如果你用 systemd 或 docker 启动环境变量要在对应的 service 文件或 compose 里注入不是在你当前终端 export 就完事。另外确认 base_url 填的是https://taotoken.net/api不要多加路径或斜杠。第二个MCP 工具服务器启动失败报 command not found。config.toml 里用的是npx如果你的环境没装 Node.js 或者 npx 不在 PATH 里就会失败。先which npx确认。另一个常见原因是-y参数在某些 npx 版本里行为不一致可以改成先全局安装再直接调用命令。还有stdio 类型的服务器如果往 stdout 打了非协议内容比如调试日志会污染通信流导致解析失败检查你的工具服务器有没有把日志打到 stderr 而不是 stdout。第三个A2A 代理发现不到对方报 agent not found。检查两点一是 agent card 的 endpoint 地址是否可达用 curl 直接打一下二是 discovery 的 registry 配置本地模式下所有代理要在同一个注册表里注册如果你用了local但代理跑在不同进程需要确认它们共享同一个注册表文件或服务。refresh_interval_seconds 设得太大会导致新注册的代理要等很久才被发现调试阶段可以设成 5 秒。第四个协作任务卡在 working 不结束。这是 A2A 任务状态机的问题。先看 max_rounds 是不是太小主代理和子代理来回几轮就用完了再看 context_ttl_seconds如果任务跑得久但上下文过期了子代理会拿不到之前的对话状态。还有一个隐蔽的坑state_store 用memory时代理进程重启上下文就丢了长任务建议换成持久化存储。调试时把日志级别调到 debug看每一轮 A2A 消息的收发情况。第五个模型调用超时。settings.json 里 timeout_seconds 默认 120如果你的任务涉及多轮推理加工具调用可能不够。但别一上来就调到很大先确认是不是网络问题或模型本身响应慢。可以单独用模型对话页面测一下同一个模型的响应速度https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 如果那边正常说明是你代理链路里的问题不是模型通道的问题。排查的核心思路是分层先确认模型通道通Key 和 base_url再确认 MCP 工具能起再确认 A2A 能发现最后才是协作逻辑。每一层都有独立的验证方法别混在一起调。6. 接入文档与后续动作配置骨架跑通之后你大概率会想改一些东西换模型、加工具、调协作策略。这时候别凭感觉改先看文档。接入相关的完整说明在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有 API 通道的详细参数和常见接入方式。如果你用的是 Claude Code 这类工具做代理开发Anthropic 兼容接入的说明在 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 配置方式略有不同但 Key 和基址是同一套。后续如果要跑长期编码或 Agent 任务Coding Plan 那条线更适合持续负载https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。短期调试和验证用按量通道就够了不用一上来就上套餐。最后说一个我自己的经验A2A 和 MCP 的配置骨架搭好之后先别急着加复杂工具和多个代理。用两个代理、一个工具的最小组合跑通端到端确认发现、委托、工具调用、结果回传这条链路没问题再往上加。每加一个代理或一个工具就重跑一遍第 4 节的三个检查。这样出问题时你永远知道是刚加的那部分导致的而不是在一堆配置里大海捞针。配置这东西能跑通的最小版本比看起来完整的复杂版本值钱得多。