package squad import ( "fmt" "strings" "sync" ) // AdHocRoleRequest 特设临时角色派生请求 type AdHocRoleRequest struct { RoleKey string `json:"role_key"` Name string `json:"name"` BaseRole string `json:"base_role"` DomainTopic string `json:"domain_topic"` Responsibilities []string `json:"responsibilities"` ForbiddenActions []string `json:"forbidden_actions"` } // RoleRegistry 智能体小队角色资产中心 type RoleRegistry struct { mu sync.RWMutex roles map[string]AgentSpec } // NewRoleRegistry 初始化角色资产中心并载入 8 大标准专员 func NewRoleRegistry() *RoleRegistry { r := &RoleRegistry{ roles: make(map[string]AgentSpec), } r.registerDefaults() return r } func (r *RoleRegistry) registerDefaults() { standards := []AgentSpec{ { Role: "organizer", Name: "材料整理专员", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"材料事实抽取", "缺口识别", "字段结构化回填", "材料提取与整理"}, ForbiddenActions: []string{"严禁测算价格", "严禁出具法规终结裁定", "严禁撰写正文终稿"}, InstructionsFile: "configs/agents/organizer.md", }, { Role: "searcher", Name: "资料检索专员", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"公开资料检索", "法规标准核对", "出处与日期标注", "文献溯源与检索"}, ForbiddenActions: []string{"严禁编造URL与标准号", "未检索到须标明尝试路径"}, InstructionsFile: "configs/agents/searcher.md", }, { Role: "regulatory", Name: "医疗器械法规专员", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"器械分类初筛", "注册路径比对", "关键标准提炼", "法规审评路径"}, ForbiddenActions: []string{"严禁代做行政终局裁定", "必须标注需向窗口确认"}, InstructionsFile: "configs/agents/regulatory.md", }, { Role: "engineer", Name: "系统与方案工程师", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"系统架构设计", "关键技术选型", "工程实现可行性推导", "硬件模块与嵌入式结构方案设计"}, ForbiddenActions: []string{"严禁虚构未验证技术可行性", "严禁忽视安全隔离要求"}, InstructionsFile: "configs/agents/engineer.md", }, { Role: "market", Name: "市场与竞品分析师", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"竞品同维度对比", "市场规模测算", "机会与风险分析", "竞品横向功能对比与市场容量测算"}, ForbiddenActions: []string{"严禁编造市场份额与价格", "必须采用统一对比维度"}, InstructionsFile: "configs/agents/market.md", }, { Role: "finance", Name: "成本与定价测算专员", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"CDO定价核算", "WBS工时拆解", "成本核算与商务条款", "CDO成本核算与定价工时拆解"}, ForbiddenActions: []string{"严禁脱离工时模型拍脑袋报价", "严禁擅自承诺超额商业折扣"}, InstructionsFile: "configs/agents/finance.md", }, { Role: "writer", Name: "文档撰写专员", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"严格四段式成文", "依据材料出处引用", "模板各章节写满", "撰写正式交付文档正文终稿"}, ForbiddenActions: []string{"严禁以省略写法跳过应写章节", "严禁随意篡改前序事实"}, InstructionsFile: "configs/agents/writer.md", }, { Role: "leader", Name: "商务对接负责人", Source: RoleSourceStandard, Model: "MiniMax-M3", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", Responsibilities: []string{"计划审核", "正文终审", "待确认清单汇总", "对外汇报", "商务合同把关与终审交付"}, ForbiddenActions: []string{"严禁代用户做商业拍板", "严禁直接交付未审核初稿"}, InstructionsFile: "configs/agents/leader.md", }, } for _, s := range standards { r.roles[s.Role] = s } } // GetRole 根据 Key 获取角色 func (r *RoleRegistry) GetRole(key string) (AgentSpec, bool) { r.mu.RLock() defer r.mu.RUnlock() spec, ok := r.roles[key] return spec, ok } // ListRoles 列出当前注册的所有角色 func (r *RoleRegistry) ListRoles() []AgentSpec { r.mu.RLock() defer r.mu.RUnlock() res := make([]AgentSpec, 0, len(r.roles)) for _, spec := range r.roles { res = append(res, spec) } return res } // RegisterRole 显式注册或更新角色 func (r *RoleRegistry) RegisterRole(spec AgentSpec) { r.mu.Lock() defer r.mu.Unlock() if spec.BashPermission == "" { spec.BashPermission = "deny" } r.roles[spec.Role] = spec } // RecommendRole 根据领域任务或文本描述推荐最贴切的标准角色 func (r *RoleRegistry) RecommendRole(query string) (AgentSpec, bool) { r.mu.RLock() defer r.mu.RUnlock() q := strings.ToLower(query) type scoreItem struct { spec AgentSpec score int } var best scoreItem // 规则特征优先字典 ruleWeights := map[string][]string{ "regulatory": {"法规", "注册", "审评", "分类界定", "临床评价", "二类", "三类", "药监局", "nmpa", "ce", "fda"}, "searcher": {"检索", "文献", "标准", "标准号", "查证", "公开资料", "溯源"}, "market": {"竞品", "市场", "容量", "份额", "对标", "优劣势", "商业模式"}, "engineer": {"工程", "硬件", "软件", "结构", "架构", "技术路线", "嵌入式", "算法", "系统", "模块", "选型"}, "organizer": {"整理", "事实", "缺口", "字段", "回填", "抽取", "材料梳理", "基线"}, "finance": {"成本", "工时", "核算", "报价", "定价", "cdo", "价格", "利润", "商务条款"}, "writer": {"撰写", "成文", "起草", "初稿", "正文", "章节", "四段式"}, "leader": {"终审", "审核", "把关", "总览", "交付", "待确认清单", "对外汇报", "决策"}, } for roleKey, keywords := range ruleWeights { spec, exists := r.roles[roleKey] if !exists { continue } curScore := 0 for _, kw := range keywords { if strings.Contains(q, kw) { curScore += 10 } } // 职责辅助匹配 for _, resp := range spec.Responsibilities { if strings.Contains(q, strings.ToLower(resp)) { curScore += 5 } } if curScore > best.score { best = scoreItem{spec: spec, score: curScore} } } if best.score > 0 { return best.spec, true } // 兜底退回 engineer 或 organizer if eng, ok := r.roles["engineer"]; ok { return eng, true } return AgentSpec{}, false } // SpawnAdHocRole 自治派生特设临时专员角色 func (r *RoleRegistry) SpawnAdHocRole(req AdHocRoleRequest) (AgentSpec, error) { if req.RoleKey == "" { return AgentSpec{}, fmt.Errorf("role_key cannot be empty") } baseRoleKey := req.BaseRole if baseRoleKey == "" { baseRoleKey = "engineer" } r.mu.Lock() defer r.mu.Unlock() baseSpec, exists := r.roles[baseRoleKey] if !exists { baseSpec = r.roles["engineer"] } model := baseSpec.Model if model == "" { model = "MiniMax-M3" } name := req.Name if name == "" { name = fmt.Sprintf("%s专项专员", req.RoleKey) } responsibilities := append([]string{}, req.Responsibilities...) if len(responsibilities) == 0 && req.DomainTopic != "" { responsibilities = append(responsibilities, fmt.Sprintf("专责推演与论证【%s】", req.DomainTopic)) } forbidden := append([]string{}, req.ForbiddenActions...) forbidden = append(forbidden, "严禁违规越权执行未经规划的破坏性命令", "严禁直接代用户做终审拍板") adHocSpec := AgentSpec{ Role: req.RoleKey, Name: name, Source: RoleSourceAdHoc, BaseRole: baseRoleKey, Model: model, Tools: []string{"read", "write", "edit"}, BashPermission: "deny", // 强制只读沙箱安全 Responsibilities: responsibilities, ForbiddenActions: forbidden, InstructionsFile: baseSpec.InstructionsFile, } r.roles[adHocSpec.Role] = adHocSpec return adHocSpec, nil } // FriendlyRoleName 将内部角色代号转换为友好的中文专员称谓 func FriendlyRoleName(role string) string { switch role { case "organizer": return "材料整理专员" case "searcher": return "资料检索专员" case "regulatory": return "法规专员" case "engineer": return "系统工程师" case "market": return "市场情报专员" case "finance": return "商务报价专员" case "writer": return "撰写专员" case "leader": return "审核主管" default: return role + "专员" } }