From 9d33b1c804d53d772e2db509fbdf9cb1a2078bd2 Mon Sep 17 00:00:00 2001 From: WeiCHEN Date: Thu, 10 Sep 2026 23:48:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(workflow):=20Phase=204=20=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E4=BA=A7=E5=93=81=E7=BB=8F=E7=90=86=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81=E3=80=81=E7=B3=BB=E7=BB=9F=E9=9C=80=E6=B1=82=E8=A7=84?= =?UTF-8?q?=E6=A0=BC=E4=B9=A6=E4=B8=8E=E8=B4=A8=E9=87=8F=E9=97=A8=E7=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/bizdev/service.go | 50 +++++- internal/squad/quality_gate.go | 41 +++++ internal/squad/quality_gate_test.go | 70 +++++++++ internal/squad/service.go | 2 + internal/squad/workspace.go | 230 ++++++++++++++++++++++++++++ templates/docs/system_reqs.md | 62 ++++++++ 6 files changed, 453 insertions(+), 2 deletions(-) create mode 100644 templates/docs/system_reqs.md diff --git a/internal/bizdev/service.go b/internal/bizdev/service.go index 16ac90d3..f6dd319a 100644 --- a/internal/bizdev/service.go +++ b/internal/bizdev/service.go @@ -187,9 +187,55 @@ func (s *Service) ExecuteTask(ctx context.Context, req TaskRunRequest) (*TaskRun }) } - // 自动补充知识库检索 (如针对 research、feasibility_reg、cleanroom_spec、prelim_design 等阶段) + // 针对 system_reqs(智能产品经理):若未显式提供 materials,自动抽取项目事实黑板/集体上下文为需求输入 + if req.TaskKey == "system_reqs" && len(materials) == 0 && s.ctxMgr != nil && req.ProjectID > 0 { + coll, err := s.ctxMgr.GetProjectContext(ctx, req.ProjectID) + if err == nil && coll != nil { + var b strings.Builder + customer := coll.BlackboardFacts["customer_name"] + if customer == "" { + customer = req.CustomerName + } + device := coll.BlackboardFacts["device_type"] + if device == "" { + device = req.DeviceType + } + intendedUse := coll.BlackboardFacts["intended_use"] + if intendedUse == "" { + intendedUse = req.IntendedUse + } + targetMarket := coll.BlackboardFacts["target_market"] + if targetMarket == "" { + targetMarket = req.TargetMarket + } + + b.WriteString(fmt.Sprintf("# 项目需求背景事实与上下文输入\n\n- 项目名称: %s\n- 客户名称: %s\n- 产品类型: %s\n- 预期用途: %s\n- 目标市场: %s\n\n", + coll.ProjectName, customer, device, intendedUse, targetMarket)) + + if len(coll.BlackboardFacts) > 0 { + b.WriteString("## 已提取项目事实与技术参数\n") + for k, v := range coll.BlackboardFacts { + b.WriteString(fmt.Sprintf("- %s: %s\n", k, v)) + } + b.WriteString("\n") + } + if len(coll.MilestoneDecisions) > 0 { + b.WriteString("## 关键里程碑与团队决策\n") + for _, d := range coll.MilestoneDecisions { + b.WriteString(fmt.Sprintf("- [%s] %s: %s\n", d.UserName, d.ActivityType, d.Title)) + } + b.WriteString("\n") + } + materials = append(materials, squad.MaterialItem{ + Filename: "project_requirements_context.md", + Content: []byte(b.String()), + }) + } + } + + // 自动补充知识库检索 (如针对 research、feasibility_reg、cleanroom_spec、prelim_design、system_reqs、test_manager 等阶段) hits := req.KnowledgeHits - if len(hits) == 0 && (req.TaskKey == "research" || req.TaskKey == "feasibility_reg" || req.TaskKey == "cleanroom_spec" || req.TaskKey == "prelim_design") { + if len(hits) == 0 && (req.TaskKey == "research" || req.TaskKey == "feasibility_reg" || req.TaskKey == "cleanroom_spec" || req.TaskKey == "prelim_design" || req.TaskKey == "system_reqs" || req.TaskKey == "test_manager") { device := req.DeviceType if device == "" && req.Fields != nil { device = req.Fields["device_type"] diff --git a/internal/squad/quality_gate.go b/internal/squad/quality_gate.go index 9a8db0b8..f8fed19e 100644 --- a/internal/squad/quality_gate.go +++ b/internal/squad/quality_gate.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "encoding/json" "fmt" "io" "os" @@ -104,6 +105,46 @@ func (q *QualityGate) Validate(wsDir string, taskKey string, content string) (*Q } } + // 5. 智能产品经理工作流:系统需求规格书检查 + if taskKey == "system_reqs" { + if !strings.Contains(content, "REQ-") && !strings.Contains(content, "SYS-REQ") { + report.Violations = append(report.Violations, "系统需求规格书缺少规范的需求编号(如 REQ-01 / SYS-REQ-01)") + report.Score -= 20.0 + report.Passed = false + } + hasVerification := strings.Contains(content, "测试") || strings.Contains(content, "分析") || + strings.Contains(content, "审查") || strings.Contains(content, "演示") || + strings.Contains(content, "检验") || strings.Contains(content, "检") || strings.Contains(content, "测") + if !hasVerification { + report.Violations = append(report.Violations, "系统需求清单缺少验证方式字段(测试/分析/审查/演示)") + report.Score -= 15.0 + report.Passed = false + } + } + + // 6. 智能测试经理工作流:系统验证方案及计划检查 + if taskKey == "test_manager" { + if !strings.Contains(content, "TC-") && !strings.Contains(content, "TEST-") { + report.Violations = append(report.Violations, "系统验证方案缺少规范的测试用例编号(如 TC-01 / TEST-01)") + report.Score -= 20.0 + report.Passed = false + } + if !strings.Contains(content, "REQ-") { + report.Violations = append(report.Violations, "系统验证方案缺少对上游系统需求编号(REQ-)的追溯覆盖") + report.Score -= 15.0 + report.Passed = false + } + tcPath := filepath.Join(wsDir, "artifacts", "test_cases.json") + if tcData, err := os.ReadFile(tcPath); err == nil && len(tcData) > 0 { + var dummy any + if err := json.Unmarshal(tcData, &dummy); err != nil { + report.Violations = append(report.Violations, "artifacts/test_cases.json 不是合法的 JSON 格式") + report.Score -= 10.0 + report.Passed = false + } + } + } + if report.Score < 0 { report.Score = 0 } diff --git a/internal/squad/quality_gate_test.go b/internal/squad/quality_gate_test.go index 22abc7e5..0fc71fbe 100644 --- a/internal/squad/quality_gate_test.go +++ b/internal/squad/quality_gate_test.go @@ -131,3 +131,73 @@ func TestQualityGate_AutoRepair(t *testing.T) { t.Errorf("expected non-nil quality report") } } + +func TestQualityGate_SystemReqsAndTestManager(t *testing.T) { + tmpDir := t.TempDir() + engine := squad.NewWorkspaceEngine() + gate := squad.NewQualityGate() + + // 1. 测试 system_reqs + ws1, err := engine.PrepareWorkspace(squad.WorkspacePrepareRequest{ + WorkDir: filepath.Join(tmpDir, "ws_reqs"), + TaskKey: "system_reqs", + StageTitle: "系统需求规格书", + ProjectName: "医疗监护仪", + TemplateContent: "# 系统需求规格书\n\n## 1. 结论\n\n## 2. 系统需求清单\n", + }) + if err != nil { + t.Fatalf("PrepareWorkspace failed: %v", err) + } + + // 缺少需求编号和验证方式 + badReqContent := "# 系统需求规格书\n\n## 1. 结论\n结论完整\n\n## 2. 系统需求清单\n系统应支持心率采集。\n" + rep1, err := gate.Validate(ws1.WorkDir, "system_reqs", badReqContent) + if err != nil { + t.Fatalf("Validate failed: %v", err) + } + if rep1.Passed { + t.Errorf("expected system_reqs missing REQ- and verification to fail") + } + + // 合规文本 + goodReqContent := "# 系统需求规格书\n\n## 1. 结论\n结论完整\n\n## 2. 系统需求清单\n| REQ-01 | 系统应支持心率监测,测量误差不超过 ±2bpm | 测试 | 高 |\n" + rep2, err := gate.Validate(ws1.WorkDir, "system_reqs", goodReqContent) + if err != nil { + t.Fatalf("Validate failed: %v", err) + } + if !rep2.Passed { + t.Errorf("expected compliant system_reqs to pass, got violations: %v", rep2.Violations) + } + + // 2. 测试 test_manager + ws2, err := engine.PrepareWorkspace(squad.WorkspacePrepareRequest{ + WorkDir: filepath.Join(tmpDir, "ws_test"), + TaskKey: "test_manager", + StageTitle: "系统验证方案及计划", + ProjectName: "医疗监护仪", + TemplateContent: "# 系统验证方案及计划\n\n## 1. 结论\n\n## 2. 用例与验证规程\n", + }) + if err != nil { + t.Fatalf("PrepareWorkspace failed: %v", err) + } + + // 缺少用例和上游追溯 + badTestContent := "# 系统验证方案及计划\n\n## 1. 结论\n结论\n\n## 2. 用例与验证规程\n验证功能正常。\n" + rep3, err := gate.Validate(ws2.WorkDir, "test_manager", badTestContent) + if err != nil { + t.Fatalf("Validate failed: %v", err) + } + if rep3.Passed { + t.Errorf("expected test_manager missing TC- and REQ- to fail") + } + + // 合规文本 + goodTestContent := "# 系统验证方案及计划\n\n## 1. 结论\n结论\n\n## 2. 用例与验证规程\n| TC-01 | 验证心率测量精度 | 追溯 REQ-01 | 判定准则误差 <= ±2bpm | 通过 |\n" + rep4, err := gate.Validate(ws2.WorkDir, "test_manager", goodTestContent) + if err != nil { + t.Fatalf("Validate failed: %v", err) + } + if !rep4.Passed { + t.Errorf("expected compliant test_manager to pass, got violations: %v", rep4.Violations) + } +} diff --git a/internal/squad/service.go b/internal/squad/service.go index c3892600..6e889f55 100644 --- a/internal/squad/service.go +++ b/internal/squad/service.go @@ -127,6 +127,8 @@ var SupportedTasks = []TaskMeta{ {Key: "feasibility_dev", Title: "设计开发可行性评估", ArtifactTitle: "设计开发可行性评估报告", Description: "工程化差距、技术路线与系统架构可行性推导"}, {Key: "feasibility_reg", Title: "注册路径可行性评估", ArtifactTitle: "注册路径可行性评估报告", Description: "分类建议、临床评价策略与主要标准检测规划"}, {Key: "user_requirements", Title: "用户需求表", ArtifactTitle: "用户需求表", Description: "用户角色画像与可追溯需求条目清单"}, + {Key: "system_reqs", Title: "系统需求规格书", ArtifactTitle: "系统需求规格书", Description: "智能产品经理深度提炼,输出系统需求规格书及工程追溯"}, + {Key: "test_manager", Title: "系统验证方案及计划", ArtifactTitle: "系统验证方案及计划", Description: "智能测试经理基于系统需求生成系统测试方案与测试用例"}, {Key: "prelim_design", Title: "系统初步设计方案", ArtifactTitle: "系统初步设计方案", Description: "子系统架构边界、数据接口与Mermaid上下文流向"}, {Key: "cdo_quote", Title: "CDO报价单", ArtifactTitle: "CDO报价单(含定价核算 Excel)", Description: "基于公司定价模型的工时拆解、成本核算与法定说明"}, } diff --git a/internal/squad/workspace.go b/internal/squad/workspace.go index 87e45e2b..cff38920 100644 --- a/internal/squad/workspace.go +++ b/internal/squad/workspace.go @@ -645,6 +645,102 @@ func DefaultSquadAgents(taskKey string) []AgentSpec { ForbiddenActions: []string{"严禁代用户做商业拍板"}, }, } + case "system_reqs": + return []AgentSpec{ + { + Role: "organizer", + Name: "需求梳理专员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"用户需求抽取", "产品定位基线对齐", "UR需求池建立"}, + ForbiddenActions: []string{"严禁随意篡改原始用户需求"}, + }, + { + Role: "engineer", + Name: "系统工程架构师", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"系统需求分解", "验证方式定义", "接口定义", "requirements.json 导出"}, + ForbiddenActions: []string{"严禁遗漏验证方式", "严禁需求编号重复"}, + }, + { + Role: "regulatory", + Name: "法规合规审查专员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"医疗器械强标比对", "适用性与理由论证"}, + ForbiddenActions: []string{"严禁引用虚构标准号"}, + }, + { + Role: "writer", + Name: "系统需求文档编制专员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"严格按 system_reqs.md 模板成文", "正文结构完整", "填满追溯表"}, + ForbiddenActions: []string{"严禁残留占位符", "严禁写不做展开"}, + }, + { + Role: "leader", + Name: "智能产品经理主管", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"系统需求规格书终审", "追溯一致性把关", "质量门禁验收"}, + ForbiddenActions: []string{"严禁放行未覆盖验证方式的需求"}, + }, + } + case "test_manager": + return []AgentSpec{ + { + Role: "organizer", + Name: "需求追溯分析员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"上游系统需求解析", "需求全集锁定", "追溯关系初始化"}, + ForbiddenActions: []string{"严禁遗漏任一条上游需求"}, + }, + { + Role: "engineer", + Name: "系统测试工程师", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"系统验证用例设计", "判据与接受准则", "test_cases.json 导出"}, + ForbiddenActions: []string{"严禁测试方法泛化为仅写标准号", "严禁无判定准则"}, + }, + { + Role: "regulatory", + Name: "试验标准审查员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"检验方法符合性评估", "检测设备与环境要求审查"}, + ForbiddenActions: []string{"严禁使用过期作废标准"}, + }, + { + Role: "writer", + Name: "系统测试方案编制专员", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"严格按 test_manager.md 模板成文", "用例主表翔实完整"}, + ForbiddenActions: []string{"严禁残留占位符", "严禁写不做展开"}, + }, + { + Role: "leader", + Name: "智能测试经理主管", + Model: "claude-3-7-sonnet", + Tools: []string{"read", "write", "edit"}, + BashPermission: "deny", + Responsibilities: []string{"系统验证方案终审", "全覆盖无静默遗漏门禁把关", "质量签署"}, + ForbiddenActions: []string{"严禁放行覆盖率不足 100% 的方案"}, + }, + } default: return []AgentSpec{ { @@ -841,6 +937,140 @@ func DefaultWorkflowSteps(taskKey string) []StepSpec { }, }, } + case "system_reqs": + return []StepSpec{ + { + ID: "step_01_organize", + Role: "organizer", + Title: "解析用户需求并抽取产品功能点", + SubWorkspace: "tasks/01_organize", + Mode: "execute", + Accept: []string{ + "抽取用户需求或项目事实黑板中的关键需求条目", + "提取系统功能、非功能指标及环境约束", + "向 blackboard 写入 facts 与 gaps", + }, + }, + { + ID: "step_02_engineer", + Role: "engineer", + Title: "系统技术规格与性能指标分解", + SubWorkspace: "tasks/02_engineer", + Mode: "execute", + Needs: []string{"tasks/01_organize/output.md"}, + Accept: []string{ + "定义子系统性能、电气/软件/机械指标与参数", + "规范接口协议与环境要求", + }, + }, + { + ID: "step_03_regulatory", + Role: "regulatory", + Title: "医疗器械强标比对与合规性论证", + SubWorkspace: "tasks/03_regulatory", + Mode: "execute", + Needs: []string{"tasks/01_organize/output.md"}, + Accept: []string{ + "审查适用医疗器械强制性标准及条款要求", + "输出安全、可靠性与合规性约束条目", + }, + }, + { + ID: "step_04_draft", + Role: "writer", + Title: "编制系统需求规格书全文", + SubWorkspace: "tasks/04_draft", + Mode: "execute", + Needs: []string{ + "tasks/01_organize/output.md", + "tasks/02_engineer/output.md", + "tasks/03_regulatory/output.md", + }, + Accept: []string{ + "按 template.md 结构展开,包含系统需求清单与接口要求", + "每条系统需求必须具备明确唯一的 REQ- 编号与验证方式", + "禁止敷衍套话与未替换占位符", + }, + }, + { + ID: "step_05_review", + Role: "leader", + Title: "终审需求可测性与可追溯性定稿", + SubWorkspace: "tasks/05_review", + Mode: "execute", + Needs: []string{"tasks/04_draft/output.md"}, + Accept: []string{ + "全面核查需求条目可验证性与无歧义性", + "核查追溯关系完整性并交付终稿", + }, + }, + } + case "test_manager": + return []StepSpec{ + { + ID: "step_01_trace", + Role: "organizer", + Title: "解析上游系统需求并锁定全量追溯矩阵", + SubWorkspace: "tasks/01_trace", + Mode: "execute", + Accept: []string{ + "全量读取上游系统需求规格书的所有 REQ- 编号条目", + "建立 100% 覆盖的测试需求追溯矩阵底表", + }, + }, + { + ID: "step_02_cases", + Role: "engineer", + Title: "设计系统测试用例与判定准则", + SubWorkspace: "tasks/02_cases", + Mode: "execute", + Needs: []string{"tasks/01_trace/output.md"}, + Accept: []string{ + "为每条需求设计至少一个具备明确合格判定准则的测试用例 TC-", + "导出 test_cases.json 结构化用例清单至 artifacts/", + }, + }, + { + ID: "step_03_regulatory", + Role: "regulatory", + Title: "检验规程与检测环境合规审查", + SubWorkspace: "tasks/03_regulatory", + Mode: "execute", + Needs: []string{"tasks/02_cases/output.md"}, + Accept: []string{ + "核验测试方法与引用的医疗器械检验标准条款一致性", + "审查仪器设备与测试环境要求", + }, + }, + { + ID: "step_04_draft", + Role: "writer", + Title: "编制系统验证方案及计划全文", + SubWorkspace: "tasks/04_draft", + Mode: "execute", + Needs: []string{ + "tasks/01_trace/output.md", + "tasks/02_cases/output.md", + "tasks/03_regulatory/output.md", + }, + Accept: []string{ + "严格按 test_manager.md 模板生成正式方案文本", + "嵌入测试用例清单与覆盖率统计,严禁遗漏上游需求", + }, + }, + { + ID: "step_05_review", + Role: "leader", + Title: "全覆盖门禁终审与定稿交付", + SubWorkspace: "tasks/05_review", + Mode: "execute", + Needs: []string{"tasks/04_draft/output.md"}, + Accept: []string{ + "验证需求覆盖率达到 100%", + "签署验证结论并交付", + }, + }, + } default: return []StepSpec{ { diff --git a/templates/docs/system_reqs.md b/templates/docs/system_reqs.md new file mode 100644 index 00000000..f553d50e --- /dev/null +++ b/templates/docs/system_reqs.md @@ -0,0 +1,62 @@ +# 系统需求规格书(SR) + +- 项目:{{project_name}} +- 生成时间:{{generated_at}} +- 快照:{{snapshot_id}} +- 文件编号:RD-SR +- 记录归属:DHF +- 版本:A +- 阶段:03 设计输入 + +## 结论 + +{{conclusion}} + +## 适用性 + +- 适用 / 不适用:{{applicability}} +- 不适用理由:{{na_rationale}} + +## 产品定位与预期用途 + +- 产品名称:{{project_name}} +- 适用人群与场景:{{intended_use}} +- 目标市场与监管路径:{{target_market}} + +## 系统需求清单 + +| ID | 需求陈述 | 追溯 UR/UN | 验证方式 | 优先级 | +| --- | --- | --- | --- | --- | +{{system_requirements_table}} + +## 接口与环境要求 + +| 接口类型 | 说明与技术参数 | 协议/物理接口 | +| --- | --- | --- | +{{interface_requirements_table}} + +## 追溯关系 + +| 本文件 ID | 上游(输入/需求) | 下游(输出/验证/确认) | +| --- | --- | --- | +| RD-SR | 用户需求文档 / 项目立项事实上下文 | 系统验证方案及计划 (RD-SVP) | + +## 已有材料摘要 + +{{materials}} + +## 待确认清单 + +{{pending_items}} + +## 签署 + +| 角色 | 姓名 | 结论 | 日期 | +| --- | --- | --- | --- | +| 编制 | {{author_name}} | 已编制 | {{generated_at}} | +| 审核 | {{reviewer_name}} | 待审核 | | +| 批准 | {{approver_name}} | 待批准 | | + +## 说明 + +本文档由智能产品经理小队在任务快照上生成,属于受控设计输入历史记录。后续补充的材料不会静默改变本次版本内容。