1. 谷歌A2A协议到底在解决什么问题
如果你最近在折腾多 Agent 系统,大概率会遇到一个很具体的痛点:你写了一个负责查资料的 Agent,又写了一个负责写代码的 Agent,还想再加一个负责跑测试的 Agent,结果发现它们之间根本没法好好说话。每个 Agent 都有自己的输入输出格式,A 的输出要手动转成 B 能吃的结构,B 跑完又要拼成 C 的入参,最后整个流程像用胶带粘起来的积木,动一下就散。
谷歌提出的 A2A 协议,全称 Agent-to-Agent Protocol,就是冲着这个场景来的。它是一套开放标准,目标是让不同平台、不同框架、甚至不同厂商做出来的 AI 智能体,能够用统一的方式互相发现、互相派活、互相汇报进度。你可以把它理解成 Agent 世界的“普通话”——以前每个 Agent 说自己方言,现在大家约定一套通用表达,跨系统协作就不用再写一堆适配层了。
它和 MCP 不是一回事,也不是替代关系。MCP 解决的是“模型怎么连外部工具和数据”,比如让模型去查数据库、调 API;A2A 解决的是“Agent 和 Agent 之间怎么协作”,比如一个主 Agent 把任务拆给三个子 Agent 并汇总结果。一个偏纵向的资源接入,一个偏横向的任务协同。实际项目里两者经常一起用:A2A 负责调度,MCP 负责取数。
这篇文章面向想快速理解并落地 A2A 的开发者。我会先讲清楚 A2A 的核心机制,然后给出一套可复制的 TaoToken 统一 Key 与 API 通道配置骨架,最后带你验证 Agent 之间的通信到底有没有生效。整套流程不需要你先把 A2A 规范全文读完,跟着配就能跑通最小示例。
2. TaoToken 前置:统一 Key 与 API 通道准备
多 Agent 协作最烦的事情之一,是每个 Agent 背后可能挂着不同的模型服务,Key 散落在各个配置文件里,改一个环境就要重新对一遍。TaoToken 在这里的作用是提供一个统一的 API 通道,让你用一套 Key 和统一的 base_url 去访问不同模型,Agent 侧只需要认一个入口,不用关心背后换的是哪个模型。
你需要先拿到自己的 API Key。打开控制台页面,登录后在 API Keys 管理里创建一个新 Key,复制出来保存好。这个 Key 后面会写进 Agent 的配置文件里,作为所有模型调用的统一凭证。
- 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
API 的基础地址是https://taotoken.net/api,注意这个地址不带任何查询参数,直接作为 base_url 使用。如果你用的是 OpenAI 兼容的 SDK,把 base_url 指向它,再把 api_key 换成刚创建的 Key,就能直接调通。
提示:Key 不要硬编码在会提交到 Git 的文件里。建议用环境变量注入,或者放在
.env这类被.gitignore忽略的文件中。多 Agent 场景下,所有 Agent 共用同一个 Key 即可,不需要每个 Agent 单独申请。
这里要区分一下:TaoToken 提供的是模型调用的统一通道,它不替代你的 Agent 框架,也不替代编辑器。你的 Agent 逻辑、任务编排还是跑在你自己的代码或框架里,TaoToken 只是让这些 Agent 在调用模型时走同一个口子,省掉多套凭证管理的麻烦。
3. 可复制配置:settings.json 与 config.toml 骨架
下面给两套配置骨架,一套是 JSON 风格(常见于各类 Agent 框架和编辑器插件),一套是 TOML 风格(常见于 Python 侧的工具链)。你可以按自己用的框架挑一套改。
3.1 settings.json 配置骨架
这套结构适合把模型通道和 Agent 定义分开管理。providers段放统一通道,agents段放每个 Agent 的角色和它要用的模型。
{ "providers": { "taotoken": { "base_url": "https://taotoken.net/api", "api_key": "${TAOTOKEN_API_KEY}", "api_type": "openai" } }, "agents": { "planner": { "role": "任务拆解与调度", "provider": "taotoken", "model": "gpt-4o-mini", "system_prompt": "你负责把用户目标拆成可执行的子任务,并分派给其他 Agent。" }, "researcher": { "role": "资料检索与整理", "provider": "taotoken", "model": "gpt-4o-mini", "system_prompt": "你负责根据子任务检索信息并返回结构化摘要。" }, "coder": { "role": "代码生成与修改", "provider": "taotoken", "model": "claude-3-5-sonnet", "system_prompt": "你负责根据需求生成或修改代码,并说明改动点。" } }, "a2a": { "enabled": true, "agent_card_path": "./agent_cards", "task_timeout_seconds": 300, "transport": "json-rpc" } }几个关键点说明一下。base_url固定写https://taotoken.net/api,不要在后面加斜杠或路径。api_key用${TAOTOKEN_API_KEY}这种占位符,运行时从环境变量读取。a2a段里的agent_card_path指向你存放 Agent Card 的目录,A2A 靠这个来发现彼此能力。
3.2 config.toml 配置骨架
如果你用的是 Python 生态,TOML 会更顺手。下面这套把通道、Agent、A2A 参数都收在一起。
[provider.taotoken] base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" api_type = "openai" [agent.planner] role = "任务拆解与调度" model = "gpt-4o-mini" provider = "taotoken" system_prompt = "你负责把用户目标拆成可执行的子任务,并分派给其他 Agent。" [agent.researcher] role = "资料检索与整理" model = "gpt-4o-mini" provider = "taotoken" system_prompt = "你负责根据子任务检索信息并返回结构化摘要。" [agent.coder] role = "代码生成与修改" model = "claude-3-5-sonnet" provider = "taotoken" system_prompt = "你负责根据需求生成或修改代码,并说明改动点。" [a2a] enabled = true agent_card_path = "./agent_cards" task_timeout_seconds = 300 transport = "json-rpc"3.3 Agent Card 最小示例
A2A 的能力发现靠 Agent Card,它是一个 JSON 文件,声明这个 Agent 叫什么、能干什么、怎么调。每个 Agent 目录下放一个,文件名建议用 Agent 名。
{ "name": "researcher", "description": "根据给定主题检索信息并返回结构化摘要", "version": "1.0.0", "capabilities": ["search", "summarize"], "endpoint": "http://localhost:8001/a2a", "input_schema": { "type": "object", "properties": { "topic": { "type": "string" } }, "required": ["topic"] } }endpoint是这个 Agent 对外暴露的 A2A 通信地址,capabilities是它声明自己能接的任务类型。主 Agent 在派活前会先读这些 Card,按能力匹配,而不是硬编码调用关系。
4. 验证请求:确认 A2A 通信真的生效
配置写完不代表通了,得实际发一次请求看结果。下面分两步:先验证模型通道本身是通的,再验证 Agent 之间的 A2A 调用是通的。
4.1 验证统一通道
先用一条最简单的请求确认 TaoToken 通道可用。用 curl 直接打:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "只回复两个字:通了"}] }'如果返回的 JSON 里choices[0].message.content是“通了”,说明 Key 和 base_url 都没问题。这一步不通,后面 A2A 一定不通,先排查这里。
4.2 验证 Agent 间通信
假设你的 planner Agent 跑在 8000 端口,researcher 跑在 8001 端口。先确认 researcher 的 Agent Card 能被读到:
curl http://localhost:8001/.well-known/agent.json返回的 JSON 里应该能看到name、capabilities、endpoint这些字段。如果 404,检查你的服务有没有把 Card 暴露在/.well-known/agent.json这个约定路径上。
然后模拟 planner 向 researcher 派一个任务,走 JSON-RPC:
curl http://localhost:8001/a2a \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "task-001", "method": "tasks/send", "params": { "task": { "type": "search", "input": { "topic": "A2A 协议的核心机制" } } } }'如果 researcher 正常处理,你会拿到一个带result的响应,里面包含任务 ID 和状态。长任务的话,状态可能是working,后续通过 SSE 或轮询拿最终结果。
4.3 看日志确认链路
光看响应还不够,建议在两个 Agent 的日志里各打一行标记。planner 侧在派活前打[A2A] dispatch task-001 to researcher,researcher 侧在收到后打[A2A] received task-001。两边日志都能对上,才说明通信链路真的通了,而不是某一边在自说自话。
实测下来,最容易出问题的是端口和路径对不上。Agent Card 里写的 endpoint 是 8001,但服务实际起在 8002,这种低级错误排查起来最费时间,配完先对一遍端口。
5. 本篇常见错排查
5.1 401 或 403:Key 没读到
最常见的原因是环境变量没生效。${TAOTOKEN_API_KEY}这种占位符需要你的框架支持变量替换,如果框架不认,它会原样把字符串发出去,服务端自然拒绝。排查方法:在代码里打印一下实际用的 Key 前几位,确认不是字面量${TAOTOKEN_API_KEY}。
5.2 404:base_url 写错
https://taotoken.net/api后面不要再拼/v1之外的东西。有些 SDK 会自动补/v1/chat/completions,有些不会。如果你手动拼路径,确认最终请求地址是https://taotoken.net/api/v1/chat/completions。多一个斜杠或少一段都可能 404。
5.3 Agent Card 读不到
A2A 的能力发现依赖 Card 暴露在约定路径。如果你把 Card 放在./agent_cards/researcher.json,但服务没有把它映射到/.well-known/agent.json,主 Agent 就发现不了它。检查你的服务路由,确认 Card 路径可访问。
5.4 任务一直 pending
任务发出去后状态卡在submitted或working不动,通常是子 Agent 处理超时或抛异常没回传。先看子 Agent 日志有没有报错,再检查task_timeout_seconds是不是设得太短。长任务建议配合 SSE 推送状态,而不是干等。
5.5 多 Agent 抢同一个 Key 导致限流
所有 Agent 共用一个 Key 时,并发高了可能触发限流。如果遇到 429,先降低并发,或者在 TaoToken 控制台确认当前 Key 的配额。多 Agent 场景下建议给关键 Agent 留出调用余量,别把并发打满。
6. 继续深入:模型对话、Coding Plan 与接入文档
跑通最小示例之后,下一步通常是两件事:一是把模型调用稳定下来,二是把 Agent 的编码和调度能力提上去。
如果你想先直观感受一下不同模型在 A2A 调度场景下的表现,可以直接在模型对话里试。把 planner 的 system_prompt 贴进去,看它拆任务的粒度合不合理,再决定用哪个模型做调度。
- 模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite
如果你要长期跑编码类 Agent,或者做需要持续调度的 Agent 工作流,Coding Plan 会更合适,它在长任务和连续调用上的稳定性更好,适合把 A2A 调度链路固定下来。
- Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
配置过程中遇到接入细节问题,比如 base_url 到底怎么填、SDK 怎么改、Agent Card 字段有哪些,接入文档里有完整说明,比到处搜零散答案快。
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
A2A 的价值不在协议本身有多复杂,而在于它让多 Agent 协作从“每家自己定规矩”变成“大家认一套规矩”。你先把统一通道和最小通信跑通,后面加 Agent 就是加一个 Card、加一个 endpoint 的事,不用再重写适配层。