扒一扒JiuwenSwarm的网络架构:一个SPA+多WebSocket的部署实战
想在公网访问JiuwenSwarm的对话界面,结果被它的网络架构上了一课。Vite代理、WebSocket桥接、网关分层——今天把这些扒清楚。
1. 起因
本地跑JiuwenSwarm很简单,pip install jiuwenswarm之后一行命令就行:
python3.12 -m jiuwenswarm.app --name test
几秒钟后终端显示Gateway started on port 20001,浏览器打开http://127.0.0.1:5173就是对话界面。体验很好,但问题来了:我想让团队其他人也从浏览器访问,不能每个人都装Python环境、拉代码、装依赖。
一开始想,不就是个Web界面吗,Nginx反代一下就行。Port 5173跑的是Vite dev server,又不是什么稀奇的东西。结果配好Nginx、打开浏览器——白屏。F12一看,JS加载失败。把JS修好了,对话又连不上。把对话修好了,控制台还在报WebSocket连接异常。
折腾一圈下来,发现这不是Nginx配得对不对的问题,是不理解JiuwenSwarm的通信架构就没法正确部署。
2. 先看看它到底起了几个端口
跑起来之后,lsof一看,好家伙:
5173 Web前端(Vite dev server)
19000 后端API代理目标
19001 内部端口
19092 Agent WebSocket服务
19600 网桥WebSocket
20001 网关API
18092 Agent进程
一个应用起了7个端口。每个端口干的事都不一样。
5173是Vite dev server,跑的是SPA前端。Vite内置了proxy配置,把/chat/、/ws/的请求自动转发到19000。19000是真正的后端服务,处理Agent对话、Session管理。但19600这个端口独立于这条链路,是给WeChat/企微外部平台桥接用的WebSocket,在JS代码里硬编码了ws://127.0.0.1:19600/ws。
20001是Gateway API端口,负责外部请求的入口路由。19092是Agent内部WebSocket服务,处理Agent之间的通信。18092则是Agent进程的管理端口。
也就是说,JiuwenSwarm内部至少有两条独立的WebSocket链路:
- 对话链路:5173(Vite) → 19000(后端) → 19092(Agent WS),走的是/ws/gateway相对路径
- 平台桥接链路:独立端口19600,走的是ws://127.0.0.1:19600/ws硬编码路径
如果再加上Gateway的HTTP API(20001),实际是三条通信路径。这对于桌面应用来说没什么问题——都在localhost,端口随便用。但一旦要做网络部署,每条路径都要单独处理。
3. 反代的坑
用Nginx反代SPA有经典三板斧:根路径给index.html、静态资源给/assets/、API给后端。但对JiuwenSwarm不够,它有三层坑。
第一坑:静态资源路径是绝对路径。Vite构建的SPA默认把所有JS/CSS放在/assets/下,引用路径是/assets/index-xxx.js。如果你把应用挂在子路径(比如/jiuwenswarm/),浏览器会请求/jiuwenswarm/assets/…,但Vite server只在/assets/根路径下响应。解法:加一条独立的location:
location /assets/ {
proxy_pass http://127.0.0.1:5173;
proxy_set_header Host 127.0.0.1:5173;
}
第二坑:WebSocket握手。对话走的是/ws/gateway这个相对路径,不是普通的HTTP请求,需要WebSocket协议升级。Nginx默认不会处理Upgrade头,要手动开启:
location /ws/ {
proxy_pass http://127.0.0.1:5173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
}
少了proxy_http_version 1.1这行,WebSocket握手会失败——前端显示一直在连接中然后超时。这个错最隐蔽,因为Nginx本身返回200,浏览器不会报网络错误,但对话就是发不出去。
第三坑:19600bridge端口。这个端口是给WeChat/企微集成用的独立WebSocket服务,在JS里硬编码了ws://127.0.0.1:19600/ws。从另一台机器访问时,浏览器会尝试连接客户端本机的19600端口——当然不存在。结果就是控制台一直报WebSocket连接异常。好消息是不影响对话功能,但坏消息是用户看到报错会觉得是不是自己网络有问题。这个硬编码的地址目前没有配置项可以改。
4. 那正确方案是什么
如果只是团队内网临时共享,SSH隧道 + Nginx反代是最快的。把5173通过远程端口转发透传到公网服务器,Nginx配好三个location块:
/jiuwenswarm/ → proxy_pass到Vite server
/assets/ → 同样proxy_pass到Vite server(否则SPA加载不了JS)
/ws/ → proxy_pass + WebSocket升级头(否则对话连不上)
19600那个bridge端口不影响对话,可以忽略报错。
如果要公网正式发布,正确做法是:
- 前端构建:npm run build生成纯静态文件,Nginx直接serve,不再依赖Vite dev server。好处是少一层代理,性能更好,也避免了Vite dev server的安全风险。
- 后端独立启动:后端的端口改成监听0.0.0.0,前端构建时把API地址写成公网域名或IP。
- 19600bridge端口:如果不用WeChat集成可以在配置里关掉。如果用,也要配成公网可访问的WebSocket端点。
- Gateway端口20001:如果外部系统需要通过API调用JiuwenSwarm,这个端口也需要暴露。
总的来说,JiuwenSwarm目前的架构是桌面优先,Vite dev server身兼三职——静态服务、API代理、WebSocket代理。桌面场景下这是合理的,少配置一个服务就少一个出问题的环节。但到了生产部署场景,这三件事应该拆开:Nginx管静态文件和TLS,后端管API和WebSocket,中间不加Vite这层代理。
另外还有个细节:JiuwenSwarm桌面版用的是Electron壳,Desktop App本身会启动一个独立的Gateway进程(19001端口),跟CLI模式启动的Gateway(20001端口)不是同一个实例。两种模式下的端口分布略有不同,但WebSocket链路结构是一样的。
5. 值不值得折腾
JiuwenSwarm本身是个好用的多Agent框架。AgentTeam模式的多Agent协作、Skill系统的能力扩展、MCP工具绑定——这些做得都挺实,不是概念堆砌,是真正能跑通业务流程的。从今天在案例实战课里用它的表现来看,作为教学工具和日常开发辅助完全够格。
网络架构这一块,作为桌面工具是合理的——一切都在localhost,端口随便用,不需要考虑跨域、WebSocket代理、域名配置这些问题。桌面应用跑得稳最重要,网络拓扑的灵活性是次要的。
但如果想把它当服务部署给团队用,需要先理解它的端口拓扑再动手。关键就三点:
- Vite dev server身兼三职(静态服务+API代理+WebSocket代理),部署时要拆开
- 对话走WebSocket,Nginx反代一定要配Upgrade头
- 19600bridge端口的硬编码地址暂时无解,不用WeChat可以忽略
哪些场景适合直接用:本地开发调试、内网团队共享(SSH隧道就够了)、课堂教学演示。
哪些场景需要改造:公网正式服务、多用户同时在线的生产环境、需要HTTPS和域名的场景。
总的来说,桌面工具的角度可以给好评。服务化部署的角度,需要自己补一层工程化封装。后面如果JiuwenSwarm出了官方Docker镜像或者Helm Chart,这件事就省了。
- 点赞
- 收藏
- 关注作者
评论(0)