From 5706fb769ed512d5673dc97aabe47732ae9db4b3 Mon Sep 17 00:00:00 2001 From: shazhou-ww Date: Thu, 26 Mar 2026 18:36:16 +0000 Subject: [PATCH] docs: A2A guide v2 - HTTPS/TLS, three-team (KUMA+NEKO+RAKU), unified paths --- docs/shared/a2a-setup.md | 409 +++++++++++++++------------------------ 1 file changed, 154 insertions(+), 255 deletions(-) diff --git a/docs/shared/a2a-setup.md b/docs/shared/a2a-setup.md index 274b4bf..150ac8e 100644 --- a/docs/shared/a2a-setup.md +++ b/docs/shared/a2a-setup.md @@ -1,6 +1,6 @@ # 🔗 A2A 跨队通信配置指南 -> 使用 A2A (Agent-to-Agent) 协议实现多小队 Agent 互联互通(NEKO / KUMA / Home PC) +> 使用 A2A (Agent-to-Agent) 协议实现 KUMA ↔ NEKO ↔ RAKU 三队 Agent 互联互通 --- @@ -12,55 +12,127 @@ A2A (Agent-to-Agent) 是 Google 提出的开放协议,用于不同 AI Agent ### 为什么用 A2A? -- **跨服务器协作** — KUMA 和 NEKO 小队分别运行在不同的 VM 上,A2A 让它们能直接对话 +- **跨服务器协作** — 三个小队分别运行在不同的机器上,A2A 让它们能直接对话 - **标准协议** — 基于 A2A v0.3.0 规范,不依赖特定实现 - **多传输支持** — 支持 JSON-RPC、REST、gRPC 三种传输方式 -- **安全认证** — Bearer Token 认证,确保只有授权方能通信 +- **安全认证** — Bearer Token 认证 + TLS 加密传输 - **自动发现** — 通过 Agent Card 自动发现对方能力 -## 前置条件 +## 三队架构 -- OpenClaw ≥ 2026.3.0 -- Node.js ≥ 22 -- 两台服务器之间网络互通(公网 IP、Tailscale、或同一内网) - -## 架构概览 - -### 三方互通(当前架构) - -```mermaid -graph LR - subgraph "NEKO (neko-vm, 7×24)" - N_A2A[A2A :18800] - N_XJ[小橘 🍊] - end - subgraph "KUMA (kuma-vm, 7×24)" - K_A2A[A2A :18800] - K_XM[小墨 🖊️] - end - subgraph "Home PC (本地, 重活)" - H_A2A[A2A :18800] - H_AG[Agent] - end - N_A2A <-->|Bearer Token| K_A2A - N_A2A <-->|Bearer Token| H_A2A - K_A2A <-->|Bearer Token| H_A2A +``` +┌───────────────────┐ HTTPS + A2A ┌───────────────────┐ +│ KUMA 🐻 小队 │ ◄──── JSON-RPC/TLS ────► │ NEKO 🐱 小队 │ +│ Azure VM │ │ Azure VM (SEA) │ +│ oc-kuma.shazhou │ │ oc-neko.shazhou │ +│ .work │ │ .work │ +└────────┬──────────┘ └────────┬──────────┘ + │ HTTPS + A2A │ + └──────────┐ ┌───────────────┘ + ▼ ▼ + ┌───────────────────┐ + │ RAKU 🐉 小队 │ + │ Home PC (Win11) │ + │ oc-raku.shazhou │ + │ .work │ + │ (CF Tunnel) │ + └───────────────────┘ ``` -每个 Gateway 独立运行,各自管理自己的 agents,通过 A2A 协议通信。这样任何一方重启/故障都不影响其他方。 +### 小队一览 -### 分工 +| 小队 | Emoji | 平台 | 域名 | 队长 | 接入方式 | +|:-----|:------|:-----|:-----|:-----|:---------| +| KUMA | 🐻 | Azure VM | `oc-kuma.shazhou.work` | 小墨 🖊️ | nginx + Let's Encrypt | +| NEKO | 🐱 | Azure VM | `oc-neko.shazhou.work` | 小橘 🍊 | nginx + Let's Encrypt | +| RAKU | 🐉 | Home PC (Win11) | `oc-raku.shazhou.work` | 敖丙 🐲 | Cloudflare Tunnel | -| 节点 | 角色 | 特点 | -|------|------|------| -| NEKO (neko-vm) | 7×24 值班、飞书/Telegram 响应 | 轻量任务 | -| KUMA (kuma-vm) | 7×24 值班、LiteLLM Proxy | 统一 LLM 入口 | -| Home PC | 重活:全栈开发、本地 AI 模型推理 | 高配硬件 | +## 统一端点规范 + +所有小队遵循统一的 URL 路径: + +| 端点 | 路径 | 用途 | +|:-----|:-----|:-----| +| Agent Card | `https:///.well-known/agent-card.json` | Agent 发现 | +| JSON-RPC | `https:///a2a/jsonrpc` | A2A 消息传输 | +| REST | `https:///a2a/rest` | REST 传输(备用) | + +**示例:** + +- KUMA Agent Card: `https://oc-kuma.shazhou.work/.well-known/agent-card.json` +- NEKO JSON-RPC: `https://oc-neko.shazhou.work/a2a/jsonrpc` +- RAKU JSON-RPC: `https://oc-raku.shazhou.work/a2a/jsonrpc` + +## 安全架构 + +### TLS 加密(必须) + +所有 A2A 通信**必须走 HTTPS**,不允许裸 HTTP: + +- **Azure VM**: nginx 反代 + Let's Encrypt 免费 SSL +- **Home PC**: Cloudflare Tunnel(自动 TLS) + +### Bearer Token 认证 + +每个小队有自己的入站 Token,对方连接时需要携带。 + +!!! danger "Token 传输安全" + - Token **只通过 A2A 点对点传输** + - **永远不在飞书/IM 等公开渠道发送** + - A2A 是加密认证的,IM 消息可能被存储/同步 + +生成安全 Token: + +```bash +openssl rand -hex 24 +``` + +## nginx 反代配置(Azure VM) + +A2A Gateway 监听 `127.0.0.1:18800`,通过 nginx 反代暴露到公网。 + +```nginx +server { + listen 443 ssl http2; + server_name oc-.shazhou.work; + + ssl_certificate /etc/letsencrypt/live/oc-.shazhou.work/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/oc-.shazhou.work/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + + # A2A Gateway + location /a2a/ { + proxy_pass http://127.0.0.1:18800/a2a/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + proxy_read_timeout 120s; + } + + # A2A Agent Card + location /.well-known/agent-card.json { + proxy_pass http://127.0.0.1:18800/.well-known/agent-card.json; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # 其他服务(如 LiteLLM)可继续添加 location 块 + # location / { proxy_pass http://127.0.0.1:4000; ... } +} +``` + +申请 SSL 证书: + +```bash +sudo certbot --nginx -d oc-.shazhou.work --non-interactive --agree-tos --email your@email.com +``` ## 插件安装 -A2A Gateway 作为 OpenClaw 插件运行,从 workspace 的 plugins 目录安装。 - ### 1. 获取插件源码 ```bash @@ -71,82 +143,53 @@ cd a2a-gateway npm install --production ``` -!!! tip "workspace 路径" - 通过 `openclaw config get agents.defaults.workspace` 查看你的 workspace 路径。 - ### 2. 注册插件 ```bash -# 查看现有 plugins 配置,避免覆盖 -openclaw config get plugins.allow - -# 添加插件(保留已有的插件) -openclaw config set plugins.load.paths '["<绝对路径>/plugins/a2a-gateway"]' openclaw config set plugins.entries.a2a-gateway.enabled true ``` -!!! warning "必须使用绝对路径" - `plugins.load.paths` 中的路径必须是绝对路径,相对路径会导致加载失败。 - ## 配置说明 所有 A2A 配置位于 `openclaw.json` 的 `plugins.entries.a2a-gateway.config` 下。 ### agentCard — Agent 名片 -Agent Card 是 A2A 协议的"名片",用于告诉对方"我是谁、我能做什么、怎么联系我"。 - | 字段 | 类型 | 说明 | |:-----|:-----|:-----| -| `name` | string | Agent/小队名称,如 `KUMA 小队` | +| `name` | string | 小队名称 | | `description` | string | 简短描述 | -| `url` | string | **JSON-RPC 端点地址**,对方发消息到这里 | -| `skills` | array | Agent 能力列表(可选) | - -!!! note "url vs agentCardUrl" - - `agentCard.url` — 你自己的 JSON-RPC 端点,告诉对方"往这儿发消息" - - `peers[].agentCardUrl` — 对方的 Agent Card 地址,用于发现对方 +| `url` | string | **公网 JSON-RPC 端点**(`https://oc-xxx.shazhou.work/a2a/jsonrpc`) | ### server — 服务监听 | 字段 | 类型 | 默认值 | 说明 | |:-----|:-----|:-------|:-----| -| `host` | string | `0.0.0.0` | 监听地址,`0.0.0.0` 表示所有网卡 | +| `host` | string | `0.0.0.0` | 监听地址 | | `port` | number | `18800` | 监听端口 | ### security — 安全认证 | 字段 | 类型 | 说明 | |:-----|:-----|:-----| -| `inboundAuth` | string | 认证方式,目前支持 `bearer` | -| `token` | string | 入站认证 Token,对方连你时需要带上这个 Token | - -生成一个安全的 Token: - -```bash -openssl rand -hex 24 -``` - -### routing — 消息路由 - -| 字段 | 类型 | 说明 | -|:-----|:-----|:-----| -| `defaultAgentId` | string | 收到消息后默认交给哪个 Agent 处理,通常设为 `main` | +| `inboundAuth` | string | `bearer` | +| `token` | string | 入站 Token | ### peers — 对端配置 -peers 是一个数组,每个元素代表一个对端 Agent。 - | 字段 | 类型 | 说明 | |:-----|:-----|:-----| -| `name` | string | 对端显示名称 | -| `agentCardUrl` | string | 对端 Agent Card 地址(`/.well-known/agent-card.json`) | -| `auth.type` | string | 认证类型,`bearer` | -| `auth.token` | string | 对端的入站 Token(对方给你的) | +| `name` | string | 对端名称 | +| `agentCardUrl` | string | `https://oc-xxx.shazhou.work/.well-known/agent-card.json` | +| `auth.type` | string | `bearer` | +| `auth.token` | string | 对端的入站 Token | -## 配置示例:KUMA ↔ NEKO 双向互联 +!!! warning "Token 互换规则" + 你的 `security.token` 给对方填到 `peers[].auth.token` 里,对方的 `security.token` 你填到你的 `peers[].auth.token` 里。 -### KUMA 侧配置 +## 配置示例 + +### 三队互联(以 KUMA 为例) ```json { @@ -158,69 +201,24 @@ peers 是一个数组,每个元素代表一个对端 Agent。 "agentCard": { "name": "KUMA 小队", "description": "KUMA 小队 A2A Gateway", - "url": "http://:18800/a2a/jsonrpc" - }, - "server": { - "host": "0.0.0.0", - "port": 18800 + "url": "https://oc-kuma.shazhou.work/a2a/jsonrpc" }, + "server": { "host": "0.0.0.0", "port": 18800 }, "security": { "inboundAuth": "bearer", - "token": "" - }, - "routing": { - "defaultAgentId": "main" + "token": "" }, + "routing": { "defaultAgentId": "main" }, "peers": [ { "name": "NEKO", - "agentCardUrl": "http://:18800/.well-known/agent-card.json", - "auth": { - "type": "bearer", - "token": "" - } - } - ] - } - } - } - } -} -``` - -### NEKO 侧配置 - -```json -{ - "plugins": { - "entries": { - "a2a-gateway": { - "enabled": true, - "config": { - "agentCard": { - "name": "NEKO 小队", - "description": "NEKO 小队 A2A Gateway", - "url": "http://:18800/a2a/jsonrpc" - }, - "server": { - "host": "0.0.0.0", - "port": 18800 - }, - "security": { - "inboundAuth": "bearer", - "token": "" - }, - "routing": { - "defaultAgentId": "main" - }, - "peers": [ + "agentCardUrl": "https://oc-neko.shazhou.work/.well-known/agent-card.json", + "auth": { "type": "bearer", "token": "" } + }, { - "name": "KUMA", - "agentCardUrl": "http://:18800/.well-known/agent-card.json", - "auth": { - "type": "bearer", - "token": "" - } + "name": "RAKU", + "agentCardUrl": "https://oc-raku.shazhou.work/.well-known/agent-card.json", + "auth": { "type": "bearer", "token": "" } } ] } @@ -230,30 +228,12 @@ peers 是一个数组,每个元素代表一个对端 Agent。 } ``` -!!! warning "Token 互换规则" - - KUMA 的 `security.token` = NEKO peers 里填的 `auth.token` - - NEKO 的 `security.token` = KUMA peers 里填的 `auth.token` - - 简单说:**你的入站 Token 给对方填到 peers 里,对方的入站 Token 你填到 peers 里** +每个小队的 peers 列表需要包含**其他两个小队**的信息。 ## 使用方法 ### 通过 `a2a_send_file` 工具发送文件 -OpenClaw 提供了内置的 `a2a_send_file` 工具,用于向对端 Agent 发送文件: - -``` -工具: a2a_send_file - -参数: - peer — 对端名称(与 peers[].name 一致,如 "NEKO") - uri — 文件的公开 URL - name — 文件名(如 "report.pdf") - mimeType — MIME 类型(可选,自动检测) - text — 附带的文本消息(可选) -``` - -**使用示例:** - ``` a2a_send_file( peer="NEKO", @@ -265,124 +245,43 @@ a2a_send_file( ### 通过 SDK 脚本发送消息 -插件自带的 `a2a-send.mjs` 脚本可用于发送文本消息或测试连通性: - ```bash -# 发送普通消息 node /plugins/a2a-gateway/skill/scripts/a2a-send.mjs \ - --peer-url http://:18800 \ - --token \ + --peer-url https://oc-neko.shazhou.work \ + --token \ --message "你好,这是一条跨队消息" - -# 指定对端接收的 Agent(OpenClaw 扩展) -node /plugins/a2a-gateway/skill/scripts/a2a-send.mjs \ - --peer-url http://:18800 \ - --token \ - --agent-id coder \ - --message "帮我跑一下测试" - -# 异步模式(适合耗时任务) -node /plugins/a2a-gateway/skill/scripts/a2a-send.mjs \ - --peer-url http://:18800 \ - --token \ - --non-blocking --wait \ - --timeout-ms 600000 --poll-ms 1000 \ - --message "请生成本月的项目总结报告" ``` -### 让 Agent 知道 A2A 的存在 - -在 Agent 的 `TOOLS.md` 中添加 A2A 相关说明,这样 Agent 才知道可以跨队通信。参考模板见插件目录下的 `skill/references/tools-md-template.md`。 - -## 端点说明 - -A2A Gateway 插件启动后会暴露以下端点: - -| 端点 | 用途 | -|:-----|:-----| -| `/.well-known/agent-card.json` | Agent Card 发现(标准路径) | -| `/.well-known/agent.json` | Agent Card 发现(兼容别名) | -| `/a2a/jsonrpc` | JSON-RPC 传输(默认) | -| `/a2a/rest` | REST 传输 | -| gRPC (port+1) | gRPC 传输(端口号为 HTTP 端口 +1) | - ## 验证步骤 -安装配置完成后,按以下步骤验证: - -### 1. 重启 Gateway +### 1. 检查 Agent Card ```bash -openclaw gateway restart +curl -s https://oc-kuma.shazhou.work/.well-known/agent-card.json | python3 -m json.tool +curl -s https://oc-neko.shazhou.work/.well-known/agent-card.json | python3 -m json.tool +curl -s https://oc-raku.shazhou.work/.well-known/agent-card.json | python3 -m json.tool ``` -### 2. 检查 Agent Card +### 2. 互联检查清单 -```bash -# 本地检查 -curl -s http://localhost:18800/.well-known/agent-card.json | python3 -m json.tool +- [ ] 所有小队 Agent Card 通过 HTTPS 可访问 +- [ ] `agentCard.url` 指向 `https://` 域名(非裸 IP) +- [ ] Token 通过 A2A 安全传输(非 IM) +- [ ] 双向消息测试通过 +- [ ] TOOLS.md 已更新 A2A 说明 -# 从对端检查(确认网络互通) -curl -s http://:18800/.well-known/agent-card.json | python3 -m json.tool -``` - -### 3. 发送测试消息 - -```bash -node /plugins/a2a-gateway/skill/scripts/a2a-send.mjs \ - --peer-url http://:18800 \ - --token \ - --message "Hello from the other side!" -``` - -## 互联检查清单 - -两端都需要完成以下步骤才能实现双向通信: - -- [ ] 双方都安装了 a2a-gateway 插件 -- [ ] 双方都配置了 Agent Card -- [ ] 双方都生成了各自的入站 Token -- [ ] 双方都把对方加入了 peers 列表(带上对方的 Token) -- [ ] 双方都重启了 Gateway(`openclaw gateway restart`) -- [ ] 双方的 Agent Card 都能从对方访问到 -- [ ] 双方的 TOOLS.md 都更新了 A2A 说明 -- [ ] A → B 消息测试通过 -- [ ] B → A 消息测试通过 - -## 常见问题 / 排错 +## 常见问题 | 现象 | 可能原因 | 解决方法 | |:-----|:---------|:---------| -| "no agent dispatch available" | AI Provider 未配置,或 Agent 处理超时 | 检查 `openclaw config get auth.profiles`;长任务使用异步模式(`--non-blocking --wait`) | -| "plugin not found: a2a-gateway" | 插件路径配置错误 | 确认 `plugins.load.paths` 使用了绝对路径 | -| Agent Card 返回 404 | 插件未加载 | 检查 `plugins.allow` 是否包含 `a2a-gateway` | -| 端口 18800 连接拒绝 | Gateway 未重启 | 执行 `openclaw gateway restart` | -| 认证失败 | Token 不匹配 | 确认 peers 里填的 Token 是对方的 `security.token` | -| Agent 不知道 A2A | TOOLS.md 未更新 | 按模板添加 A2A 工具说明到 Agent 的 TOOLS.md | -| 网络不通 | 防火墙 / 安全组规则 | 检查 18800 端口是否开放;考虑使用 Tailscale | - -## 网络方案:Tailscale(可选) - -当两台服务器不在同一网络时,推荐使用 Tailscale 建立安全隧道: - -```bash -# 安装 -curl -fsSL https://tailscale.com/install.sh | sh - -# 启动并认证(两台机器用同一账号) -sudo tailscale up - -# 获取 Tailscale IP -tailscale ip -4 # 输出类似 100.x.x.x -``` - -在 A2A 配置中使用 Tailscale IP 即可。 - -!!! tip "适用于所有小队" - A2A 配置对 KUMA 和 NEKO 小队通用。只需在各自 VM 上完成配置,互换 Token 即可实现双向通信。 +| Agent Card 返回 404 | nginx 未代理 `.well-known` | 检查 nginx 配置 | +| HTTPS 超时 | Azure NSG 未开 443 | 添加 NSG 入站规则 | +| 认证失败 | Token 不匹配 | 确认 Token 互换正确 | +| 端口连接拒绝 | Gateway 未重启 | `openclaw gateway restart` | +| Cloudflare 502 | Tunnel 未连接 | 检查 `cloudflared` 服务状态 | ---
-:material-link-variant:{ .middle } 让 Agent 们跨越边界,协作无间 +:material-link-variant:{ .middle } 三队互联,安全协作