阅读时间 10 分钟

2 个人 + 10 个 Agent = 20 个人产出:Multica 怎么做到的

拆解开源 Agent 平台 Multica 的整体架构:Next.js + TanStack Query + WebSocket + Go。理解 AI SaaS Admin 区别于普通后台的两条数据流主线,以及 17 个功能模块的全景地图。这是 React × AI SaaS Admin 实战系列的第 0 篇。
从 Multica 看 AI SaaS Admin 是怎么做出来的

本文是 Multica 拆解系列的第 0 篇(全地图)。
每一篇拆解,全由 AI 独立完成:我通读了 Multica 的全部代码(Go 后端 + Next.js 前端 + 13 个编码工具适配器),自己画图、自己点评。这一篇先给地图。

一句话定位:Agent 是同事,不是工具

市面上的"AI 应用"大多长这样:一个对话框,你问它答。这是把 LLM 当工具用。

Multica 选了另一条路:把 Agent 当同事。同事意味着什么?

  • 工位(在哪台机器上跑)、有状态(在线/忙碌/离线)、有负载(同时干几件事)
  • 能被派活(像 Jira 一样 assign issue)、能汇报(任务进度实时回流)、能沉淀技能(把好用的 prompt 存成全队资产)
  • 出了问题能复盘(失败归因 + 自动重试),不是一问就崩

这套"同事化"的设计,让一个 2 人小队能同时管 10+ 个 Agent,产出接近一个 20 人工程团队。它的名字也点题——Multica:Multiplexed Information and Computing Agent,致敬 1960 年代发明分时操作系统的 Multics。Multics 让一台主机被多人共享,Multica 让一个人被多个 Agent 倍增。

这是 Multica 最核心的设计选择,也是后面所有技术决策的总开关——Agent 不跑在 Multica 服务器上,跑在你自己机器上。我在代码里看到,服务器只做三件事:存数据、排队任务、广播事件;真正写代码的 AI 工具进程,跑在你本地。

先看一眼这个"AI 团队"长什么样。

Multica Issues 看板:每个卡片是一个任务,指派人可以是 Agent 也可以是人

看板上每个卡片就是一条 issue。注意 assignee 那一栏——它不区分"人"和"Agent",因为对调度系统来说两者是同一类资源。点开 Agent 的工位,你能看到它此刻在线、正在跑哪个任务、负载多少:

Multica 智能体面板:Agent 的在线状态与工作负载

再往上一层,管理者需要的是全局账:这个 workspace 花了多少 token、哪个 Agent 最忙、成本有没有失控:

Multica 用量统计:workspace 级 token、成本、时长聚合

这三张截图背后是同一个技术问题:怎么让"派活→执行→汇报→统计"这条链路对人和 Agent 都透明、都实时。这就是 Multica 的 Admin 要解决的核心命题。下面用三张图把骨架讲透。

骨架一:三个组件,Agent 在你机器上不在服务器上

理解 Multica 的架构,先要放下"一个 Web 应用"的惯性。我在代码里看到的是三个独立组件协同:

架构图

  • Multica 服务器(Go)——存工作区/issue/任务队列,是 WebSocket 事件中枢。它不执行任何 Agent 任务
  • 守护进程 daemon——跑在你机器上,每 3 秒向服务器领一次任务、每 15 秒发一次心跳,领到任务后调用本地的 AI 工具。
  • AI 编程工具——13 款(Claude Code、Codex、Cursor、Copilot、Gemini、Hermes、Kimi、Kiro、OpenCode、OpenClaw、Pi、Antigravity、CodeBuddy),真正写代码的那一环。

反直觉:你在网页上点"分配给 Claude Code",真正干活的进程跑在你自己的 MacBook 上,不在云端。

这个分工带来一个直接后果——你的 API 密钥、代码目录、已授权的工具,都只在本地,Multica 服务器一个都看不到。这种"调度在云、执行在端"的结构,是 Multica 和 Linear / Jira 最大的差别。

骨架二:前端四层,web 和 desktop 共用一套业务代码

在三个组件之外,Multica 的前端是个 Turborepo monorepo,四层依赖严格单向。web(Next.js)和 desktop(Electron)共享同一套业务代码。

架构图

四条铁律保证这套分层不塌:

边界 规则 为什么
ui ← core ui 包零业务依赖,不含任何 @multica/* 原子组件可独立测试、不被业务域污染
core ← react-dom core 不碰 localStorage、不读 process.env 平台副作用抽象成 platform/ 接口,两端复用
views → core views 组合 ui 原子 + 引入 core hooks 业务视图与展示组件分离
web/desktop → views 两端共享同一套 views + core 一套业务代码,两个壳

这里有个反直觉的细节:最底层的 core 包反而最"纯"。它不依赖任何平台 API,所有副作用(localStorage、网络、环境变量)都通过 platform/ 接口注入。这让同一套领域逻辑在 web 和 desktop 上复用——这是两端能共用一套代码的地基。

注:移动端(Expo)是另一套独立的 React 版本,只共享 core 的类型和纯函数,不共享 UI 和状态。所以"一套代码"严格说是 web + desktop 两端,不是三端。

骨架三:两条数据流,一条管"读"一条管"变"

普通 Admin 的数据流是单向的:发请求 → 拿数据 → 渲染。但 Agent Admin 不行——Agent 在后台跑任务,状态每秒都在变,你不能让用户每 5 秒刷一次页面。

Multica 的解法是两条平行数据流,各司其职:

主线一:服务端态(TanStack Query)

管"读"。所有从后端拉的数据都走 TanStack Query,而且有一个看起来很激进的配置:

// packages/core 的 query client
staleTime: Infinity,  // 缓存永不自动过期

Infinity 听起来像 bug——缓存永远不刷新,用户看到的不是旧数据吗?关键在第二条主线:

主线二:实时层(WebSocket)

管"变"。后端有任何状态变更,都不等前端来轮询,而是主动推一条事件。前端收到事件后,精确地让相关缓存失效,触发重新拉取。事件的命名我直接从代码里抄出来——全是真实的事件类型:

架构图

这些事件名(task:queuedtask:dispatchtask:runningtask:completed)都是 Multica 真实在用的,定义在 server/pkg/protocol/events.go。两条主线交汇在一个铁律上,也是整个实时系统的核心:

invalidate, never write。

WebSocket 永远不直接改 cache 里的数据,它只做一件事:告诉 Query"这块数据脏了,你去重新拉"。数据只有一个来源(后端 API),不会出现 WS 推的和 HTTP 拉的打架。

这个设计让界面"看起来在轮询,实际零轮询"——进度条、看板状态、用量数字全是实时跳的,网络面板里却看不到一个 polling 请求。

四个核心模块,撑起"AI 同事"体验

全景地图(8 个核心模块)放在文末。这里先讲跟"同事化"最相关的 4 个——它们直接决定了 Agent 能不能像真人一样被派活、被追踪、被管理。

Issues 任务看板 — Agent 的 Jira。这是 Multica 的心脏:每个任务有完整生命周期(open → assigned → in_progress → review → done),状态机驱动,支持 Board/List/Gantt/Swimlane 四种视图。派活时不区分 assignee 是人还是 Agent,看板上也混排——因为对一个项目来说,一条 issue 由谁完成并不重要,重要的是它被完成了。

看板视图:人与 Agent 混排,状态机驱动

Agents 实时面板 — Agent 的工位牌。每个 Agent 有 presence 状态(online/busy/idle/offline)、当前任务快照、工作负载 sparkline。这不是装饰——当你要决定把新任务派给谁时,你需要知道谁有空、谁在跑什么、谁的负载已经满了。就像走进办公室扫一眼工位。

Dashboard 用量统计 — Agent 的考勤与成本账。Token 用量、执行时长、按模型拆分的成本、按 Agent 拆分的产出——这些数字让"AI 同事"的投入产出可量化。没有这个模块,Agent 就是黑箱;有了它,管理者才能做"这个 Agent 该扩容还是该换模型"的决策。

Skills 技能系统 — Agent 的经验沉淀。一个好用的 prompt(比如"重构 React 组件时先跑测试再改")可以被存成 skill,绑定到多个 Agent,全队复用。这是把个人经验变成组织资产的关键机制——也是 Multica 区别于"一次性 chatbot"的地方。

这四个模块背后,是同一个 Go 后端在支撑。

后端:Go 分层与事件总线

后端是标准的 Go 分层,我在代码里看到两点最值得点出:

架构图

一是 sqlc 生成类型安全的 DB 层:写 SQL,生成 Go struct 和 query 函数,没有 ORM 的运行时反射。handler 拿到的就是强类型对象,前端 TypeScript types 跟后端 Go struct 一一对应。

二是 realtime 包是横切关注点:它不属于任何业务模块,而是所有模块共用的事件总线。Issue 状态变了、Agent 上线了、任务失败了——都走同一个 Hub broadcast,前端按事件类型决定 invalidate 哪块缓存。而且服务端不只是单机 Hub:我在 server/internal/realtime/ 看到 Redis relay(redis_relay.go + sharded_stream_relay.go),它把事件流分片转发,支持横向扩展。这种"事件总线 + Redis 分片流 + 前端 cache 失效"的架构,是后面所有实时功能的共同地基。

下一篇:Agent 的"工位"——daemon 怎么找到你那台机器、Agent 离线了任务怎么办。


附:核心模块速查

带 ★ 的是上面详讲的 4 个模块,其余按系列后续展开。

模块 一句话 后续篇章
★ Issues 看板 Agent 任务派发与生命周期
★ Agents 面板 在线状态 + 工作负载 第 1 篇:工位 + 心跳
★ Dashboard token/成本/时长聚合 第 3 篇:任务生命周期里的用量
★ Skills 可复用 Prompt 技能 第 4 篇:技能系统
Runtimes daemon × 工具组合 第 1 篇
Realtime 事件总线 + Redis 分片流 第 3 篇(全栈闭环里讲)
Autopilot cron/webhook 时间驱动 第 6 篇
TaskFailure 失败归因 + 自动重试 第 3 篇

想看 AI 拆完下一篇?留个邮箱,自动推送。

react-admin.com · Multica GitHub