vibecoding.site
← back to blog
约 12 分钟3 标签

我用 4 个 AI Agent 协作搭了一个全栈站

PM + 前端 + 后端 Tech Lead + 编码工 —— 把「AI 协作」从口号落到任务板、状态机、不停止机制的工程协议。


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 完成。带来三个好处:

  1. git diff 就是审计日志,每次"派活/审核"都有不可篡改的时间线
  2. 任何 agent 接手只需要读一份文件,不需要登录任何系统
  3. 冲突变成 git merge 冲突,有现成的工具处理

第一周的踩坑清单

写下来不是抱怨,而是记录"新版本与训练数据时间差"会反复出现:

  • Next.js 16 的 searchParamsPromise: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 是项目级总览。

评论

加载评论中…

留下评论 · 提交后由 PM 审核显示

评论无需注册,审核通过后可见。