灵犀 AI Agent:让你的 AI 跨越山海 ------ Project Nexus 广域网 Agent 对话全解析
你的 AI 助理和千里之外同事的 AI 助理,能不能像两个人一样直接对话?现在可以了。本文深入解析灵犀 Project Nexus 的广域网升级------从局域网 mDNS 发现到跨公网信令中继,一个真正 Zero-Config 的全球 Agent-to-Agent 实时对话网络。
GitHub 地址:https://github.com/MT-xjr2/lingxi
一、从局域网到广域网:为什么要打破这堵墙?
在上一篇 Project Nexus 文章中,我们构建了一个局域网内的 Agent-to-Agent 对话网络------同一 WiFi 下的灵犀实例通过 mDNS 自动发现,PSK 密钥建联,双向流式对话。
但局域网有一个致命的局限:你只能和身边的人对话。
想想这些场景:
- 你在北京,同事在深圳,两个人的 AI 需要讨论同一个技术方案
- 开源社区的两位开发者分别在家远程办公,Agent 需要协作完成代码审查
- 你在公司的灵犀实例上训练了一个财务分析 Agent,想让家里的灵犀实例远程调用它
这些场景有一个共同点:Agent 需要跨越公网通信。
灵犀 v1.1 的 Project Nexus 广域网升级,正是为了解决这个问题。

最关键的设计目标是:开箱即用,Zero-Config。 用户不需要配置公网 IP、端口转发、VPN 隧道------启动灵犀就自动连入全球网络。
二、架构全景:信令 + 中继的极简设计
跨公网通信面临一个核心挑战:NAT 穿透。 绝大多数家庭和企业网络都在 NAT 后面,两台机器无法直接建立连接。
经典的解决方案有三种:
| 方案 | 复杂度 | 可靠性 | 灵犀的选择 |
|---|---|---|---|
| STUN/TURN + ICE(WebRTC 路线) | 极高 | 中(受 NAT 类型影响) | ❌ 过重 |
| 中心化服务器全量转发 | 中 | 高 | ❌ 隐私风险 |
| 信令服务器 + 消息中继 | 低 | 高 | ✅ 选这个 |
灵犀选择了第三种:一个轻量信令服务器,承担三个职责------注册、发现、中继。

信令服务器本身是一个不到 430 行 Go 代码 的微服务,部署在 Render 上。它不存储任何消息------消息只在内存中转瞬即逝。
三、Transport 抽象层:LAN 和 WAN 的统一接口
广域网支持的关键设计决策是引入 Transport 抽象层。对话引擎不关心消息是通过局域网 HTTP 直连还是广域网信令中继发送的------它只调用同一个接口。
┌──────────────┐
│ Transport │ interface
│ ├── Send() │
│ ├── Get() │
│ └── Type() │
└──────┬───────┘
│
┌──────────┼──────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ LANTransport │ │ WANTransport │
│ │ │ │
│ HTTP 直连 │ │ 信令中继 │
│ http://ip:port │ │ WebSocket → │
│ /api/nexus/... │ │ Signal Server │
│ │ │ → 对方客户端 │
└─────────────────┘ └─────────────────┘
对话引擎选择 Transport 的逻辑极其简洁:先查 mDNS 发现的局域网 peer,找到就用 LAN 直连;找不到就走 WAN 中继。
go
func GetTransportForPeer(peerID string) Transport {
// 先检查局域网
peers, _ := db.ListNexusPeers()
for _, p := range peers {
if p.ID == peerID {
return NewLANTransport(p.Host, p.Port)
}
}
// 默认走广域网
return NewWANTransport(peerID)
}
这个设计的优雅之处在于:同一局域网的两台灵犀实例,即使都连着信令服务器,对话依然走 LAN 直连------零延迟、零中继开销。 只有在局域网找不到对方时,才会走广域网。
四、信令服务器:430 行代码的全球中继
信令服务器是整个广域网架构中唯一的中心化组件。它的设计哲学是:越简单越好。
4.1 注册与发现
灵犀启动时,信令客户端通过 WebSocket 连接信令服务器,发送 register 消息注册自己:
json
{
"type": "register",
"data": {
"instance_id": "lingxi-macbook-1715...",
"nickname": "小明的灵犀",
"platform": "darwin",
"device_name": "MacBook-Pro",
"agents": [
{"name": "代码审查员", "capability_tags": ["code-review", "go"]},
{"name": "产品分析师", "capability_tags": ["product", "analysis"]}
]
}
}
其他灵犀实例会立即收到 peer_online 通知,前端实时更新在线节点列表。

4.2 消息中继
信令服务器的核心功能是消息中继(Relay) 。它不解析消息内容,只看 to 字段,然后原样转发:
灵犀A 信令服务器 灵犀B
│ │ │
│ relay {to: B, data} │ │
│───────────────────────►│ │
│ │ relay {from: A, data} │
│ │────────────────────────►│
│ │ │
如果目标不在线,信令服务器会返回 delivery_failed,客户端收到后展示通知。
4.3 写入串行化:解决 WebSocket 并发写问题
信令服务器有一个精巧的并发设计。WebSocket 不允许多个 goroutine 同时写入同一个连接,但中继消息可能从任意 goroutine 发起。解决方案是 每个 peer 一个写入 goroutine + 带缓冲的 channel:
┌───────────────┐
goroutine A ──────►│ │
│ writeCh │──────► writeLoop goroutine ──► WebSocket
goroutine B ──────►│ (buffer=256) │ (串行化所有写操作)
│ │
goroutine C ──────►│ │
└───────────────┘
这样无论多少个 goroutine 同时往同一个 peer 发消息,最终都通过 channel 序列化到单一的 writeLoop goroutine,彻底避免 concurrent write panic。
4.4 心跳保活
两层心跳机制确保连接活性:
| 机制 | 间隔 | 作用 |
|---|---|---|
| WebSocket Ping/Pong | 25 秒 | 保持底层 TCP 连接 |
| 应用层 Heartbeat | 3 分钟 | 信令服务器确认 peer 存活 |
如果 120 秒内没有收到任何消息(包括 Pong),连接被视为断开,触发自动重连。
五、对话邀请:跨越公网的握手
广域网下的对话发起流程与局域网保持一致------这是 Transport 抽象的威力。差异仅在于消息的传输路径。
用户 A(北京) 信令服务器 用户 B(深圳)
│ │ │
│ 1. 选择远程 Agent │ │
│ 填写提问 │ │
│ │ │
│ conversation_invite ─────►│ │
│ {topic, goal, agent...} │── conversation_invite ─►│
│ │ │
│ │ │ 2. 用户 B 看到邀请
│ │ │ 选择己方 Agent
│ │ │ 点击「接受」
│ │ │
│ │◄─ conversation_accept ──│
│◄── conversation_accept ──│ {conv_uuid, agent_id} │
│ │ │
│ 3. 对话引擎启动! │ │
│ 双方 Agent 开始 │ │
│ 流式自动对话 │ │
│ │ │
注意对话邀请(conversation_invite)、接受(conversation_accept)、拒绝(conversation_reject)是信令协议的一等公民------它们有专用的消息类型,不走通用 relay 通道。这确保了对话建立过程的可靠性和可追踪性。


六、跨公网流式对话:Token 级实时转发
Agent 间对话的精华在于双向流式。当本地 Agent 产生每一个 token,不仅推送给本地前端,还要通过广域网中继给对方------对方用户可以实时看到远端 Agent 的思考和输出过程。
本地 Agent 产生 token "你好"
│
├──► 本地 WebSocket → 本地前端渲染(己方 Agent 输出)
│
└──► WANTransport.Send("/conversation/stream-token", ...)
│
▼
信令服务器 relay
│
▼
对方 SignalingClient 接收 → relayHandler
│
▼
对方 WebSocket → 对方前端渲染(远端 Agent 输出)
流式转发的关键设计点:
1. stream_done 同步发送
普通的 text/thinking token 异步转发(不阻塞本地渲染),但 stream_done 和 stream_start 事件同步发送------确保对方知道这一轮输出结束了。
2. 500ms 缓冲延迟
Agent 输出完毕后,先等待 500ms 再发送完整消息。这个缓冲保证 stream_done 事件先到达对方,对方清除了流式状态后,再收到完整消息------避免两个 Agent "抢话"。
3. 重试机制
WANTransport 内置 3 次重试 + 指数退避。如果信令服务器暂时不可达,不会立刻失败:
重试策略:
第 1 次失败 → 等 2s → 重试
第 2 次失败 → 等 4s → 重试
第 3 次失败 → 报错,保存 error 消息到对话
严格轮次对话
A2A 对话遵循严格的"一来一回"轮次制。每一轮只有一个 Agent 在输出。上一个 Agent 的 stream_done 到达后,才会触发对方 Agent 开始回复。这个设计防止了两个 AI 同时说话的混乱场景。


七、开箱即用:默认就连上全球网络
最后也是最重要的设计决策:广域网默认启用。
灵犀内置了一个公共信令服务器地址:
wss://xxx.onrender.com/ws
启动灵犀时:
- mDNS 扫描局域网(和以前一样)
- 信令客户端自动连接公共信令服务器
- 注册自己的信息(昵称、Agent 列表、平台、设备名)
- 接收在线节点列表
用户不需要配置任何东西。只要两台灵犀实例都连着互联网,就能看到对方。

当然,如果你需要私有部署,可以在设置中修改信令服务器地址为自己部署的实例。信令服务器本身只有一个 Go 文件,部署到任何支持 WebSocket 的平台即可。
八、安全性设计
"消息经过一个中心化服务器,安全吗?" 这是一个合理的疑问。灵犀在安全性上做了以下设计:
8.1 WSS/TLS 加密
信令服务器默认使用 wss://(WebSocket over TLS),所有传输中的数据都经过 TLS 1.2+ 加密。中间人无法窃听。
8.2 信令服务器无状态
信令服务器不持久化任何数据------不存消息、不存用户信息。所有 peer 信息仅存在于内存中。服务器重启后,peer 列表清空,客户端自动重连重新注册。
8.3 Agent 安全约束
每个参与对话的 Agent 都有独立的安全设置:
| 配置 | 作用 |
|---|---|
| 公开开关 | Agent 是否出现在发现列表中 |
| 能力标签 | 标记 Agent 的专长领域 |
| 授权级别 | 控制 Agent 的行为边界 |
| 禁止透露 | Agent 绝对不能泄露的敏感信息 |
"禁止透露"约束会注入到 Agent 的 system prompt 中------即使对方 Agent 试图套话,你的 Agent 也会拒绝回答。
8.4 断线恢复
信令客户端内置了指数退避重连机制。网络中断后,会以 1s → 2s → 5s → 10s → 30s 的间隔自动重连,并在重连成功后重新注册。前端实时显示连接状态。
九、前端体验:LAN + WAN 一体化
广域网节点和局域网节点在前端统一展示,用颜色和图标区分:

底部状态栏实时显示 LAN/WAN 节点数量和连接状态,用户一目了然。
对话发起后,无论对方是 LAN 还是 WAN 节点,对话界面完全一致------用户不需要(也不会)感知底层的传输差异。
十、对话的终结:自动收敛机制
两个 AI 对话,如果没有终止条件,可能会永远聊下去(或者陷入无意义的寒暄循环)。灵犀设计了三层收敛机制:
第一层:[CLOSE] 标记检测
Agent 的 system prompt 中包含指令:当认为对话目标已达成时,在回复开头加上 [CLOSE] 标记。对话引擎检测到后,自动将对话标记为 completed,并通知对方终止。
第二层:最大轮次限制
每场对话有预设的最大轮次(默认 10 轮)。达到上限后对话自动暂停,等待人类决定是否继续。
第三层:人类随时可控
用户可以随时暂停、接管或终止对话。暂停通过 Go channel 即时生效;接管后人类手动输入消息;终止信号同步发送给对方。
十一、一图读懂全链路
让我们用一张图串联整个广域网 Agent 对话的完整链路:
用户 A (北京) 用户 B (深圳)
│ │
│ 1. 打开灵犀 │ 1. 打开灵犀
│ ↓ │ ↓
│ 2. 自动连接信令服务器 │ 2. 自动连接信令服务器
│ ↓ │ ↓
│ 3. 发现面板看到 B │ 3. 发现面板看到 A
│ ↓ │
│ 4. 点击「对话」 │
│ 选择己方 Agent │
│ 输入提问 │
│ ↓ │
│ ── conversation_invite ─► 信令服务器 ─────────────────► │
│ │ 5. 收到邀请通知
│ │ 选择己方 Agent
│ │ 点击「接受」
│ │ ↓
│ ◄── conversation_accept ◄─ 信令服务器 ◄──────────────── │
│ ↓ │
│ 6. Agent A 开始流式输出 │
│ ├──► 本地前端渲染 │
│ └──► WAN relay ──► 信令服务器 ──► B 前端实时渲染 │
│ ↓ │
│ 7. 完整消息发送给 B │
│ ↓ │ ↓
│ │ 8. Agent B 开始流式回复
│ B 前端实时渲染 ◄── 信令服务器 ◄── WAN relay ◄──┤ │
│ └──► │ B 本地前端渲染
│ │ ↓
│ ◄───────────── 完整消息发送给 A ◄──────────────────────── │
│ ↓ │
│ ... (循环,直到 [CLOSE] 或达到最大轮次) │
十二、与局域网版本的对比
| 维度 | 局域网版 (v1.0) | 广域网版 (v1.1) |
|---|---|---|
| 发现方式 | mDNS 多播 | mDNS + 信令服务器注册 |
| 通信路径 | HTTP 直连 | HTTP 直连 (LAN) / 信令中继 (WAN) |
| 配置要求 | 同一 WiFi | 有互联网即可 |
| 建联机制 | PSK 密钥交换 | 直接邀请,无需预先建联 |
| 传输安全 | HTTP 明文 | WSS/TLS 加密 |
| 第三方依赖 | 无 | 公共信令服务器 (可自建) |
| 断线恢复 | 无 | 指数退避自动重连 |
| 节点信息 | ID + 昵称 | ID + 昵称 + 头像 + 平台 + 设备 + Agent 列表 |
一个值得注意的简化:广域网版本移除了 PSK 建联机制和 Token 认证。在局域网中,这两个机制用于在信任边界不明确的本地网络中建立互信。但在广域网中,用户明确地选择了要对话的对象,对话本身就是显式授权------再加上 WSS 传输加密和 Agent 级安全约束,PSK 建联变得多余。去掉它,用户体验更简洁。
十三、如何体验
最快体验路径
- 在两台电脑上分别安装灵犀(或一台用安装版,一台用开发模式
PORT=3099) - 确保两台机器都连着互联网
- 分别在设置中配置模型接入点
- 打开 Nexus 页面 → 发现面板 → 看到对方 → 点击「对话」
- 选择 Agent,输入你的问题,发送
- 对方接受邀请,对话自动开始
自建信令服务器
如果你需要私有部署:
bash
# 克隆信令服务器(只有一个 main.go)
git clone https://github.com/OdysseyFather/lingxi-singaling-server.git
cd lingxi-singaling-server
# 本地运行
go run main.go # 默认 9090 端口
# 或 Docker 部署
# 或推送到 Render / Railway / Fly.io(支持 WebSocket 的任何平台)
然后在灵犀设置中将信令服务器地址改为你的实例。
结语
从局域网到广域网,Project Nexus 走出了 Agent-to-Agent 通信最关键的一步。通过一个极简的信令服务器和精心设计的 Transport 抽象层,灵犀实现了:
- Zero-Config:启动就连上全球网络,不需要任何配置
- LAN 优先:同网络走直连,零延迟零中继
- 安全传输:WSS 加密 + Agent 级安全约束
- 可靠通信:自动重连 + 消息重试 + 断线恢复
- 统一体验:LAN/WAN 对话界面完全一致
下一步,我们计划引入端到端加密(E2EE),让消息内容即使经过信令服务器中继,服务器本身也无法解读------真正实现"不信任中间人"的安全模型。
让 AI 跨越山海,只为更好的协作。
灵犀 ------ 让 AI 成为你的工作伙伴,而不只是聊天对象。
GitHub:https://github.com/MT-xjr2/lingxi
如果觉得项目有价值,欢迎 Star 支持!
git