package squad import ( "fmt" "strings" "time" ) // PlannerRequest 任务规划请求 type PlannerRequest struct { TaskKey string `json:"task_key"` Title string `json:"title"` ProjectName string `json:"project_name"` CustomerName string `json:"customer_name"` DeviceType string `json:"device_type"` IntendedUse string `json:"intended_use"` TargetMarket string `json:"target_market"` Materials []MaterialItem `json:"materials"` KnowledgeHits []KnowledgeHit `json:"knowledge_hits"` Fields map[string]string `json:"fields"` CustomSteps []StepSpec `json:"custom_steps,omitempty"` } // PlannerResult 任务规划产出 type PlannerResult struct { TaskKey string `json:"task_key"` Title string `json:"title"` PlanningMode PlanningMode `json:"planning_mode"` Squad SquadConfig `json:"squad"` Workflow WorkflowPlan `json:"workflow"` TemplateContent string `json:"template_content"` } // AdaptivePlanner 自适应任务规划器 type AdaptivePlanner struct { registry *RoleRegistry assets AssetProvider } // NewAdaptivePlanner 创建自适应任务规划器 func NewAdaptivePlanner(reg *RoleRegistry, assets AssetProvider) *AdaptivePlanner { if reg == nil { reg = NewRoleRegistry() } return &AdaptivePlanner{registry: reg, assets: assets} } // Plan 执行动态规划:区分固定工作流自适应微调 vs 非标文档自主规划 func (p *AdaptivePlanner) Plan(req PlannerRequest) (*PlannerResult, error) { if isStandardTask(req.TaskKey) { return p.planFixedAdaptive(req) } return p.planAutonomousAdhoc(req) } func isStandardTask(taskKey string) bool { return taskKnown(taskKey) } // planFixedAdaptive 固定工作流动态微调 func (p *AdaptivePlanner) planFixedAdaptive(req PlannerRequest) (*PlannerResult, error) { title := TaskArtifactTitle(req.TaskKey) if req.Title != "" { title = req.Title } steps := req.CustomSteps if len(steps) == 0 { if strings.HasPrefix(req.TaskKey, "rd_") { steps = rdevWorkflowSteps(req.TaskKey, rdevComplexityTier(req.Fields)) } else { steps = DefaultWorkflowSteps(req.TaskKey) } } var agents []AgentSpec if strings.HasPrefix(req.TaskKey, "rd_") { agents = rdevSquadAgents(req.TaskKey, rdevComplexityTier(req.Fields)) } else { agents = DefaultSquadAgents(req.TaskKey) } // 材料嗅探感知 (Material Sniffing) var matBuilder strings.Builder for _, m := range req.Materials { matBuilder.Write(m.Content) matBuilder.WriteString(" ") } matText := strings.ToLower(matBuilder.String()) // 嗅探 1: 动物源与生物相容性 (植入/牛心包/猪源/GB/T 16886/ISO 10993) if strings.Contains(matText, "牛心包") || strings.Contains(matText, "动物源") || strings.Contains(matText, "生物相容性") || strings.Contains(matText, "16886") || strings.Contains(matText, "植入接触血液") { // 检查是否已包含专门步骤 hasBioStep := false for _, s := range steps { if strings.Contains(s.ID, "biocompatibility") || strings.Contains(s.Title, "生物相容性") { hasBioStep = true break } } if !hasBioStep { bioStep := StepSpec{ ID: "step_01_biocompatibility", Role: "biocompatibility_expert", Title: "动物源生物相容性与病毒灭活专项评估", SubWorkspace: "tasks/01_biocompatibility", Mode: "execute", Parallel: true, AllowDynamicAdjustment: true, Accept: []string{ "识别植入接触途径与接触时间级别", "依据GB/T 16886提炼必测生物学指标", "出具动物源性病毒灭活与免疫原性风险控制建议", }, } // 派生特设专员 bioRole, _ := p.registry.SpawnAdHocRole(AdHocRoleRequest{ RoleKey: "biocompatibility_expert", Name: "生物相容性评估专员", BaseRole: "engineer", DomainTopic: "动物源性材料与生物相容性评价", Responsibilities: []string{"生物相容性接触级别界定", "动物源材料病毒灭活路径核对"}, ForbiddenActions: []string{"严禁代替国家检验机构出具报告"}, }) // 插入到 steps 列表(插入在 organize/search 之后,draft 之前) draftIdx := len(steps) - 1 for idx, s := range steps { if s.Role == "writer" || strings.Contains(s.ID, "draft") { draftIdx = idx break } } newSteps := make([]StepSpec, 0, len(steps)+1) newSteps = append(newSteps, steps[:draftIdx]...) newSteps = append(newSteps, bioStep) newSteps = append(newSteps, steps[draftIdx:]...) steps = newSteps // 向小队追加专员 hasBioAgent := false for _, a := range agents { if a.Role == "biocompatibility_expert" { hasBioAgent = true break } } if !hasBioAgent { agents = append(agents, bioRole) } } } var tmplContent string if p.assets != nil { var err error tmplContent, err = p.assets.DocTemplate(req.TaskKey) if err != nil { tmplContent = "" } } if strings.TrimSpace(tmplContent) == "" { tmplContent = fmt.Sprintf("# %s\n\n## 1. 结论\n\n待确认\n\n## 2. 正文\n\n待确认\n", title) } now := time.Now() wfPlan := WorkflowPlan{ WorkflowID: fmt.Sprintf("wf_%s_%d", req.TaskKey, now.UnixNano()), TaskKey: req.TaskKey, Title: title, PlanningMode: PlanModeFixedAdaptive, Status: "pending", CurrentStepIndex: 0, Steps: steps, } squadCfg := SquadConfig{ SquadName: fmt.Sprintf("%s_squad", req.TaskKey), Version: "1.0.0", Agents: agents, } return &PlannerResult{ TaskKey: req.TaskKey, Title: title, PlanningMode: PlanModeFixedAdaptive, Squad: squadCfg, Workflow: wfPlan, TemplateContent: tmplContent, }, nil } // planAutonomousAdhoc 非工作流文档自主规划 func (p *AdaptivePlanner) planAutonomousAdhoc(req PlannerRequest) (*PlannerResult, error) { title := req.Title if title == "" { title = req.TaskKey } // 匹配或派生领域专家角色 specialistRole := p.resolveSpecialistRole(req) // 准备小队成员:整理专员、领域专员、文档专员、商务把关负责人 orgSpec, _ := p.registry.GetRole("organizer") writerSpec, _ := p.registry.GetRole("writer") leaderSpec, _ := p.registry.GetRole("leader") agents := []AgentSpec{orgSpec, specialistRole, writerSpec, leaderSpec} // 组装标准 4-stage WBS 步骤 steps := []StepSpec{ { ID: "step_01_organize", Role: "organizer", Title: "梳理输入背景、提取事实与缺口", SubWorkspace: "tasks/01_organize", Mode: "execute", AllowDynamicAdjustment: true, Accept: []string{ "梳理材料中的客户需求与产品边界条件", "提取结构化字段并沉淀至黑板 facts", "标记待论证的工程/法规/环境参数缺口", }, }, { ID: "step_02_specialist", Role: specialistRole.Role, Title: fmt.Sprintf("开展【%s】专业推演与核心技术规程制定", title), SubWorkspace: fmt.Sprintf("tasks/02_%s", specialistRole.Role), Mode: "execute", Needs: []string{"tasks/01_organize/output.md"}, AllowDynamicAdjustment: true, Accept: []string{ "针对核心技术指标与环境/工程要求给出详尽设计方案", "针对缺失信息依据行业先验推断基准假设(Baseline Assumptions)", "给出关键参数验证与监控路径", }, }, { ID: "step_03_draft", Role: "writer", Title: fmt.Sprintf("按标准化架构撰写《%s》正文终稿", title), SubWorkspace: "tasks/03_draft", Mode: "execute", Needs: []string{fmt.Sprintf("tasks/02_%s/output.md", specialistRole.Role)}, Accept: []string{ "严格按模板章节成文,杜绝敷衍套话", "详实展开技术与管理条款,写满正文", "文末集中挂载《基准假设与待确认清单》", }, }, { ID: "step_04_review", Role: "leader", Title: "全篇一致性终审与商务合规把关", SubWorkspace: "tasks/04_review", Mode: "execute", Needs: []string{"tasks/03_draft/output.md"}, Accept: []string{ "校验全文逻辑闭环与标准出处标注", "汇总待客户最终拍板的决策项", "交付终稿 output.md", }, }, } // 自动生成结构完备的文档 Markdown 模板 tmpl := p.generateAdhocTemplate(title) now := time.Now() wfPlan := WorkflowPlan{ WorkflowID: fmt.Sprintf("wf_adhoc_%s_%d", req.TaskKey, now.UnixNano()), TaskKey: req.TaskKey, Title: title, PlanningMode: PlanModeAutonomousAdhoc, Status: "pending", CurrentStepIndex: 0, Steps: steps, } squadCfg := SquadConfig{ SquadName: fmt.Sprintf("%s_dynamic_squad", req.TaskKey), Version: "1.0.0", Agents: agents, } return &PlannerResult{ TaskKey: req.TaskKey, Title: title, PlanningMode: PlanModeAutonomousAdhoc, Squad: squadCfg, Workflow: wfPlan, TemplateContent: tmpl, }, nil } // resolveSpecialistRole 智能匹配或派生领域专家 func (p *AdaptivePlanner) resolveSpecialistRole(req PlannerRequest) AgentSpec { var matText strings.Builder for _, m := range req.Materials { matText.WriteString(m.Filename) matText.WriteString(" ") matText.Write(m.Content) matText.WriteString(" ") } query := strings.ToLower(fmt.Sprintf("%s %s %s %s %s %s", req.Title, req.TaskKey, req.ProjectName, req.DeviceType, req.IntendedUse, matText.String())) // 特殊垂直领域主动派生 if strings.Contains(query, "洁净") || strings.Contains(query, "净化") || strings.Contains(query, "车间") || strings.Contains(query, "厂房") || strings.Contains(query, "gmp") || strings.Contains(query, "cleanroom") { adHoc, err := p.registry.SpawnAdHocRole(AdHocRoleRequest{ RoleKey: "cleanroom_expert", Name: "洁净工程与环境控制专员", BaseRole: "engineer", DomainTopic: "十万级/万级洁净厂房建设与GMP环境控制", Responsibilities: []string{"净化空调通风系统设计", "车间压差梯度与气流流型规划", "悬浮粒子与沉降菌监测规程"}, ForbiddenActions: []string{"严禁虚报洁净度等级"}, }) if err == nil { return adHoc } } if strings.Contains(query, "伦理") || strings.Contains(query, "知情同意") || strings.Contains(query, "临床试验") { adHoc, err := p.registry.SpawnAdHocRole(AdHocRoleRequest{ RoleKey: "clinical_ethics_specialist", Name: "临床试验伦理合规专员", BaseRole: "regulatory", DomainTopic: "临床试验伦理审查与知情同意(ICF)", Responsibilities: []string{"伦理委员会前置审查要点自查", "知情同意书合规条款审核"}, ForbiddenActions: []string{"严禁代行伦理委员会裁定"}, }) if err == nil { return adHoc } } if rec, found := p.registry.RecommendRole(query); found { return rec } eng, _ := p.registry.GetRole("engineer") return eng } // generateAdhocTemplate 生成自解释标准化文档模板 func (p *AdaptivePlanner) generateAdhocTemplate(title string) string { var sb strings.Builder sb.WriteString(fmt.Sprintf("# {{project_name}} - %s\n\n", title)) sb.WriteString("> 编制单位:北京水木东方医疗器械研发小队 \n") sb.WriteString("> 生成日期:{{generated_at}} \n") sb.WriteString("> 项目编号:{{snapshot_id}} \n\n") sb.WriteString("---\n\n") sb.WriteString("## 1. 概述与背景目标\n\n") sb.WriteString("### 1.1 编制目的与适用范围\n\n") sb.WriteString("{{scope_and_purpose}}\n\n") sb.WriteString("### 1.2 产品与项目基本信息\n\n") sb.WriteString("- 产品名称:{{product_name}}\n") sb.WriteString("- 客户名称:{{customer_name}}\n") sb.WriteString("- 设备分类:{{device_type}}\n") sb.WriteString("- 预期用途:{{intended_use}}\n\n") sb.WriteString("## 2. 核心技术规范与规程细则\n\n") sb.WriteString("### 2.1 关键指标体系与系统要求\n\n") sb.WriteString("{{technical_specifications}}\n\n") sb.WriteString("### 2.2 实施路径与工序控制要求\n\n") sb.WriteString("{{procedure_and_control}}\n\n") sb.WriteString("## 3. 风险防范与法规质量合规\n\n") sb.WriteString("### 3.1 关键风险识别与防御策略\n\n") sb.WriteString("{{risk_control}}\n\n") sb.WriteString("### 3.2 适用标准与规范清单\n\n") sb.WriteString("{{compliance_standards}}\n\n") sb.WriteString("## 4. 基准假设与待确认清单\n\n") sb.WriteString("### 4.1 系统先行推断的基准假设 (Baseline Assumptions)\n\n") sb.WriteString("{{baseline_assumptions}}\n\n") sb.WriteString("### 4.2 待客户决策与补充清单 (Pending Checklist)\n\n") sb.WriteString("{{pending_checklist}}\n\n") return sb.String() }