软件公司工作流:从需求到代码
学习目标
理解 MetaGPT 软件公司工作流中各角色的数据流向和触发机制,以及如何从一行需求产出完整的项目代码。
项目实践
工作流全景
UserRequirement │ ▼ cause_by: UserRequirement┌─────────────┐ ┌────────────────────────────────────┐│ProductManager│───▶│ watch: [UserRequirement] ││ (Alice) │ │ actions: [PrepareDocuments, ││ │ │ WritePRD] │└─────────────┘ └──────────┬─────────────────────────┘ │ cause_by: WritePRD ▼┌─────────────┐ ┌────────────────────────────────────┐│ Architect │───▶│ watch: [WritePRD] ││ (Bob) │ │ actions: [WriteDesign] │└─────────────┘ └──────────┬─────────────────────────┘ │ cause_by: WriteDesign ▼┌─────────────┐ ┌────────────────────────────────────┐│ Engineer2 │───▶│ watch: [WriteDesign] ││ (Alex) │ │ actions: [WriteCode, WriteReview] │└─────────────┘ └──────────┬─────────────────────────┘ │ cause_by: WriteCode ▼ src/*.py (代码文件)流水线式数据流
每个角色通过 _watch() 声明对上游输出的依赖:
| 角色 | 监听(watch) | 输出(cause_by) | by_order actions |
|---|---|---|---|
| ProductManager | UserRequirement | WritePRD | 1. PrepareDocuments 2. WritePRD |
| Architect | WritePRD | WriteDesign | 1. WriteDesign |
| Engineer2 | WriteDesign | WriteCode | 1. WriteCode 2. WriteCodeReview |
WritePRD 三类场景处理
WritePRD.run() 根据需求类型分三路:
1. Bugfix 场景
async def _is_bugfix(self, context: str) -> bool: if not self.repo.code_files_exists(): # 必须先有代码 return False node = await WP_ISSUE_TYPE_NODE.fill(req=context, llm=self.llm) return node.get("issue_type") == "BUG"检测到 bugfix 后:
- 保存
BUGFIX_FILENAME - 返回
AIMessage(send_to="Alex")直接转发给 Engineer
2. 新需求场景
async def _handle_new_requirement(self, req: Document): node = await self._new_prd(req.content) # LLM 生成 PRD new_prd_doc = await self.repo.docs.prd.save(...) await self._save_competitive_analysis(new_prd_doc) # 竞品分析 await self.repo.resources.prd.save_pdf(doc=new_prd_doc) # 生成 PDF输出文件:
docs/prd.json— PRD 结构化数据resources/prd-competitive-analysis.svg— 竞争象限图resources/prd.md— PRD Markdown 版本
3. 需求更新场景
async def _handle_requirement_update(self, req, related_docs): for doc in related_docs: await self._update_prd(req=req, prd_doc=doc) # 合并旧 PRD使用 REFINED_PRD_NODE 将新需求与旧 PRD 合并。
ProjectRepo 文件管理
workspace/├── docs/│ ├── prd/ # PRD JSON 文件│ │ └── 20240101_120000.json│ └── system_design/ # 系统设计 JSON│ └── 20240101_120000.json├── resources/│ ├── prd/ # PRD PDF 和 SVG│ └── competitive_analysis/ # 竞争分析 SVG├── src/ # 源代码│ └── *.py└── tests/ # 测试代码 └── *.pyProjectRepo 封装了对这些目录的操作:
repo.docs.prd.save()— 保存 PRDrepo.docs.system_design.save()— 保存系统设计repo.resources.prd.save_pdf()— 生成 PDFrepo.git_repo— Git 仓库管理
成本与轮次控制
company.invest(investment=3.0) # 预算 $3await company.run(n_round=5) # 最多 5 轮CostManager统计每轮 token 消耗Team._check_balance()在每轮前检查预算NoMoneyException在超出预算时终止运行
问题与规避
轮次不足导致流程未完成
- 5 轮是最低要求(PM → Architect → Engineer 至少 3 轮 + code review 2 轮)
- 如果启用 QA 测试(
run_tests=True),需要至少 8 轮 - 对策:复杂任务增加
n_round,或增大investment
增量开发(inc 模式)
inc=True时,从project_path加载现有仓库,只处理增量需求- 需要指定
reqa_file(目标文件)来限定修改范围 - 注意:增量模式需要
max_auto_summarize_code控制代码总结次数
设计取舍
固定流水线 vs 动态协商
- 软件公司使用固定流水线(BY_ORDER 模式),角色按预定义顺序执行
- 优点:流程确定性强、调试方便、成本可预测
- 代价:无法处理异常情况(如设计阶段发现需求不合理需要回溯)
PRD 结构化 vs 自由文本
- PRD 使用 JSON 结构化存储(ActionNode 约束字段)
- 优点:下游角色(Architect)可以精确提取需要的信息
- 代价:prompt 较长、LLM 可能遗漏部分字段
- 折中:提供 Markdown 版本作为人类可读输出
参考来源
- 源码验证:
metagpt/software_company.py:14—generate_repo()组装团队 - 源码验证:
metagpt/roles/product_manager.py:43— ProductManager 的 actions 和 watch - 源码验证:
metagpt/roles/architect.py:47— Architect 的 actions 和 watch - 源码验证:
metagpt/actions/write_prd.py:86— WritePRD.run() 三路分发 - 源码验证:
metagpt/utils/project_repo.py— ProjectRepo 文件管理