feat(squad): 增强领域核心模型支持角色来源、自适应步骤与黑板基准假设

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WeiCHEN
2026-09-07 22:19:57 +08:00
co-authored by Cursor
parent 8a2c537445
commit 486fbf1977
2 changed files with 256 additions and 23 deletions
+79 -23
View File
@@ -23,16 +23,27 @@ type WorkspaceMetadata struct {
Metadata map[string]string `json:"metadata,omitempty"`
}
// RoleSource 标识角色来源
type RoleSource string
const (
RoleSourceStandard RoleSource = "standard" // 预设标准化角色 (organizer, searcher, regulatory...)
RoleSourceCustom RoleSource = "custom" // 配置文件声明的业务扩展角色
RoleSourceAdHoc RoleSource = "ad_hoc" // 规划器现场生成的特设专员
)
// AgentSpec 声明单个专员角色在小队中的设定
type AgentSpec struct {
Role string `json:"role"`
Name string `json:"name"`
Model string `json:"model"`
Tools []string `json:"tools"`
BashPermission string `json:"bash_permission"` // allow, deny
Responsibilities []string `json:"responsibilities"`
ForbiddenActions []string `json:"forbidden_actions"`
InstructionsFile string `json:"instructions_file,omitempty"`
Role string `json:"role"`
Name string `json:"name"`
Source RoleSource `json:"source,omitempty"`
BaseRole string `json:"base_role,omitempty"`
Model string `json:"model"`
Tools []string `json:"tools"`
BashPermission string `json:"bash_permission"` // allow, deny
Responsibilities []string `json:"responsibilities"`
ForbiddenActions []string `json:"forbidden_actions"`
InstructionsFile string `json:"instructions_file,omitempty"`
}
// SquadConfig 激活的智能体小队编制
@@ -42,27 +53,40 @@ type SquadConfig struct {
Agents []AgentSpec `json:"agents"`
}
// PlanningMode 规划模式
type PlanningMode string
const (
PlanModeFixedAdaptive PlanningMode = "fixed_adaptive" // 固定文档:基于基线模板,允许动态微调
PlanModeAutonomousAdhoc PlanningMode = "autonomous_adhoc" // 非工作流:全自动动态规划
)
// StepSpec 单个任务步骤规格定义
type StepSpec struct {
ID string `json:"id"`
Role string `json:"role"`
Title string `json:"title"`
SubWorkspace string `json:"sub_workspace"` // 相对子路径,如 tasks/01_organize
Mode string `json:"mode"` // execute, plan, review_plan, replan
Parallel bool `json:"parallel"`
Needs []string `json:"needs,omitempty"`
Accept []string `json:"accept,omitempty"`
Status string `json:"status"` // pending, running, completed, failed, skipped
DurationMs int64 `json:"duration_ms,omitempty"`
Error string `json:"error,omitempty"`
ID string `json:"id"`
Role string `json:"role"`
Title string `json:"title"`
SubWorkspace string `json:"sub_workspace"` // 相对子路径,如 tasks/01_organize
Mode string `json:"mode"` // execute, plan, review_plan, replan
Parallel bool `json:"parallel"`
Needs []string `json:"needs,omitempty"`
Accept []string `json:"accept,omitempty"`
Status string `json:"status"` // pending, running, completed, failed, skipped
DurationMs int64 `json:"duration_ms,omitempty"`
Error string `json:"error,omitempty"`
AllowDynamicAdjustment bool `json:"allow_dynamic_adjustment,omitempty"`
BaselineAssumptions []string `json:"baseline_assumptions,omitempty"`
}
// WorkflowPlan 动态任务编排清单
type WorkflowPlan struct {
WorkflowID string `json:"workflow_id"`
Status string `json:"status"` // pending, in_progress, completed, failed
CurrentStepIndex int `json:"current_step_index"`
Steps []StepSpec `json:"steps"`
WorkflowID string `json:"workflow_id"`
TaskKey string `json:"task_key,omitempty"`
Title string `json:"title,omitempty"`
PlanningMode PlanningMode `json:"planning_mode,omitempty"`
Status string `json:"status"` // pending, in_progress, completed, failed
CurrentStepIndex int `json:"current_step_index"`
Steps []StepSpec `json:"steps"`
}
// ContextItem 上下文项目元数据
@@ -126,15 +150,47 @@ type ImplicationItem struct {
Statement string `json:"statement"`
}
// AssumptionItem 黑板基准假设项(医疗器械工程/法规先验推断)
type AssumptionItem struct {
ID string `json:"id"`
Topic string `json:"topic"`
Statement string `json:"statement"`
Rationale string `json:"rationale"` // 行业先验推导依据
Source string `json:"source"` // 默认 "inferred"
}
// BlackboardState 结构化共享黑板
type BlackboardState struct {
Facts []FactItem `json:"facts"`
Gaps []GapItem `json:"gaps"`
Implications []ImplicationItem `json:"implications"`
Assumptions []AssumptionItem `json:"assumptions,omitempty"`
Fields map[string]string `json:"fields"`
UpdatedAt time.Time `json:"updated_at"`
}
// StepAction 单步评估后的调整决策
type StepAction string
const (
StepActionContinue StepAction = "CONTINUE" // 无异常,正常按既定计划继续
StepActionAddStep StepAction = "ADD_STEP" // 发现关键事实或缺口,动态追加补充步骤
StepActionUpdateStep StepAction = "UPDATE_STEP" // 调整后续步骤的验收标准或指派角色
StepActionSkipStep StepAction = "SKIP_STEP" // 前序步骤已充分覆盖,跳过冗余步骤
)
// EvaluationResult 步骤评估报告
type EvaluationResult struct {
StepID string `json:"step_id"`
Action StepAction `json:"action"`
Reason string `json:"reason"`
NewAssumptions []AssumptionItem `json:"new_assumptions,omitempty"` // 新增的基准假设
ResolvedGaps []string `json:"resolved_gaps,omitempty"`
DynamicStepsToAdd []StepSpec `json:"dynamic_steps_to_add,omitempty"`
DynamicStepsToAlter []StepSpec `json:"dynamic_steps_to_alter,omitempty"`
StepsToSkip []string `json:"steps_to_skip,omitempty"`
}
// QualityReport 自动化质量门禁报告
type QualityReport struct {
Passed bool `json:"passed"`
+177
View File
@@ -0,0 +1,177 @@
package squad
import (
"encoding/json"
"testing"
"time"
)
func TestAgentSpecEnhancements(t *testing.T) {
spec := AgentSpec{
Role: "biocompatibility_expert",
Name: "生物相容性评估专员",
Source: RoleSourceAdHoc,
BaseRole: "engineer",
Model: "MiniMax-M3",
Tools: []string{"read", "write", "edit"},
BashPermission: "deny",
Responsibilities: []string{"生物相容性风险评估"},
ForbiddenActions: []string{"严禁越权发布正式检验报告"},
}
data, err := json.Marshal(spec)
if err != nil {
t.Fatalf("marshal AgentSpec failed: %v", err)
}
var parsed AgentSpec
if err := json.Unmarshal(data, &parsed); err != nil {
t.Fatalf("unmarshal AgentSpec failed: %v", err)
}
if parsed.Source != RoleSourceAdHoc {
t.Errorf("expected source %s, got %s", RoleSourceAdHoc, parsed.Source)
}
if parsed.BaseRole != "engineer" {
t.Errorf("expected base_role engineer, got %s", parsed.BaseRole)
}
}
func TestStepSpecDynamicAdjustment(t *testing.T) {
step := StepSpec{
ID: "step_01_search",
Role: "searcher",
Title: "文献与标准检索",
SubWorkspace: "tasks/01_search",
Mode: "execute",
AllowDynamicAdjustment: true,
}
data, err := json.Marshal(step)
if err != nil {
t.Fatalf("marshal StepSpec failed: %v", err)
}
var parsed StepSpec
if err := json.Unmarshal(data, &parsed); err != nil {
t.Fatalf("unmarshal StepSpec failed: %v", err)
}
if !parsed.AllowDynamicAdjustment {
t.Errorf("expected AllowDynamicAdjustment to be true")
}
}
func TestWorkflowPlanPlanningMode(t *testing.T) {
wf := WorkflowPlan{
WorkflowID: "wf_test_123",
TaskKey: "cleanroom_design",
Title: "洁净厂房设计方案",
PlanningMode: PlanModeAutonomousAdhoc,
Status: "pending",
Steps: []StepSpec{
{
ID: "step_01",
Role: "organizer",
},
},
}
data, err := json.Marshal(wf)
if err != nil {
t.Fatalf("marshal WorkflowPlan failed: %v", err)
}
var parsed WorkflowPlan
if err := json.Unmarshal(data, &parsed); err != nil {
t.Fatalf("unmarshal WorkflowPlan failed: %v", err)
}
if parsed.PlanningMode != PlanModeAutonomousAdhoc {
t.Errorf("expected planning mode %s, got %s", PlanModeAutonomousAdhoc, parsed.PlanningMode)
}
if parsed.TaskKey != "cleanroom_design" {
t.Errorf("expected task_key cleanroom_design, got %s", parsed.TaskKey)
}
}
func TestBlackboardAssumptions(t *testing.T) {
bb := BlackboardState{
Facts: []FactItem{
{ID: "f1", Claim: "产品为无菌二类导管", Verified: true},
},
Assumptions: []AssumptionItem{
{
ID: "a1",
Topic: "sterilization_method",
Statement: "基准假设灭菌方式采用环氧乙烷(EO)灭菌,解析期设定为14天",
Rationale: "客户未明确灭菌方式,依据二类无源无菌高分子导管临床通行工程惯例设定",
Source: "inferred",
},
},
UpdatedAt: time.Now(),
}
data, err := json.Marshal(bb)
if err != nil {
t.Fatalf("marshal BlackboardState failed: %v", err)
}
var parsed BlackboardState
if err := json.Unmarshal(data, &parsed); err != nil {
t.Fatalf("unmarshal BlackboardState failed: %v", err)
}
if len(parsed.Assumptions) != 1 {
t.Fatalf("expected 1 assumption, got %d", len(parsed.Assumptions))
}
if parsed.Assumptions[0].Source != "inferred" {
t.Errorf("expected assumption source 'inferred', got '%s'", parsed.Assumptions[0].Source)
}
}
func TestEvaluationResult(t *testing.T) {
res := EvaluationResult{
StepID: "step_01_search",
Action: StepActionAddStep,
Reason: "检测到产品使用动物源牛心包,需动态追加生物相容性专题调研",
NewAssumptions: []AssumptionItem{
{
ID: "a2",
Topic: "animal_origin",
Statement: "需执行GB/T 16886及ISO 22442动物源医疗器械病毒灭活评价",
Source: "inferred",
},
},
DynamicStepsToAdd: []StepSpec{
{
ID: "step_01_biocompatibility",
Role: "biocompatibility_expert",
Title: "动物源生物相容性与病毒灭活专项评估",
SubWorkspace: "tasks/01_biocompatibility",
Mode: "execute",
},
},
StepsToSkip: []string{"step_02_market"},
}
data, err := json.Marshal(res)
if err != nil {
t.Fatalf("marshal EvaluationResult failed: %v", err)
}
var parsed EvaluationResult
if err := json.Unmarshal(data, &parsed); err != nil {
t.Fatalf("unmarshal EvaluationResult failed: %v", err)
}
if parsed.Action != StepActionAddStep {
t.Errorf("expected action %s, got %s", StepActionAddStep, parsed.Action)
}
if len(parsed.DynamicStepsToAdd) != 1 {
t.Errorf("expected 1 dynamic step to add, got %d", len(parsed.DynamicStepsToAdd))
}
if len(parsed.StepsToSkip) != 1 || parsed.StepsToSkip[0] != "step_02_market" {
t.Errorf("expected steps to skip ['step_02_market'], got %v", parsed.StepsToSkip)
}
}