跳转到内容

软件公司工作流:从需求到代码

学习目标

理解 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
ProductManagerUserRequirementWritePRD1. PrepareDocuments 2. WritePRD
ArchitectWritePRDWriteDesign1. WriteDesign
Engineer2WriteDesignWriteCode1. 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/ # 测试代码
└── *.py

ProjectRepo 封装了对这些目录的操作:

  • repo.docs.prd.save() — 保存 PRD
  • repo.docs.system_design.save() — 保存系统设计
  • repo.resources.prd.save_pdf() — 生成 PDF
  • repo.git_repo — Git 仓库管理

成本与轮次控制

company.invest(investment=3.0) # 预算 $3
await 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:14generate_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 文件管理