把几台机器上的 AI Agent 连成一张能互相调用的网
起点:我有一堆机器,但它们彼此够不着
我手上散着好几台机器:一台有公网的云服务器、一部常年插着电的手机、一台 Mac,还有几台杂七杂八的 Linux。每台上面都跑着 agent,各干各的活。
问题是它们互相不认识。我想让 Mac 上的 agent 临时把一段重活派给云服务器,或者让云上的 agent 去问一下手机本地才有的某个上下文——做不到。它们之间隔着一层我一开始没太当回事、后来才发现是整件事核心的东西:网络可达性。
先分清两个面:控制面和数据面
在动手连之前,我先想清楚我到底要的是哪种「互通」。
我早就有一套基于 Git 的「邮箱」机制充当控制面:每台机器的 agent 往一个共享仓库里留言、协调、交接任务,所有动作都落进 git history。这套东西的好处是耐久、异步、可审计——谁在什么时候说了什么、做了什么决定,全部留痕。坏处也很明显:它慢。它适合「留个话」,不适合「我现在就要结果」。
这次要补的是另一半——数据面:一台机器把任务派给另一台,秒级拿回结果。实时互调。我选了 Google 的 A2A(Agent-to-Agent)这个开放协议来做标准化的互调接口,不想自己再发明一套消息格式。
一句话定位:邮箱是控制面(慢、可靠、留痕),A2A 是数据面(快、实时)。两个面互补,不是谁替代谁。
真正的拦路虎:NAT
协议选完,我以为剩下的是体力活。结果一上手就撞墙。
云服务器有公网 IP,它能被任何机器主动连接,这没问题。但反过来——云服务器连不动那些躲在家庭宽带和移动网络 NAT 后面的机器。我的手机、我的 Mac,它们只有「出站」的能力,没有「入站」的地址。
为什么入站不可达?因为这些设备在 NAT 后面根本没有一个外部世界能拨过去的地址。它们的内网 IP 对公网毫无意义;NAT 设备只会在它们主动发起一个连接、并因此在转换表里留下一条记录之后,才知道把回来的包送给谁。没有这条记录,外面打进来的包不知道该交给内网里的哪台机器,直接被丢掉。所以「hub 主动去连 spoke」这个方向,在物理上就走不通——不是端口没开,是压根没有能被拨的号码。
这一下就把拓扑给定死了。能被别人连的,只有那台有公网的云服务器。于是它顺理成章当 hub,其它机器全部当 spoke,围着它转。Hub-and-Spoke,没得选。
[手机 spoke]
|
[Mac spoke]--[云服务器 hub]--[Linux spoke]
|
(公网可达的只有 hub)
两个方向,难度天差地别
连通这件事拆开看是两个方向,得分别解决。
方向一,spoke 调 hub——这个简单。 Spoke 作为客户端主动连 hub,发起的是出站连接,天然可达。NAT 不拦出站。所以这条路我先跑通了,几乎没费什么劲:spoke 上的 agent 直接把 A2A 请求打到 hub 的端点,拿结果回来。
方向二,hub 调 spoke——这个才是真问题。 我想让 hub 上的 agent 反过来把任务派给某台 NAT 后的 spoke 去跑。可前面说了,hub 拨不进去。
解法是把方向掉个头:worker-pull,长轮询。
我不让 hub 去推任务,而是让 spoke 主动出站去 hub「拉」任务。Spoke 上常驻一个 worker,它去 long-poll hub 上的一个 /poll 端点——连接挂在那儿,hub 暂时没活就把这个请求 hold 住不回,一旦有派给这台 spoke 的任务,立刻顺着这条已经建立好的出站连接把任务吐回去。Spoke 在本地跑完自己的推理,再把结果 POST 回 hub。
妙就妙在:从 NAT 的视角看,全程都是 spoke 在出站。转换表里一直有它那条记录,回包永远找得到家。我用「出站长轮询」把「入站不可达」彻底绕开了。这是穿 NAT 的经典招,不花哨,但可靠。
一些工程上的真实细节
跑通之后,有几个点是实际运维里才浮出来的。
成本。 A2A server 空闲时几乎是 0 成本——它就挂在那儿等。只有任务真到达,才点火大模型推理。没有任务,没有账单。这点让我敢把它一直开着。
常驻。 Worker 必须活着,死了整条链路就断。手机我用开机自启加一个 keepalive 脚本兜底;Mac 上我换成了 launchd 守护进程——交给系统管比自己写 keepalive 省心得多,掉了它会帮我拉起来。
安全。 明文 HTTP 在公网上裸跑是不能接受的,任务内容和结果都在线上飘。我尽快上了 TLS,并用 Bearer token 做鉴权。这不是可选项,是开着公网端点的最低门槛。
最后:连通性是入场券,不是护城河
把这张 mesh 搭通之后,我反而冷静下来想了想它到底值多少。
连通性本身——A2A 协议、长轮询、hub-spoke——正在被快速商品化。它是借来的开放协议,谁都能用,我用的招别人也能照搬。它是入场券,不是护城河。把这部分当成核心竞争力,是看错了重点。
真正难抄、真正承重的是另一样东西:验证面。
当 agent 的数量上去、自主运行的时长拉长,一个「没有痛觉」的系统会出大问题。它会默默跑偏,并且把错误一层层放大——agent 干错了事,系统自己根本不知道,只能靠我这个人肉「痛觉传感器」事后去发现。机器越多、跑得越久,我能盯过来的比例就越小,失控面就越大。
所以我现在的判断很明确:
在加更多机器之前,先给每一个跨机任务装一个「可机器判定的验收契约」,并且让结果能回看。先装痛觉,再加肌肉。
肌肉是算力节点,是更多的 spoke。痛觉是验证回路——每个任务派出去之前就定义好「什么样算成功」,回来之后机器能自动判一次,判不过就报警、就留痕。没有这层,肌肉加得越多,系统失控的面积就越大,最后是负资产。
把网连起来只用了几天,但我打算把接下来的时间,先花在给它装上痛觉。