title: 我用 4 个 AI Agent 协作搭了一个全栈站 —— 协作架构与踩坑 slug: multi-agent-fullstack publishedAt: 2026-05-10 excerpt: PM + 前端 + 后端 Tech Lead + 编码工 —— 把「AI 协作」从口号落到任务板、状态机、不停止机制的工程协议。 tags: [multi-agent, vibe-coding, process] readingMin: 12 wordCount: 1650 draft: false
为什么不是一个 super-agent
把所有活儿交给一个 agent 一气呵成,看起来最省事 —— 一个 system prompt、一个会话、一次输出。但凡试过用单 agent 跑超过半小时的工作流的人都知道,这种方式有三个结构性的问题:
- token 上限:Claude 一次 invocation 的可用上下文有限,跑半天就被截断
- 失忆:上一段写过的设计决策,后半段经常忘掉甚至自我矛盾
- 角色混乱:既要写前端,又要写后端,又要审自己 —— 当一个 agent 把"做"和"审"放在一起时,几乎一定会偏向自洽而不是挑毛病
所以这个站从立项第一天就决定:4 个 AI Agent 协作,每个 agent 只负责一段很窄的能力,所有跨 agent 的状态写到磁盘上的 Markdown 文件。看起来繁琐,实际是把"协作"从口头协议变成了版本化的工程协议。
4 个角色
| 代号 | 职责 | 可写状态 |
|---|---|---|
| PM(主 Claude) | 选题 / 拆任务 / 派活 / 审核 / 合并 | 通过 完成 打回 阻塞 STOP_NOW |
| Claude1(前端) | 实现 apps/web 下所有前端代码 + 自测 | 进行中 提交 待审核 |
| Claude2(后端 Tech Lead) | 给 Codex 派后端微任务 + 审 Codex 产出 | 进行中 提交 待审核 |
| Codex(后端编码工) | 按 Claude2 的指令实现后端代码 | 进行中 提交 |
权限红线:通过 / 完成 / 合并 / STOP_NOW 这几个终态字段,只有 PM 能写。其它角色越权写入,PM 下一次巡检时会撤销。这条红线是后面所有"信任"的源头。
任务状态机长什么样
草稿 ──PM──▶ 待领取 ──Agent 领取──▶ 进行中 ──Agent──▶ 提交
│
PM 审核 ◀────┘
│ │
┌───────┘ └────────┐
▼ ▼
通过 打回(回到 进行中)
│
▼
完成
每条任务在 协作/任务板.md 里独立一段,任何 agent 都能扫一眼就知道"现在我能不能动这条":
type TaskStatus =
| "草稿"
| "待领取"
| "进行中"
| "提交"
| "通过"
| "打回"
| "完成"
| "阻塞";
function isAgentCanGrab(s: TaskStatus, owner: string, me: string): boolean {
return owner === me && (s === "待领取" || s === "打回");
}Agent 改 状态: 进行中 就视为认领,改 状态: 提交 就视为待审。PM 巡检只看"状态 = 提交"的任务,审核后落 通过 或 打回。这套状态字段加上权限红线,就是协作语言本身,不再依赖 prompt 的措辞调优。
不停止机制
更狠的一招是"不停止协作"。每个干活的 agent 进入 invocation 后,跑这样一段伪代码:
loop forever:
read 协作/任务板.md 顶部 PROJECT_STATUS
read 自己角色卡的 STOP_NOW 字段
if 任一非空: save_state(); exit
tasks = parse(任务板.md) where 负责==me and 状态 in {待领取, 打回}
if tasks 非空:
pick first
do_work()
write 提交段 + 改状态为 提交
continue
# 没活干:轻轮询
for i in 1..10: sleep 60s; recheck
while true: sleep 300s; recheck
Token 上限会让 invocation 自然截断 —— 这时 PM 监听完成事件,立刻用同角色 prompt 起新 invocation,带上"接力 prompt:你是 ClaudeX,先读你的角色卡和任务板"。用户感知不到这种切换,看到的是"3 个 agent 始终在线"。
落到代码:apps/web 与 apps/api 的边界
技术栈选型本身没有什么稀奇的:
- 前端:Next.js 16.2.6(App Router) + React 19 + TypeScript strict + Tailwind v4 + shadcn/ui
- 后端:Fastify 5 + Zod + Prisma 6 + SQLite(起步)
- Monorepo:pnpm workspace
- 内容:
@next/mdx+ remark-gfm + rehype-slug + rehype-pretty-code + Shiki 双主题
但有一条目录红线值得单独写下:
E:/web项目/
├── apps/web/ # 只有 Claude1 可写
├── apps/api/ # 只有 Claude2 派 / Codex 写
├── 协作/ # Claude1/Claude2 只动自己卡;任务板按状态字段动
└── 进度/ # 只有 PM 写
Agent 在工作循环里被告知"你不能 commit 自己负责范围之外的文件"。Claude1 不动 apps/api,Codex 不动 apps/web,PM 不亲自写任何业务代码。这条规则让 git history 异常干净:每个 commit 都能反查到出自哪个 agent、对应任务板的哪一条任务。
任务板是唯一的真源
很容易踩的坑是"用 GitHub Issues / Linear / 自建后端"来管任务。但只要任务管理脱离了代码仓库本身,就多了一层需要同步的状态。我们做的相反:任务板就是仓库里的一个 Markdown 文件,提交、审核、状态变更都通过修改这个文件 + git commit 完成。带来三个好处:
- git diff 就是审计日志,每次"派活/审核"都有不可篡改的时间线
- 任何 agent 接手只需要读一份文件,不需要登录任何系统
- 冲突变成 git merge 冲突,有现成的工具处理
第一周的踩坑清单
写下来不是抱怨,而是记录"新版本与训练数据时间差"会反复出现:
- Next.js 16 的
searchParams是Promise:async page 必须await,否则 typecheck 直接失败。这条在我们 T102/blog列表上踩了一次 - Tailwind v4 的
@theme inline:CSS variable 要在@theme里再声明一次,utility class 才认得bg-brand @base-ui/react/button:没有 Radix 风格的asChild,只能用<Link className={cn(buttonVariants(...))}>兜- Turbopack 的 MDX 插件约束:
remarkPlugins/rehypePlugins只能传字符串名,不能传函数,因为 Rust runtime 拿不到 JS 函数引用 - MDX 正文里裸的
{xxx}:会被 MDX 当 JSX 表达式编译,build 时报ReferenceError。要么用反引号包,要么用反斜杠转义
这些坑大多不是"Next 不好",而是 新版本与训练数据的时间差。解药是 apps/web/AGENTS.md 里那行钉子:
read
node_modules/next/dist/docs/before writing any code.
让 agent 每次先看本地文档,而不是凭印象写。
在实际跑的过程里学到的
跑到 Sprint 2 收尾,有几条结论比"哪个框架更好用"重要:
- PM 的核心价值不是写任何代码,是维护"任务板 + 状态机 + 进度文档"这三件事的不变量。一旦不变量被破坏(例如 agent 越权写了
通过),整个系统的可信度就掉了 - Agent 的失败模式高度可预测:多数错误是"绕开红线"或"假装看了某个文档其实没看"。解决办法不是改 prompt,而是把红线落到工程协议上 —— 比如把"必须读
AGENTS.md"写到apps/web/CLAUDE.md的@AGENTS.md引用里,让框架强制每个 agent 在写 apps/web 代码前看一遍 /compact上下文压缩之后,PM 用 5 步 SOP(读进度 README + 协作总览 + 任务板 + 角色卡顶部 + git log)就能恢复完整状态。这个 SOP 现在写在进度/README.md → 上下文压缩与恢复段里,任何接手的 AI 一眼能看懂
接下来要做的事
剩下要写的篇:
Claude Code + Magic UI MCP:让 AI 自己长出「审美」:讲怎么把组件库变成 MCP 工具Next.js 16 + Tailwind v4 + shadcn/ui:把骨架塞进 monorepo:技术栈选型与陷阱把「PM 审核」变成可执行的协议:协作 MD 文档设计:协议设计本身- 两篇 Mini Demo 的工程笔记
- 一篇真实案例:
一天搞定 Cloudflare Turnstile(模糊化)
想看协作流程本身长什么样,真正的源在仓库里 ——
协作/任务板.md是唯一的进度真源,协作/前端-Claude1.md/协作/后端-Claude2.md/协作/后端-Codex.md是 3 张角色卡,进度/README.md是项目级总览。