A2A(Agent-to-Agent,智能体对智能体)
A2A 是开放的 Agent2Agent 协议(v1.0,由 Linux Foundation 托管),用于独立 AI agent 之间的通信。Hermes A2A 插件双向工作:你的 agent 可以把其他 A2A agent 当工具调用,其他 agent 也可以通过 HTTP 把任务发给你的 Hermes。
它可与任何 A2A 兼容的对等方互操作——另一个 Hermes、LangChain、CrewAI、Google ADK agent,或任何基于官方 a2a-sdk 构建的东西。
何时用 A2A
- 跨机器的 Hermes ↔ Hermes——让你的桌面 agent 把任务交给服务器上的 Hermes,或反之,各自拥有自己的记忆、工具和凭据。
- 委派给专家 agent——在其 Agent Card 上声明了
web_search/research/coding技能的对等方可在对话中途被发现并调用。 - 作为可被调用的服务——把你的 Hermes 暴露出去,让其他框架的 agent 能给它发任务。
当你想让多个 agent 跑在同一台机器上时,优先用委派(进程内子 agent)或看板(持久的多 profile 工作队列)——A2A 用于跨越进程/机器/框架边界。
启用
hermes gateway setup # 选 A2A
或在 ~/.hermes/config.yaml 中:
gateway:
platforms:
a2a:
enabled: true
extra:
port: 9900
出站客户端工具以 a2a 工具集形式提供,默认关闭——按平台启用:
hermes tools enable a2a --platform cli # CLI/TUI 会话
hermes tools enable a2a --platform telegram # 或任何消息平台
hermes tools enable a2a --platform a2a # 让入站 A2A 任务调用对等方(agent 链式调用)
这些工具在每种进程类型中都可用——CLI、TUI、网关和 cron——无需启用入站平台。
出站:调用其他 agent
启用 a2a 工具集后,agent 获得:
| 工具 | 作用 |
|---|---|
a2a_discover(url) | 拉取并总结一个对等方的 Agent Card |
a2a_call(agent, message, context_id?) | 发任务,拿回复;通过 context_id 多轮 |
a2a_list() | 已配置的对等方、已保存的会话、指标 |
a2a_history(context_id) | 召回一段持久化的 A2A 会话 |
a2a_orchestrate(capability, message, mode?) | 把任务扇出到所有声明了某能力的对等方(all / first / best) |
在 config.yaml 中配置已知对等方:
a2a_agents:
researcher:
url: "http://research-box.local:9900"
auth: { type: bearer, token: "..." }
timeout: 120
capabilities: [web_search, research]
然后直接提问即可:"让 researcher agent 总结今天 arXiv 上的新帖。" 直接给 URL 也行——a2a_call 接受任何 A2A 端点。
入站:成为可被调用的服务
启用平台后,Hermes 提供:
- Agent Card,位于
GET /.well-known/agent-card.json(v1.0 规范路径;旧版agent.json也响应)——声明你 agent 的名字、技能(派生自已启用的工具集)和认证要求。 - JSON-RPC 2.0,位于
POST /——v1.0 规范方法(SendMessage、SendStreamingMessage、GetTask、ListTasks、CancelTask、SubscribeToTask、推送通知配置 CRUD),加上 1.0 之前的路径风格别名(message/send等)。 - 面向
SendStreamingMessage的 SSE 流式,帧为符合规范的 JSON-RPC 封装。 - 面向长时间任务的推送通知(webhooks),HMAC-SHA256 签名。
入站任务被注入一个活跃的网关会话——与服务你其他渠道的是同一个 agent、记忆和工具——最终回复作为任务结果返回给调用方。会话以 A2A contextId 为键,因此对等方可以进行多轮交流。
互操作性已对照官方 Python a2a-sdk 验证(卡片解析、SendMessage、流式)。
安全模型
默认安全;每一步放宽都是显式的:
- 无 token ⇒ 仅 localhost。 服务器绑定
127.0.0.1。对外暴露需要 bearer token 且显式设置A2A_HOST。 - 按对等方发 token——
A2A_PEER_TOKENS="alice:tok1,bob:tok2"给每个对等方各自的凭据;已认证的名字用于限流、信任和审计。 - 提示注入过滤——入站文本会被过滤并当作不可信的对等方输入。远程对等方无法调用操作者的斜杠命令。
- 出站脱敏——回复中形如凭据的字符串(API key、JWT、token)会被擦除。
- 审计日志——每次交流都追加到
~/.hermes/a2a_audit.jsonl。 - 防循环——按上下文的轮次上限阻止两个 agent 无限对打。
配置参考
| 环境变量 | 默认值 | 含义 |
|---|---|---|
A2A_PEER_TOKENS | (未设置) | 按对等方的凭据 name:token,…(推荐) |
A2A_BEARER_TOKEN | (未设置) | 共享 token;身份回退到调用方 IP |
A2A_HOST | 127.0.0.1 | 绑定主机——仅在设置了 token 时才放宽 |
A2A_PORT | 9900 | 入站端口 |
A2A_AGENT_NAME | 由主机名派生 | Agent Card 上的名字 |
A2A_PUBLIC_URL | (未设置) | 卡片上声明的可路由 URL(反向代理 / k8s) |
A2A_TRUSTED_PEERS | (未设置) | 已认证身份的允许列表 |
A2A_ALLOW_ALL_USERS | false | 允许任何已认证对等方(仅开发用) |
A2A_RATE_LIMIT | 60 | 每身份每分钟请求数 |
A2A_MAX_PINGPONG_TURNS | 5 | 每上下文防循环轮次上限(最大 20) |
A2A_REPLY_TIMEOUT | 300 | 等待 agent 回复的秒数。孤儿任务清扫在该窗口过去前绝不会判任务失败(下限 300s),也绝不会在请求仍在等待它时判失败 |
A2A_PUSH_SECRET | bearer token | 推送通知签名的 HMAC 密钥 |
A2A_ADVERTISED_TOOLSETS | 全部已注册 | 限制 Agent Card 上出现哪些技能 |
在反向代理或 Kubernetes Service 之后,设置 A2A_PUBLIC_URL(或依赖 X-Forwarded-Host/X-Forwarded-Proto),让 Agent Card 声明一个对等方真正能回调的 URL。
快速测试
# 从另一台机器 / 另一个 agent:
curl http://your-host:9900/.well-known/agent-card.json
curl -X POST http://your-host:9900/ \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"jsonrpc":"2.0","id":1,"method":"SendMessage",
"params":{"message":{"messageId":"m1","role":"ROLE_USER",
"parts":[{"text":"What tools do you have?"}]}}}'
故障排查
- 对等方访问不到卡片 URL——卡片声明的是你的绑定地址;把
A2A_PUBLIC_URL设为外部可路由 URL。 401 Unauthorized——token 不匹配;检查服务器上的A2A_PEER_TOKENS/A2A_BEARER_TOKEN和对等方的auth:块。- 服务器不肯绑定非 localhost——这是设计使然:先设 bearer token,再
A2A_HOST=0.0.0.0。 - 长任务回复超时——调大
A2A_REPLY_TIMEOUT(孤儿清扫跟随它,所以迟到的回复会被存储而非丢弃),或让调用方注册推送通知配置并轮询GetTask。