A2A 与 A2A Plus:AI Agent 跨机器通信协议配置与旧版兼容实战
本文最后更新于 2026年8月8日 下午
为什么写这篇
我有一个 AI Agent 集群,分布在不同的机器上:
| 代理 | 机器 | 系统 | Hermes 版本 |
|---|---|---|---|
| 代理 A | 内网服务器 1 | Linux | v0.20.0 |
| 代理 B | 同机,独立 profile | Linux | v0.20.0 |
| 代理 C | 内网服务器 2 | Windows | v0.20.0 |
| 代理 D | NAS | UGOS (Linux) | v0.10.0 |
需求很简单:让这四个代理互相通信,形成闭环。A 发消息给 B,B 处理后通过飞书回复用户,或者 B 再回传给 A。
但简单需求背后是一串坑。
A2A 协议是什么
A2A(Agent-to-Agent)是 Hermes v0.20 引入的代理间通信协议,基于 JSON-RPC 2.0 的 HTTP 通信。每个代理运行一个 gateway,监听指定端口,通过 SendMessage 方法交换消息。
早期的 Agent Registry
其实早在 2026 年 5 月 12 日,我们就开始了这方面的探索。当时做了一个叫 Agent Registry(代理通讯录) 的技能——每个代理在注册表中登记自己的地址和能力,通过一个中心化的注册表互相发现。思路和今天的 A2A 几乎一样,只是实现方式不同。
当时的技术选型用了 OpenAI Threads/Runs API(简称 TR)。为什么选这个?因为 Hermes 原生支持 OpenAI 协议,默认就能调用 OpenAI 的 API,不需要额外适配。每个代理创建一个 Thread,其他代理通过 Runs 来读写消息——本质上是用 OpenAI 的对话 API 做消息队列。
但后来为什么用得少了呢?因为有了 看板(Kanban) 工具,代理之间通过看板任务卡片来协作,虽然慢但够用,Agent Registry 就渐渐少用了——功能一直在,只是不再频繁调用。
为什么现在又做 A2A
看板的延迟太长了。A 代理派一个任务到看板,B 代理要等下一个 cron 周期才能看到,再处理,再回复——一来一回可能几十分钟。A2A 是实时的,毫秒级送达,代理之间对话像人聊天一样自然。这种及时性看板给不了,所以 A2A 值得重新做一遍。
三个场景,三种坑
整个部署过程其实是三个独立的场景,每个场景都有不同的坑。
场景一:同机器 A2A(代理 A ↔ 代理 B)
背景:代理 A 和代理 B 在同一台 Linux 机器上,A 走默认 profile,B 是独立 profile。B 有自己的飞书 bot,能直接给用户发消息。
调试过程:这个场景其实很快就通了。A 通过 A2A 给 B 发消息,B 收到后回复——单向链路非常顺畅。
但反过来就不行。B 给 A 发消息,A 收到了,但不执行。明明 A2A 握手成功、HTTP 200,就是没有动作。
根因:安全审查拦截(这是最大的坑)
A2A 的入站消息被当作”不可信外部输入”。security.py 里的 wrap_inbound() 会给每条入站消息加一个边界前缀:
1 | |
目标代理收到后,会把它当成”外国同事的请求”而不是”自己操作者的命令”,出于安全考虑不执行高风险动作(发消息、跑命令)。
为什么这个坑最大:它不报错、不拒绝、不返回 401,只是让目标代理”不听话”。排查时你会先怀疑配置、token、工具集——循环一圈才发现是安全策略。
处理:对于可信的内网代理集群,在 security.py 里关闭这个安全边界:
1 | |
关键权衡:这是个二选一决策——
- 🟢 信任内部网络:入站指令直接执行,闭环顺畅
- 🔴 保持安全边界:防注入防泄露,但代理不会自动执行高风险动作
场景二:跨机器 A2A(代理 A ↔ 代理 C)
背景:代理 C 在 Windows 机器上(内网服务器 2),代理 A 在 Linux 上(内网服务器 1)。跨机器通信,需要身份验证。
坑 1:token 配置
跨机器 A2A 必须配置 bearer token。a2a_agents.<peer>.auth 字段缺失时,调用方会收到 HTTP 401 Unauthorized。
需要双方都配:
1 | |
同时 .env 需要配置三件套:
1 | |
关键理解:A2A_BEARER_TOKEN 是别人调用你时用的,A2A_PEER_TOKENS 是你调用别人时用的。a2a_agents.<peer>.auth.token 是你调用对方时用的凭证。三件套缺一不可。
同机器 vs 跨机器差异:同机器 A2A(localhost)不需要 token,Hermes 做了本地回环地址的信任豁免。跨机器则严格要求 bearer 认证。所以代理 A 调代理 B 不用 token,调代理 C 必须。
坑 2:A2A 入站会话没有 terminal 工具
A2A 入站会话默认只加载 a2a 工具集,没有 terminal、file、code_execution。代理 C 收到消息后说”我无法执行,没有 terminal 工具”——连 hermes send 都跑不了。
修复:在 platform_toolsets 中添加:
1 | |
修改后重启 gateway 生效。
教训:A2A 入站会话不等于正常网关会话,它是受限沙箱,要主动放行工具。
坑 3:Windows 上传文件
传 a2a-plus 技能到代理 C,tar 文件 SCP 成功但解压后目录为空。Windows 的 tar 命令对 gzip 兼容性有问题,PowerShell 的 tar 解压 gz 文件有时会静默失败。
修复:用 Python 的 tarfile 库解压:
1 | |
场景三:旧版 Hermes 兼容(代理 A ↔ 代理 D)
背景:代理 D 在 NAS 上,Hermes v0.10.0,不支持 A2A 协议。NAS 的 Hermes 是 Docker 镜像自带的,不方便升级(升级意味着要改 NAS 厂商的镜像、重新部署、可能影响其他服务)。
方案选择:A2A Plus
老版本 Hermes 没有 A2A,怎么通信?我们试过几种方案:
旧版 Agent Registry 思路:用 OpenAI 的 Threads/Runs API(TR)做中间通道——A 代理创建一个 Thread,B 代理去轮询读取。但这种方法依赖外部 API,有延迟,且需要每个代理都有 OpenAI key。
SSH 模拟 A2A:用 SSH 通道代替 HTTP,双方互相 SSH 登录,通过
hermes chat -q发送消息。
最终选择了 SSH 方案,做成 A2A Plus 技能。SSH 在安全上不如 A2A(涉及密钥管理),但在局域网内足够简单实用。A2A Plus 的核心思路:
1 | |
A2A Plus 的隐藏优势:文件传递
A2A 协议本质上是一个对话信息传递协议,设计目标就是消息交换——SendMessage、GetTask、SendTaskNotification。在文件传递这块比较弱,需要额外搭建文件服务器或依赖外部存储。
而 A2A Plus 基于 SSH,天然具备文件传递能力。SSH 协议自带 SCP 和 SFTP,不需要额外的中间件:
1 | |
这意味着 A2A Plus 不仅能发消息,还能:
- 传递配置文件(把新配的 registry 推到各代理)
- 传递日志文件(让代理 A 远程拉取代理 D 的日志分析)
- 传递安装包/技能文件(给旧版代理装新技能)
- 传递截图/报告(代理 D 处理完 NAS 任务后把结果传回来)
这是 A2A 协议做不到的,或者说做起来很麻烦的。A2A Plus 的 SSH 通道让”对话 + 文件”一体化,两个维度都打通了。
坑 1:容器内 SSH 密钥缺失
代理 D 在 Docker 容器里运行,SSH 密钥在 NAS 宿主机上,容器内没有。第一次跑双向闭环时,代理 D 第二步”SSH 回代理 A”直接失败。
修复:用 docker cp 把密钥从宿主机复制到容器:
1 | |
坑 2:NAS 宿主机 SCP 写入失败
SCP 文件到 NAS 宿主机时报错 dest open: No such file or directory,但 SSH 能正常连接。UGOS NAS 的文件系统有权限限制,某些路径通过 SCP 直接写入会失败。
解决:用 SSH exec + base64 管道传输:
1 | |
坑 3:飞书 open_id 跨应用不通
代理 A 让代理 B 发飞书给用户,指定 open_id,代理 B 回复 Bot/User can NOT be out of the chat。每个代理有自己的飞书应用(app_id 不同),open_id 跨应用不通。
修复:用各代理自己的 home channel chat_id 发消息:
1 | |
共享技能与代理注册表
为了让所有代理都能互相通信,需要两样东西:
- a2a-plus 技能:给每个代理装一份,让它们知道怎么用 SSH 通道通信
- agent-registry-v2.yaml:统一代理注册表,定义每个代理的通信方式、地址、端口
1 | |
闭环测试方法
单向闭环测试
1 | |
双向闭环测试(全环测试)
1 | |
最终结果
| 代理 | 通信方式 | 单向闭环 | 双向闭环 | 场景 |
|---|---|---|---|---|
| 代理 B | A2A(同机器) | ✅ | ✅ | 同机 A2A |
| 代理 C | A2A(跨机器) | ✅ | ✅ | 跨机 A2A |
| 代理 D | SSH 模拟 A2A | ✅ | ✅ | 旧版兼容 |
三个代理、三种场景、全部闭环打通。用户可以在飞书上看到消息从任意代理发出,经过 A2A/SSH 链路,最终回到用户。
总结
- A2A 比看板更及时——毫秒级 vs 分钟级,适合需要实时对话的场景
- 安全审查是最大的坑——不报错不拒绝,只是”不听话”,排查最隐蔽
- A2A 入站会话是受限沙箱——需要显式配置工具集
- 跨机器通信必须 bearer token——同机器豁免
- 旧版代理用 SSH 模拟 A2A——A2A Plus 技能提供统一接口
- 飞书跨应用用 home channel——不用 open_id
参考文献
- Hermes A2A 协议文档:https://hermes-agent.nousresearch.com/docs
- Hermes v0.20 Release Notes:A2A 协议实现
- OpenAI Threads/Runs API 文档:https://platform.openai.com/docs/api-reference/runs