Project-Nexus-WAN-跨公网Agent对话

灵犀 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_donestream_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

启动灵犀时:

  1. mDNS 扫描局域网(和以前一样)
  2. 信令客户端自动连接公共信令服务器
  3. 注册自己的信息(昵称、Agent 列表、平台、设备名)
  4. 接收在线节点列表

用户不需要配置任何东西。只要两台灵犀实例都连着互联网,就能看到对方。

当然,如果你需要私有部署,可以在设置中修改信令服务器地址为自己部署的实例。信令服务器本身只有一个 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 建联变得多余。去掉它,用户体验更简洁。


十三、如何体验

最快体验路径

  1. 在两台电脑上分别安装灵犀(或一台用安装版,一台用开发模式 PORT=3099
  2. 确保两台机器都连着互联网
  3. 分别在设置中配置模型接入点
  4. 打开 Nexus 页面 → 发现面板 → 看到对方 → 点击「对话」
  5. 选择 Agent,输入你的问题,发送
  6. 对方接受邀请,对话自动开始

自建信令服务器

如果你需要私有部署:

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

相关推荐
子安柠1 小时前
深入理解 Go 语言文件操作:从基础到最佳实践
开发语言·后端·golang
代码中介商1 小时前
C++文件流操作全解析
开发语言·c++
Forget_85501 小时前
RHEL——Kubernetes容器编排平台(二)
java·开发语言
Achou.Wang1 小时前
go语言中使用等待组(waitgroups)和内存屏障(barriers)进行同步
开发语言·后端·golang
MATLAB代码顾问1 小时前
【智能优化】鹈鹕优化算法(POA)原理与Python实现
开发语言·python·算法
lsx2024061 小时前
C 标准库 - `<stdio.h>`
开发语言
得闲喝茶1 小时前
JavaScript在数据处理的应用
开发语言·前端·javascript·经验分享·笔记
嵌入式×边缘AI:打怪升级日志1 小时前
转换模块(十二):实现 RGB 转 RGB + 项目整合与上机实验
开发语言·ios·swift
研究点啥好呢1 小时前
凯捷 自动化测试(Java+Selenium)面试题精选:10道高频考题+答案解析
java·开发语言·python·selenium·测试工具·求职招聘