为什么 Multica 的 Server 用 Go 写
一次关于技术选型的真实复盘——从证据出发,不堆术语。Single binary + 本机 daemon + 高并发 + sqlc 强类型 + 跨平台零运行时——Go 是少数能同时把这些做对的选择。
一次关于技术选型的真实复盘——从证据出发,不堆术语。
一句话回答
因为 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.mod:go 1.26.1,依赖都是 Go 一线库——pgx/v5、gorilla/websocket、chi/v5、cobra、robfig/cron、prometheus/client_golang,配 sqlc 从 100+ 个 SQL migrations 生成强类型查询代码。
代码结构:
server/internal/daemon/30+ 文件——daemon 装在用户本机server/pkg/agent/12 个 runtime 适配器——每个os/execspawn 子进程读 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 migrations(002_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