为什么 Multica 的 Server 用 Go 写

一次关于技术选型的真实复盘——从证据出发,不堆术语。Single binary + 本机 daemon + 高并发 + sqlc 强类型 + 跨平台零运行时——Go 是少数能同时把这些做对的选择。

by 于尘 ·

一次关于技术选型的真实复盘——从证据出发,不堆术语。

一句话回答

因为 Multica 的 Server 不只是"跑在云上"的那个——它还要把二进制装到每个用户本机,去管理 Claude Code / Cursor / OpenClaw 这一堆 agent 子进程。Go 是少数能同时把这两件事做对的选择。

证据先行

先把事实摆出来,再讲为什么。

SELF_HOSTING.md 明确写:

组件 描述 技术
Backend REST API + WebSocket server Go (single binary)
Frontend Web application Next.js 16
Database Primary data store PostgreSQL 17 with pgvector

go.modgo 1.26.1,依赖都是 Go 一线库——pgx/v5gorilla/websocketchi/v5cobrarobfig/cronprometheus/client_golang,配 sqlc100+ 个 SQL migrations 生成强类型查询代码。

代码结构

  • server/internal/daemon/ 30+ 文件——daemon 装在用户本机
  • server/pkg/agent/ 12 个 runtime 适配器——每个 os/exec spawn 子进程读 NDJSON
  • 一堆 *_windows.go / *_other.go——跨平台到 Windows / macOS / Linux

下面这八条,就是从这些证据推出来的。

一、Single binary 是头号理由

Multica 的部署是双二进制

  • Server:自托管用户跑在云上,或用官方云版
  • Daemon:必须装在每个用户本机,调度本地 agent 进程

Go 编出来是单个静态二进制,无 glibc 依赖,alpine 镜像几 MB 起步。

# 用户一行命令装好
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash

SELF_HOSTING.md 把 "Go (single binary)" 直接写进架构表——这不是修辞,是部署约束。

换成 Node 得带 node_modules,Python 还得对 venv / runtime 版本,Java 得带 JVM。全都不行。

二、本机 daemon 必须低资源

daemon 跑在用户机器上,跟 Claude Code / OpenClaw / Cursor / Codex 这些 agent 进程共存

server/pkg/agent/ 代码:daemon 同时管理 N 个 agent 子进程,每个还要读 NDJSON stream。

Go 内存占用比 Node / Python 小一个数量级,常驻后台不卡用户电脑。

三、高并发模型跟业务天生契合

Multica 干的事,就是成百上千个并发流

  • WebSocket 长连接(实时事件推送)
  • 多个 agent 子进程(每个一个 goroutine)
  • NDJSON 流式解析(每个 session 一个 reader goroutine)
  • 定时任务(robfig/cron,autopilot 调度)
  • 实时协作(realtime/ 包)

Go 的 goroutine + channel 就是为这种场景设计的。net/http 标准库原生支持高并发,gorilla/websocket 加上去就完事。

换成 Node,单线程事件循环遇到 CPU 密集(比如大 JSON 解析、schema 校验)就卡。

四、CLI 和 server 共享代码

multica CLI(Homebrew 装的)和 server 同一套 Go 代码

  • server/internal/handler/(agent / runtime / issue 业务逻辑)
  • server/pkg/agent/(12 个 runtime 适配器)
  • server/pkg/db/(sqlc 生成的 query)

CLI 跑命令直接 import 业务包,没有 RPC、没有重复实现。

用 Node 写 CLI + server 也能共享 TS 代码,但本机 daemon 那条路就废了。

五、sqlc + 100 个 migration 的强类型安全

Multica 有 100+ SQL migrations002_agent_config.up.sql 一直到 138_*),schema 复杂。

sqlc 把 SQL 编译成强类型 Go 代码——编译期就能抓到 schema 错误,运行时零反射。

这对 OSS 项目特别重要:贡献者改 SQL 后改 Go 代码,编译不过就直接挂。换成 Prisma / TypeORM 那种运行时 ORM,重构大表时容易留运行时坑。

六、跨平台零运行时

daemon 装在 macOS / Linux / Windows 三平台用户本机,Go 的交叉编译一行命令

GOOS=windows GOARCH=amd64 go build -o multica.exe

产物是原生二进制——macOS 用户不会遇到 "Python 3.11 vs 3.12 不兼容",Linux 用户不会遇到 "glibc 版本不对"。

七、生态对 server 业务对路

需求 Go 选型
PostgreSQL jackc/pgx/v5(公认最快的 PG 驱动)
WebSocket gorilla/websocket(事实标准)
HTTP router go-chi/chi(轻量、中间件丰富)
CLI 框架 spf13/cobra(k8s / hugo / docker 都用)
定时任务 robfig/cron
监控 prometheus/client_golang
邮件 resend-go
S3 / 密钥 aws-sdk-go-v2

全是一线库,没踩过坑。

八、工程纪律对 OSS 友好

  • gofmt 强制统一格式——PR review 不用吵格式
  • go vet + staticcheck 静态检查
  • go test 内置——server/pkg/agent/ 下每个适配器都有 _test.go + testdata/
  • 没有"我机器上能跑"问题——编译过的就能跑

为什么不选别的

备选 不选的原因
Node / TypeScript 前端已经是 TS(Next.js),后端再 Node 单线程遇 CPU 密集就卡;本机 daemon 内存占用大
Python GIL + 类型弱 + 部署依赖 venv;daemon 跨平台分发痛苦
Rust 学习曲线陡、开发速度慢、CLI 生态没 Go 厚;单二进制优势 Go 也有
Java / Kotlin JVM 重,daemon 跑用户本机不合适;冷启动慢
Elixir 生态小,招人难

写在最后

技术选型没有银弹,只有适配业务的取舍。

Multica 选 Go,不是因为 Go"时髦"或"性能最强",而是因为它要解决的是一个非常具体的难题:把一个 server 二进制 + 一个本机 daemon 二进制,以最低成本分发到全平台用户机器上,同时扛住 WebSocket + 多 agent 子进程 + 定时任务 + 强类型数据库查询这种复合并发。

Go 在这个具体场景下,几乎是唯一不踩坑的选择。

这不是 Go 赢,是这个场景赢。


关于 Multica:一个开源的 AI agent 协作平台,把 Claude Code、Cursor、OpenClaw、Codex 这些 coding agent 变成可分配的"团队成员",支持自托管。

GitHub: github.com/multica-ai/multica

← 所有文章