一个基于 QClaw 的多 Agent 协作开发模式探索实践
之前做小程序开发有个问题一直困扰我:重复劳动太多。
同样的列表页、表单、状态管理,每次都要重新写。更烦的是需求一变,改个接口字段得翻遍所有引用它的地方。
后来接触到腾讯电脑管家推出的 QClaw,它支持多 Agent 协作。我冒出个想法:能不能搞一条全自动的小程序生产线? 需求丢进去,代码吐出来,人只负责验收。
这就是"小程序黑暗工厂"的由来。

图:QClaw 客户端中的黑暗工厂 Agent 全貌 - 包含 Project Manager 和 5 个 Worker Agents
名字借用了制造业的概念——黑暗工厂(Dark Factory)是完全自动化、不需要灯光的工厂,因为里面没有工人。
我的小程序黑暗工厂思路类似:
你的一句话需求 ↓[QClaw] 接收需求,派发给 Project Manager ↓[Project Manager] 创建 RTM 追踪矩阵,派发给 Analysis Worker ↓[Analysis Worker] 拆解需求,生成规格文档 + 任务计划 ↓[UI Worker] 出高保真设计稿 + HTML 交互原型 ↓[Backend + Frontend + Test Worker] 并行开发 ↓[Project Manager] 监控进度 + 触发 QA 验证 ↓微信推送通知你验收人只需要做三件事:提需求、确认设计稿、最终验收。其他全部自动化。
为了验证这套模式,我用黑暗工厂做了个简单的 Demo 小程序——「每日一句」阅读打卡。功能不复杂,主要是验证黑暗工厂的可行性。

图:每日一句小程序首页 - 展示金句卡片、收藏按钮、已打卡状态
"做一个每日金句阅读打卡小程序,每天展示一句精选名言/诗词,用户可以打卡记录阅读,收藏喜欢的句子,查看历史打卡日历。"
| 首页 | |
| 历史页 | |
| 我的页 |

图:每日一句小程序历史页 - 日历视图展示打卡记录,顶部显示阅读天数和连续打卡统计

图:每日一句小程序我的页 - 展示收藏列表和统计数据(总阅读天数/连续打卡/累计收藏)
QClaw 的实际架构是三层 Agent 体系:

图:三层 Agent 架构 - QClaw 作为入口,Project Manager 调度,5 个 Worker 并行执行
| 第一层 | QClaw | ||
| 第二层 | Project Manager | ||
| 第三层 | Analysis Worker | ||
| 第三层 | UI Worker | ||
| 第三层 | Backend Worker | ||
| 第三层 | Frontend Worker | ||
| 第三层 | Test Worker |
Project Manager 是流程守门人,不是代码编写者:
RTM(需求追踪矩阵)是整个工厂的唯一真相来源:
queue/<PROJECT>/wip/<任务名>/RTM.md以「每日一句」项目为例:
PM 每完成一个 STEP,必须更新 RTM。

图:10 步流水线 - 从需求接收到最终验收的完整流程,包含 Phase 2 并行开发阶段
你给 QClaw 发一句话:
"做一个每日金句阅读打卡小程序,每天展示一句精选名言/诗词,用户可以打卡记录阅读,收藏喜欢的句子,查看历史打卡日历。"

图:微信 ClawBot 推送的设计稿确认通知 - 包含首页、历史页、我的页的设计规范详情
QClaw 接收后,派发给 Project Manager:
sessions_spawn( task: "接收需求:做一个每日金句阅读打卡小程序...\n" +"1. 写入 queue/pending/<时间戳>-daily-quote-reader.md\n" +"2. 运行 RTM 初始化\n" +"3. 进入 STEP-2 派发 Analysis Worker", runtime: "subagent", agentId: "project-manager", cwd: "D:/project/mp-dark-factory", mode: "run")PM 自动把需求写入 queue/pending/,文件名带上时间戳,按 FIFO 排队。然后运行 RTM 初始化。
RTM 更新:填写基本信息 + 技术栈(uni-app CLI),当前阶段 → STEP-1。
⚠️ PM 绝对不能自己写 spec.md。必须派发给 Analysis Worker。
PM 派发 Analysis Worker:
sessions_spawn( task: "读取 queue/<PROJECT>/pending/<需求文件.md>, 在 projects/daily-quote-reader/specs/ 下生成: - spec.md(功能清单:首页/历史页/我的页、前后端边界、验收标准) - task_plan.md(Phase 列表 + 验收标准) - scenarios.md(用户场景:打开小程序→浏览金句→打卡→查看历史) 如有歧义列出选项,不要自己猜。完成后通知 PM。", runtime: "subagent", agentId: "analysis-worker", cwd: "D:/project/mp-dark-factory/agents/workers/analysis", mode: "run")Analysis Worker 产出示例:
# spec.md## 功能清单- 首页:每日金句轮播、打卡按钮、收藏按钮- 历史页:日历视图、打卡记录、连续打卡统计- 我的页:收藏列表、阅读统计## 数据模型```tsinterface Quote { id: string content: string author: string source: string type: 'quote' | 'poem' | 'excerpt'}interface UserData { checkInDates: string[] favoriteIds: string[] lastCheckIn: string}**RTM 更新**:REQ 表填写完毕,当前阶段 → STEP-2。### Step 3:UI 设计(UI Worker)> ⚠️ **PM 绝对不能自己做设计。必须派发给 UI Worker。**PM 派发 UI Worker:```typescriptsessions_spawn( task: "读取 projects/daily-quote-reader/specs/SPEC.md, 在 projects/daily-quote-reader/designs/ 下生成: - 365pt × 667pt 高保真设计稿(首页/历史页/我的页) - tokens.json(Design Token:主色 #4A90D9、卡片圆角 24rpx 等) - HTML 交互原型 + interaction.md 设计稿必须包含真机外壳(iPhone机身+状态栏+小程序胶囊+Home Indicator)。 每个页面必须附带 interaction.md 说明交互行为。 完成后通知 PM。", runtime: "subagent", agentId: "ui-worker", cwd: "D:/project/mp-dark-factory/agents/workers/ui", mode: "run")UI Worker 完成后,PM 必须微信通知用户确认设计稿。

图:微信 ClawBot 推送的开发计划通知 - 设计稿确认后 Frontend Worker 已派发,展示 6 个开发阶段
RTM 更新:UI 项填写完毕,设计稿+原型已确认,当前阶段 → STEP-3。
⚠️ PM 不自己生成 task_plan.md,它由 Analysis Worker 在 STEP-2 产出。PM 只确认。
PM 检查 projects/daily-quote-reader/task_plan.md,确认:
RTM 更新:负责人列填写完毕,当前阶段 → STEP-4。
PM 从项目 repo 创建 git worktree:
cd projects/daily-quote-readergit worktree add worktrees/feature-daily-quote -b feature/daily-quote然后派发 Worker:
// 派发 Frontend Workersessions_spawn( task: "【技术栈约束 - 强制】- 必须使用 uni-app CLI + Vue3 + TypeScript- 参考 designs/tokens.json 和 designs/prototypes/ 按图施工- 开发以下页面: 1. pages/index/index.vue:首页(金句轮播、打卡、收藏) 2. pages/history/index.vue:历史页(日历视图、统计) 3. pages/my/index.vue:我的页(收藏列表)- 使用本地存储 utils/storage.ts 持久化用户数据- 完成后通知 PM。", runtime: "subagent", agentId: "frontend-worker", cwd: "D:/project/mp-dark-factory/agents/workers/frontend", mode: "run")// 派发 Test Workersessions_spawn( task: "为 daily-quote-reader 编写 Vitest 测试:- 测试 quotes.ts 数据逻辑- 测试 storage.ts 本地存储- 测试页面组件渲染- 覆盖率阈值 ≥ 70%", runtime: "subagent", agentId: "test-worker", cwd: "D:/project/mp-dark-factory/agents/workers/test", mode: "run")
图:微信 ClawBot 推送的开发完成通知 - Frontend Worker 已完成所有功能开发,6 个 Phase 全部完成
RTM 更新:派发时间 + Worktree 路径 + 各 REQ 状态 → 🔄 进行中。
PM 每 5 分钟运行心跳检测:
npx ts-node scripts/feedback-monitor.ts check --project daily-quote-reader⚠️ PM 不得在 worker 干活时自己上手写代码!
RTM 更新:Worker 每完成一个子任务 → 更新 RTM 完成度。
PM 主动推送验收结果给用户,用户回复"✅"才继续。

图:每日一句小程序打卡成功弹窗 - 展示打卡成功后的动画效果和提示文案
RTM 更新:UI 验收结果 → ✅ 通过 或 ❌ 需修改。
PM 运行 Verification 检查:
npx ts-node scripts/verification-check.ts run projects/daily-quote-reader/worktrees/feature-daily-quote自动执行:
// verification-report.json{"taskId": "daily-quote-reader","timestamp": "2026/4/12 09:10:00","results": [ { "name": "Vitest 测试", "passed": true, "coverage": 78 }, { "name": "ESLint 检查", "passed": true, "errorCount": 0 }, { "name": "uni build 构建", "passed": true }, { "name": "设计还原度", "passed": true } ],"overallPassed": true}RTM 更新:填写 QA 门控记录。

图:STEP-8 QA 验证结果 - 全量通过,包含 Vitest 测试、ESLint、uni build、Boundary Scan 的检查结果
git merge feature/daily-quote → devqueue/daily-quote-reader/pending/ → queue/daily-quote-reader/done/(归档)PM 将结果返回给 QClaw,QClaw 推送完成通知:
好的,验收通过 ✅
daily-quote-reader 任务正式关闭 🏁
交付清单
项目 状态 uni-app 构建产物 ✅ dist/build/mp-weixin TabBar 图标 ✅ 6 个精美 PNG 打卡按钮 ✅ 尺寸优化 Vitest 测试 ✅ 85 个测试,78.49% 覆盖率 ESLint ✅ 0 错误 队列归档 ✅ queue/done/ 回复 ✅ 确认关闭 或 💬 提修改意见

图:最终交付清单 - 包含 uni-app 构建产物、TabBar 图标、打卡按钮、Vitest 测试、ESLint、队列归档的完整状态

图:微信 ClawBot 推送的项目就绪通知 - UI 设计已验收、代码质量已通过、已合并到主分支
RTM 更新:填写最终确认清单 + 完成时间 + 结论。
用户查看交付清单,回复 ✅ 确认关闭 或提出修改意见。
RTM 更新:所有 REQ → ✅ 完成,RTM 完成率 → 100%,任务关闭。
根据最新 Agent 职责,工厂采用五阶段流水线:

图:五阶段流水线 - Phase 0~4 的完整流程,包含人工介入点和自动化阶段
| Phase 0 | ||||
| Phase 1 | ||||
| Phase 2 | ||||
| Phase 3 | ||||
| Phase 4 |
图:Phase 2 并行开发 - Backend、Frontend、Test Worker 的依赖关系和数据流转
关键约束:
apis/*.ts)后才能开始对接// src/data/quotes.tsexportinterface Quote { id: string content: string author: string source: stringtype: 'quote' | 'poem' | 'excerpt'}// 预置 30 条金句(名言15 + 诗词10 + 书摘5)exportconst allQuotes: Quote[] = [ { id: 'q1', content: '人生就像骑自行车,要保持平衡就得不断前进。', author: '阿尔伯特·爱因斯坦', source: '名言', type: 'quote' }, { id: 'p1', content: '春风又绿江南岸,明月何时照我还。', author: '王安石', source: '泊船瓜洲', type: 'poem' },// ... 更多数据]// 根据日期获取今日句子exportfunctiongetTodayQuote(): Quote{const today = newDate()const dayOfYear = Math.floor((today.getTime() - newDate(today.getFullYear(), 0, 0).getTime()) / (1000 * 60 * 60 * 24))return allQuotes[dayOfYear % allQuotes.length]}<template> <view class="container"> <!-- 顶部日期 --> <view class="date-header"> <text class="date-text">{{ currentDate }}</text> </view> <!-- 金句轮播 --> <swiper class="quote-swiper" :current="currentIndex" @change="onSwiperChange"> <swiper-item v-for="quote in displayQuotes" :key="quote.id"> <view class="quote-card"> <text class="quote-text">{{ quote.content }}</text> <text class="author">—— {{ quote.author }}</text> </view> </swiper-item> </swiper> <!-- 操作按钮 --> <view class="action-buttons"> <view class="btn-favorite" @click="toggleFavorite"> <text :class="['icon-heart', { active: isFavorite }]">❤</text> <text>{{ isFavorite ? '已收藏' : '收藏' }}</text> </view> <view class="btn-checkin" @click="handleCheckIn"> <view class="checkin-circle" :class="{ checked: isTodayChecked }"> <text>✓</text> </view> <text>{{ isTodayChecked ? '已打卡' : '打卡' }}</text> </view> </view> </view></template><script setup lang="ts">import { ref, computed, onMounted } from 'vue'import { getTodayQuote, getAllQuotes } from '@/data/quotes'import { getStorage, setStorage } from '@/utils/storage'// 用户数据const userData = ref({ checkInDates: [] as string[], favoriteIds: [] as string[]})// 今日是否已打卡const isTodayChecked = computed(() => { const today = new Date().toISOString().split('T')[0] return userData.value.checkInDates.includes(today)})// 打卡处理const handleCheckIn = () => { const today = new Date().toISOString().split('T')[0] if (userData.value.checkInDates.includes(today)) { uni.showToast({ title: '今日已打卡', icon: 'none' }) return } userData.value.checkInDates.push(today) setStorage('userData', userData.value) uni.showToast({ title: '打卡成功!', icon: 'success' })}onMounted(() => { const data = getStorage('userData') if (data) userData.value = data})</script>用黑暗工厂开发「每日一句」小程序,有三点感受比较深:
开发效率提升
传统方式:需求 → 设计 → 编码 → 测试,产品经理、设计师、前端、后端、测试,多人协作,信息反复同步。
黑暗工厂:Analysis Worker 分析需求的同时,UI Worker 准备设计规范,Frontend Worker 搭建项目骨架。原本数天的工作,1 天完成。
代码质量稳定
每个产出都有测试覆盖率和 ESLint 检查。最终测试覆盖率 78%,0 个 ESLint 错误,构建一次通过。
人可以专注重要的事
我只需要:告诉 QClaw 我要什么,确认 UI Worker 的设计稿,最后验收。其他全部自动化,我有更多时间思考产品逻辑。
PM 抢着写代码
一开始 PM 觉得自己写 spec.md 更快,结果流程混乱。后来强制规定 PM 只能派发不能自己写,所有文档必须 Worker 产出。
Agent 之间协调死锁
一开始想让 Agent 之间直接通信,结果经常出现 A 等 B、B 等 A 的情况。后来改成文件系统协调——每个 Worker 只读写自己的进度文件,PM 统一轮询,死锁问题解决。
需求模糊时容易跑偏
Analysis Worker 初期经常"过度发挥",我说"做一个列表",它可能脑补出筛选、排序、分页全套功能。后来加了强制确认机制——遇到模糊需求 PM 必须暂停,发微信问清楚再继续。
这套黑暗工厂的设计,借鉴了 Harness Engineering(驾驭工程) 的理念。
Harness Engineering 的核心思想是:通过强约束来驾驭复杂性,而不是依赖人的自觉。
具体体现在:
| 流程约束 | |
| 职责约束 | |
| 数据约束 | |
| 质量约束 | |
| 反馈约束 |
通过这套约束系统,把"人可能犯错的地方"用流程卡住,让系统自己运转。
说实话,这座"黑暗工厂"并不完美。但它让我意识到一件事:AI 不是来替代程序员的,而是来替代重复劳动的。
机器处理 80% 的常规工作,人就可以专注于 20% 真正需要创造力的部分。我感觉,软件研发黑暗工厂的时代可能比我们想象的要来得快。也许再过一两年(国内),这种多 Agent 协作的开发模式就会成为常态。到那时候,程序员的角色可能会从"写代码的人"变成"设计工厂的人",而我们需要积极拥抱这种变化。