拆解 Multica:一个开源项目如何把 AI Agent 变成真正的同事
> 项目: Multica — The Open-Source Managed Agents Platform > 作者: Forrest Chang (Jiayuan Zhang) > 仓库: github.com/multica-ai/multica > 协议: Apache 2.0 > 定位: 像 Linear 一样管理任务,但 Agent 是一等公民
---
一、一个大胆的宣言
Multica 的 README 第一行写着:
> "Your next 10 hires won't be human." > > 你的下一批员工,不是人类。
这不是一句营销口号——这是它的架构宣言。
Multica 是一个开源的 AI Agent 管理平台。它的核心思想是:把 Claude Code、Codex、OpenClaw、Cursor Agent 这些编程 Agent,变成你团队里真正的同事。 它们可以接任务、写代码、提 PR、评论、改状态——就像一个人类开发者一样,但运行在你本地的 Daemon 上。
我逐行读完了 Multica 的核心代码(Go 后端约 30,000+ 行,前端 monorepo),从架构和设计思想角度做一次深度拆解。
二、整体架构:四层分离
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Next.js │────>│ Go 后端 │────>│ PostgreSQL │
│ 前端 │<────│ (Chi + WS) │<────│ (pgvector) │
└──────────────┘ └──────┬───────┘ └──────────────────┘
│
┌──────┴───────┐
│ Agent Daemon │ 运行在你的机器上
└──────────────┘ (Claude Code、Codex、OpenClaw...)
| 层级 | 技术栈 | 职责 |
|---|---|---|
| 前端 | Next.js 16 (App Router) + pnpm monorepo | 任务看板、Agent 管理、实时状态 |
| 后端 | Go (Chi router, sqlc, gorilla/websocket) | API、权限、事件总线、任务调度 |
| 数据库 | PostgreSQL 17 + pgvector | 持久化、多租户隔离 |
| Daemon | 本地进程(通过 CLI 启动) | 在用户机器上执行 Agent CLI |
1. 安全性:代码不离开用户的机器,API Key 不经过 Multica 服务器 2. 灵活性:支持任何 Agent CLI,不绑定特定模型或厂商
三、后端架构深度拆解
3.1 Agent Backend 接口:一个接口,十种实现
Multica 的 server/pkg/agent/ 目录下有一个极其优雅的设计:
// Backend 是统一的 Agent 执行接口
type Backend interface {
Execute(ctx context.Context, prompt string, opts ExecOptions) (*Session, error)
}
一个接口,十种实现:
| 文件 | Agent | 通信方式 |
|---|---|---|
claude.go | Claude Code | --output-format stream-json |
codex.go | OpenAI Codex | app-server 模式 |
cursor.go | Cursor Agent | stream-json |
openclaw.go | OpenClaw | JSON 模式 |
opencode.go | OpenCode | JSON 模式 |
gemini.go | Gemini CLI | stream-json |
hermes.go | Hermes | ACP 协议 |
kimi.go | Kimi | ACP 协议 |
pi.go | Pi | JSON 模式 |
copilot.go | GitHub Copilot | JSON 模式 |
类比:这就像一个出租车调度中心——它不自己开车,它只负责接单、派单、跟踪进度。至于司机开的是特斯拉还是比亚迪,调度中心不关心,只要司机能按标准格式汇报位置就行。
3.2 Daemon:任务执行的"沙盒"
Daemon 是 Multica 最核心的组件。它运行在用户本地,负责:
1. 接收任务:通过 WebSocket 从服务器接收 task:dispatch 事件
2. 准备环境:为每个任务创建隔离的执行目录(execenv)
3. 执行 Agent:调用对应的 Backend 实现,启动 Agent CLI
4. 流式回报:将 Agent 的输出实时推送到服务器
5. Skill 注入:将关联的 Skill 文件注入到 Agent 的工作目录
execenv 包的设计特别值得注意:
type Environment struct {
RootDir string // ~/multica_workspaces/{workspaceID}/{taskID}/
WorkDir string // .../workdir/ (Agent 在这里工作)
OutputDir string // .../output/ (Agent 的输出文件)
LogsDir string // .../logs/ (日志)
}
每个任务都有自己独立的目录,Agent 的所有操作都被限制在这个沙盒里。任务完成后,workdir 被清理,但 output 和 logs 保留用于调试。
设计思想:隔离 > 共享。每个任务从零开始,不依赖上一个任务的残留状态。这避免了"上一个任务改了个配置文件导致下一个任务崩溃"这类幽灵 Bug。
3.3 事件总线:同步 Pub/Sub
Multica 的 events.Bus 是一个进程内的同步发布/订阅系统:
type Bus struct {
mu sync.RWMutex
listeners map[string][]Handler // 按事件类型订阅
globalHandlers []Handler // 全局订阅
}
事件类型定义在 protocol/events.go 中,涵盖了整个系统的生命周期:
- Issue 事件:
issue:created,issue:updated,issue:deleted - Task 事件:
task:dispatch,task:progress,task:completed,task:failed - Agent 事件:
agent:status,agent:created,agent:archived - Autopilot 事件:
autopilot:run_start,autopilot:run_done - Chat 事件:
chat:message,chat:done
issue:created 事件,不需要知道谁会处理它(可能是通知系统、可能是 Autopilot 触发器、可能是 Analytics)。3.4 Autopilot:自动化编排引擎
Autopilot 是 Multica 的"定时任务 + 自动触发"系统。它支持两种执行模式:
create_issue:创建一个 Issue,然后让 Agent 去完成direct_task:直接创建任务,不经过 Issue
DispatchAutopilot 方法是核心入口:func (s *AutopilotService) DispatchAutopilot(ctx context.Context, ap db.Autopilot) error {
// 1. 创建一次 run 记录
// 2. 根据 execution_mode 创建 Issue 或直接入队任务
// 3. 发布 autopilot:run_start 事件
}
设计思想:声明式自动化。用户定义"什么时候做什么"(比如"每天早上 9 点检查依赖更新"),Autopilot 负责执行。这和 OpenClaw 的 cron job 思想一致,但 Multica 把它集成到了任务管理流程中——Autopilot 创建的 Issue 和手动创建的 Issue 走同样的生命周期。
3.5 Skill 系统:知识注入
Multica 的 Skill 系统有两层:
云端 Skill:存储在数据库中,通过 API 管理。支持从 ClawHub 和 skills.sh 导入。
本地 Skill:Daemon 会扫描本地 Agent 运行时的 Skill 目录(比如 ~/.claude/skills/),自动发现可用的 Skill。
当任务执行时,Daemon 会:
1. 查询 Agent 关联的云端 Skill
2. 扫描本地可用的 Skill
3. 将所有 Skill 文件注入到任务的执行环境中
4. 根据不同的 Agent Provider,选择不同的注入路径(Claude Code 用 .claude/skills/,OpenCode 用 release/ 等)
设计思想:Skill 是 Agent 的"经验"。就像一个新员工入职时会收到一份 SOP 文档一样,Agent 在执行任务前会收到相关的 Skill 文件。这让 Agent 的行为可以被标准化和复用。
四、前端架构深度拆解
4.1 Monorepo 分层:严格的包边界
Multica 的前端采用了极其严格的分层设计:
packages/
├── core/ # 业务逻辑(Zustand stores, React Query hooks, API client)
├── ui/ # 原子 UI 组件(零业务逻辑)
├── views/ # 业务页面/组件(零 next/*, 零 react-router-dom)
└── tsconfig/ # 共享 TypeScript 配置
硬规则(写死在 AGENTS.md 里):
| 包 | 不能导入 | 原因 |
|---|---|---|
core/ | react-dom, localStorage, process.env | 保持平台无关,Web/Desktop/未来 CLI 都能用 |
ui/ | @multica/core | 纯 UI,不知道业务概念 |
views/ | next/*, react-router-dom | 用 NavigationAdapter 抽象路由,Web 和 Desktop 共享 |
.ts/.tsx 文件(不预编译),由消费端的 bundler 直接编译。这带来了零配置的 HMR 和即时的 go-to-definition。类比:这就像一个公司的组织架构——ui/ 是设计部门(只管好看),core/ 是业务部门(只管逻辑),views/ 是产品部门(把设计和业务组装起来)。每个部门有自己的职责边界,不能越权。
4.2 状态管理:React Query + Zustand 的双轨制
Multica 的状态管理策略非常清晰:
- React Query 拥有所有服务端状态(Issues、Members、Agents、Inbox 等)
- Zustand 拥有所有客户端状态(当前 workspace 选择、视图过滤器、草稿、模态框)
// use-realtime-sync.ts 中的事件处理
onTaskCompleted((data) => {
qc.invalidateQueries({ queryKey: issueKeys.all(wsId) });
qc.invalidateQueries({ queryKey: inboxKeys.all(wsId) });
});
设计思想:单一数据源。服务端是唯一的数据真相,客户端只是缓存。WebSocket 事件不是"更新数据",而是"标记缓存过期"。下次访问时,React Query 会自动重新获取最新数据。
4.3 实时同步:WebSocket + 断线重连
前端的实时同步通过 use-realtime-sync.ts 实现,它监听所有 WebSocket 事件并相应地 invalidate React Query 缓存。
一个有趣的细节:断线重连后会全量 invalidate 所有缓存。这确保了即使断线期间错过了事件,重连后也能恢复到最新状态。
ws.onReconnect(async () => {
qc.invalidateQueries({ queryKey: issueKeys.all(wsId) });
qc.invalidateQueries({ queryKey: inboxKeys.all(wsId) });
qc.invalidateQueries({ queryKey: workspaceKeys.agents(wsId) });
// ... 全量刷新
});
五、最精妙的设计决策
5.1 多态指派(Polymorphic Assignees)
Issue 的指派人(assignee)不是简单的 user_id,而是 assignee_type + assignee_id 的组合:
assignee_type VARCHAR -- 'member' 或 'agent'
assignee_id UUID
这意味着 人类和 Agent 在任务系统里是完全平等的。一个 Issue 可以指派给人类、指派给 Agent、甚至同时指派给两者。Agent 创建的 Issue 和人类创建的 Issue 走完全相同的状态机。
设计思想:Agent 是一等公民,不是附属品。这不是一个"AI 辅助工具",而是一个"人机混合团队管理平台"。Agent 有自己的头像(紫色背景 + 机器人图标)、自己的并发限制、自己的 Skill 配置。
5.2 Agent-to-Agent 交互:防无限循环
Multica 的 prompt.go 里有一段特别有意思的代码:
if task.TriggerAuthorType == "agent" {
b.WriteString("⚠️ The triggering comment was posted by another agent. " +
"Before replying, decide whether a reply is warranted at all. " +
"If that comment was an acknowledgment, thanks, or sign-off " +
"and no concrete question or task is being asked of you, " +
"do NOT reply — silence is the preferred way to end " +
"agent-to-agent threads. If you do reply, do not @mention " +
"the other agent as a sign-off (that re-triggers them " +
"and starts a loop).\n\n")
}
设计思想:预防性设计 > 修复性设计。当两个 Agent 互相 @mention 时,很容易形成无限循环(A 回复 B → B 被 @mention 触发 → B 回复 A → A 被 @mention 触发 → ...)。Multica 在 prompt 层面就告诉 Agent:"如果对方只是在说谢谢,就不要回复了。"
这比事后加一个"最大回复次数"的限制要优雅得多——它让 Agent 学会了"什么时候该闭嘴"。
5.3 Session Resume:断点续传
Daemon 支持任务的中断恢复。如果 Agent 执行到一半超时或崩溃,下次可以带着 ResumeSessionID 继续:
if result.Status == "failed" && task.PriorSessionID != "" && result.SessionID == "" {
// Session resume 失败,用全新 session 重试
execOpts.ResumeSessionID = ""
retryResult, retryTools, retryErr := d.executeAndDrain(ctx, backend, prompt, execOpts, taskLog, task.ID)
}
设计思想:容错 > 完美。长时间运行的任务(比如大规模重构)不可能一次完成。支持断点续传让 Agent 可以"接着上次的进度继续",而不是每次都从头开始。
5.4 多租户隔离:workspace_id 无处不在
Multica 的所有数据库查询都带 workspace_id 过滤:
// 所有查询都过滤 workspace_id
func (h *Handler) ListSkills(w http.ResponseWriter, r *http.Request) {
workspaceID := h.resolveWorkspaceID(r)
skills, err := h.Queries.ListSkillsByWorkspace(r.Context(), parseUUID(workspaceID))
}
X-Workspace-ID header 路由请求到正确的 workspace。WebSocket 连接也按 workspace 隔离。
设计思想:租户隔离是架构级约束,不是业务逻辑。不是"每个 Handler 记得加 workspace 过滤",而是"框架层面保证不可能查到其他 workspace 的数据"。
六、技术栈的选择哲学
Multica 的技术栈选择透露出一种务实的工程哲学:
| 选择 | 不选 | 原因 |
|---|---|---|
| Go | Node.js/Python | 后端需要高性能 WebSocket 和进程管理 |
| sqlc | ORM (GORM/Prisma) | 类型安全的 SQL,零运行时开销 |
| Chi | Gin/Echo | 轻量、标准库兼容、中间件链清晰 |
| React Query | Redux/SWR | 服务端状态缓存 + 自动失效是核心需求 |
| Zustand | Redux | 轻量、无 boilerplate、适合客户端状态 |
| pnpm + Turborepo | Nx/Lerna | 更快的安装速度和构建缓存 |
七、和同类项目的对比
| 维度 | Multica | Paperclip | Vibe Kanban | Claude Code Dispatch |
|---|---|---|---|---|
| 开源 | ✅ Apache 2.0 | ❌ | ❌ | ❌ (Anthropic) |
| Agent 多样性 | 10+ 种 | 有限 | Claude only | Claude only |
| 本地执行 | ✅ Daemon | ❌ 云端 | ❌ 云端 | ❌ 云端 |
| Skill 系统 | ✅ 云端+本地 | ❌ | ❌ | ❌ |
| Autopilot | ✅ 定时+触发 | 部分 | ❌ | ❌ |
| 人机混合 | ✅ 一等公民 | 部分 | ❌ | ❌ |
八、一句话总结
> Multica 的架构精髓可以用一句话概括:它不是在构建一个"AI 工具",而是在构建一个"AI 员工管理系统"。Agent Backend 接口让任何 CLI Agent 都能接入,Daemon 让代码不离开用户机器,事件总线让系统松耦合,Skill 系统让 Agent 的知识可复用,多态指派让人类和 Agent 真正平等。这不是一个周末项目——这是一个经过深思熟虑的、面向 AI 原生团队的基础设施。
---
📎 GitHub: multica-ai/multica 📎 官网: multica.ai 📎 作者: forrestchang (Jiayuan Zhang) 📎 协议: Apache 2.0 📎 相关项目: andrej-karpathy-skills (78K ⭐)
🌟 智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。
🎁 领取 2000万 Tokens