BossAgents 六大能力增强 — 实现方案文档

BossAgents 六大能力增强 — 实现方案文档

版本:v1.0 | 日期:2026-06-25 | 基于 spec-六大能力增强.md 需求规格


1. 实现模型

1.1 上下文视图

1.1.1 系统上下文

六大能力增强在 BossAgents 整体架构中的定位:

┌─────────────────────────────────────────────────────────────────────┐
│                        外部系统                                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐  │
│  │ 业务用户      │  │ SCSAI Agent│  │ SmartLLMRouter          │  │
│  │ (IM/Web/小程序)│  │ (AML操作)     │  │ (5级降级链路)            │  │
│  └──────┬───────┘  └──────┬───────┘  └───────────┬──────────────┘  │
└─────────┼─────────────────┼──────────────────────┼─────────────────┘
          │                 │                      │
          ▼                 ▼                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     BossAgents 核心层                                │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │              CapabilityDispatcher (统一调度)                   │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │           CapabilityRuntime (六大能力入口) ★ 本次增强核心      │   │
│  │  identify │ create │ repair │ optimize │ compare │ generate   │   │
│  └────────┬─────────┬────────┬─────────┬─────────┬─────────────┘   │
│           │         │        │         │         │                   │
│           ▼         ▼        ▼         ▼         ▼                   │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │        UnifiedRuleEngine (规则引擎核心, 2384行) ★ 主要修改    │   │
│  │  新增: GENERATE/TRANSFORM规则 | 关系差异 | auto_fix |         │   │
│  │        create_post扩展 | identify专用规则                     │   │
│  └────────┬───────────────────────────────────────────────────┘   │
│           │                                                         │
│           ▼                                                         │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │    RelationshipCapability + RelationshipResolver ★ 关系层    │   │
│  │    新增: SCSAI关系查询 | 关系去重 | identify集成               │   │
│  └───────────────────────────────────────────────────────────┘   │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │    AMLGenerator + AMLBuilder ★ AML生成层                     │   │
│  │    新增: Relationships节点输出 (AMLGenerator)                  │   │
│  └───────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

1.1.2 需求与模块映射

| 需求ID | 需求名称 | 主要修改模块 | 优先级 |

|--------|---------|-------------|--------|

| P0-1 | generate能力规则驱动 | rule-engine.js, capability-runtime.js | P0 |

| P0-2 | AMLGenerator Relationships支持 | aml-generator.js | P0 |

| P0-3 | identify关系发现集成 | capability-runtime.js, relationship-capability.js | P0 |

| P1-1 | compare关系层对比 | rule-engine.js | P1 |

| P1-2 | optimize自动执行 | rule-engine.js | P1 |

| P1-3 | repair关系修复 | rule-engine.js | P1 |

| P1-4 | create_post规则扩展 | rule-engine.js | P1 |

| P2-1 | identify内置规则扩展 | rule-engine.js | P2 |

| P2-2 | RelationshipResolver SCSAI关系查询 | relationship-resolver.js | P2 |

1.2 服务/组件总体架构

1.2.1 增强后的能力执行流水线

用户请求 → CapabilityDispatcher.execute()
              │
              ▼
         CapabilityRuntime.{capability}()
              │
              ├─ 1. 规则引擎匹配 (UnifiedRuleEngine)
              │     ├─ GENERATE/TRANSFORM scope (★新增)
              │     ├─ IDENTIFY scope (★扩展专用规则)
              │     ├─ CREATE scope (含 CREATE_PRE/CREATE_POST)
              │     ├─ REPAIR scope (★扩展关系修复)
              │     ├─ OPTIMIZE scope (★扩展auto_fix)
              │     └─ COMPARE scope (★扩展关系差异)
              │
              ├─ 2. 关系感知层 (★新增)
              │     ├─ identifyRelations() — 关系发现
              │     ├─ discoverRelations() — SCSAI关系查询
              │     └─ 关系结果合并/去重
              │
              ├─ 3. AML生成层
              │     ├─ AMLBuilder (已支持Relationships)
              │     └─ AMLGenerator (★新增Relationships支持)
              │
              ├─ 4. SCSAI提交 (applyAML)
              │
              └─ 5. LLM降级 (SmartLLMRouter)

1.2.2 数据流架构

                    ┌─────────────────────┐
                    │  sciot_rules_v2     │ ← 规则定义(含新增GENERATE/TRANSFORM)
                    │  prompt_templates   │ ← 模板定义(generate引用)
                    │  sciot_relationships│ ← 关系元数据
                    └─────────┬───────────┘
                              │
                              ▼
┌──────────┐    ┌──────────────────────────┐    ┌──────────────┐
│ 用户请求  │───▶│  UnifiedRuleEngine       │───▶│ SCSAI Agent│
│          │    │  + 关系感知层             │    │ (AML操作)     │
└──────────┘    └──────────────────────────┘    └──────────────┘
                              │
                    ┌─────────┴───────────┐
                    │  执行结果            │
                    │  - 规则命中/LLM降级   │
                    │  - 关系发现结果       │
                    │  - AML操作结果        │
                    │  - auto_fix执行确认   │
                    └─────────────────────┘

1.3 实现设计文档

1.3.1 P0-1: generate能力规则驱动

#### 需求概述

为 GENERATE 和 TRANSFORM scope 注册内置规则,实现基于模板的规则驱动生成,替代纯LLM降级路径。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | _loadBuiltinRules() 添加 GENERATE/TRANSFORM 内置规则 |

| server/core/capability-runtime.js | 修改 | generate() 方法集成规则引擎,添加 generate_pre/generate_post 生命周期 |

#### 核心类/函数设计

1. rule-engine.js — 新增内置规则

_loadBuiltinRules() 方法末尾添加:

// ===== Generate 生成规则 =====

// 通用: 模板化生成(引用 prompt_templates 表)
rules.push({
  id: 'builtin-generate-001',
  name: '通用: 模板化生成',
  scope: RULE_SCOPES.GENERATE,
  description: '基于 prompt_templates 表的模板化生成',
  condition: JSON.stringify({ type: 'has_template' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P1,
  prompt_template_id: null,  // 运行时从 context.template_id 注入
  action_script: `
    var tpl = context._promptTemplate;
    if (!tpl || !tpl.content) return { generated: false };
    var content = tpl.content;
    var vars = tpl.variables ? (typeof tpl.variables === 'string' ? JSON.parse(tpl.variables) : tpl.variables) : [];
    for (var i = 0; i < vars.length; i++) {
      var v = vars[i];
      var val = context.properties[v] || context.data[v] || '';
      content = content.replace(new RegExp('\\{\\{' + v + '\\}\\}', 'g'), val);
    }
    return { generated: true, content: content, template_id: tpl.id, template_name: tpl.name };
  `,
  is_builtin: 1
});

// 通用: 数据转换(transform scope)
rules.push({
  id: 'builtin-transform-001',
  name: '通用: 数据格式转换',
  scope: RULE_SCOPES.TRANSFORM,
  description: '将输入数据转换为指定格式',
  condition: JSON.stringify({ type: 'has_transform_target' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P1,
  action_script: `
    var src = context.properties || context.data || {};
    var target = context.transform_target || 'json';
    if (target === 'aml') {
      var aml = '<AML><Item type="' + (context.item_type || 'Part') + '" action="add">';
      for (var k in src) {
        if (src[k] !== null && src[k] !== undefined && typeof src[k] !== 'object') {
          aml += '<' + k + '>' + String(src[k]) + '</' + k + '>';
        }
      }
      aml += '</Item></AML>';
      return { transformed: true, content: aml, format: 'aml' };
    }
    return { transformed: true, content: JSON.stringify(src, null, 2), format: 'json' };
  `,
  is_builtin: 1
});

// ECO 专用生成规则
rules.push({
  id: 'builtin-generate-eco-001',
  name: 'ECO: 工程变更单生成',
  scope: RULE_SCOPES.GENERATE,
  item_type_name: 'ECO',
  description: '生成ECO工程变更单结构化模板',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'ECO' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    var eco = {
      item_type: 'ECO',
      title: p.title || p.name || '工程变更单',
      description: p.description || '',
      change_reason: p.change_reason || '待填写',
      affected_items: p.affected_items || [],
      priority: p.priority || 'Medium',
      change_type: p.change_type || 'Engineering'
    };
    return { generated: true, content: JSON.stringify(eco, null, 2), template: 'eco_standard' };
  `,
  is_builtin: 1
});

// BOM 专用生成规则
rules.push({
  id: 'builtin-generate-bom-001',
  name: 'BOM: 物料清单生成',
  scope: RULE_SCOPES.GENERATE,
  item_type_name: 'BOM',
  description: '生成BOM物料清单结构化模板',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'BOM' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    var bom = {
      item_type: 'BOM',
      bom_number: p.bom_number || 'BOM-' + Date.now(),
      product_name: p.product_name || p.name || '待填写',
      version: p.version || '1.0',
      components: p.components || [],
      total_cost: p.total_cost || 0
    };
    return { generated: true, content: JSON.stringify(bom, null, 2), template: 'bom_standard' };
  `,
  is_builtin: 1
});

// Document 专用生成规则
rules.push({
  id: 'builtin-generate-document-001',
  name: 'Document: 文档生成',
  scope: RULE_SCOPES.GENERATE,
  item_type_name: 'Document',
  description: '生成文档结构化模板',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Document' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    var doc = {
      item_type: 'Document',
      title: p.title || p.name || '新文档',
      document_type: p.document_type || 'Specification',
      classification: p.classification || 'General',
      content: p.content || '',
      author: p.author || 'SYSTEM'
    };
    return { generated: true, content: JSON.stringify(doc, null, 2), template: 'document_standard' };
  `,
  is_builtin: 1
});

2. rule-engine.js — 新增 executeGenerate() 方法

/**
 * executeGenerate — 生成能力(规则驱动 + 模板化)
 * @param {Object} context - { item_type, data, template_id }
 * @param {Object} options - { SCSAIClient, llmClient }
 * @returns {Object} { executed, scope, item_type, generated_content, source, elapsed }
 */
async executeGenerate(context, options = {}) {
  const startTime = Date.now();
  const { item_type, data, template_id } = context;

  // 1. 如果指定了 template_id,加载 prompt_templates
  if (template_id && this.db) {
    try {
      const tpl = this.db.prepare('SELECT * FROM prompt_templates WHERE id = ? AND status = ?').get(template_id, 'active');
      if (tpl) {
        context._promptTemplate = tpl;
      }
    } catch (e) {
      this.logger.warn('[executeGenerate] 模板加载失败:', e.message);
    }
  }

  // 2. 如果未指定 template_id 但有 item_type,尝试加载默认模板
  if (!context._promptTemplate && item_type && this.db) {
    try {
      const tpl = this.db.prepare(
        'SELECT * FROM prompt_templates WHERE item_type_name = ? AND prompt_type = ? AND status = ? ORDER BY score DESC LIMIT 1'
      ).get(item_type, 'creation', 'active');
      if (tpl) {
        context._promptTemplate = tpl;
      }
    } catch (e) { /* 无默认模板,继续 */ }
  }

  // 3. 匹配 GENERATE scope 规则
  const generateRules = await this.getRules({ scope: RULE_SCOPES.GENERATE, item_type });
  const generateResults = [];

  for (const rule of generateRules) {
    if (await this._evaluateCondition(rule, context)) {
      const result = await this._executeAction(rule, context, options);
      if (result.generated || result.suggested) {
        generateResults.push({
          rule: rule.name,
          rule_id: rule.id,
          result,
          template_id: rule.prompt_template_id || context._promptTemplate?.id,
          priority: rule.priority
        });
      }
    }
  }

  // 4. 如果 GENERATE 未命中,尝试 TRANSFORM scope
  if (generateResults.length === 0) {
    const transformRules = await this.getRules({ scope: RULE_SCOPES.TRANSFORM, item_type });
    for (const rule of transformRules) {
      if (await this._evaluateCondition(rule, context)) {
        const result = await this._executeAction(rule, context, options);
        if (result.transformed || result.suggested) {
          generateResults.push({
            rule: rule.name,
            rule_id: rule.id,
            result,
            scope: 'transform',
            priority: rule.priority
          });
        }
      }
    }
  }

  generateResults.sort((a, b) => a.priority - b.priority);

  return {
    executed: generateResults.length > 0,
    scope: RULE_SCOPES.GENERATE,
    item_type,
    generated_content: generateResults.length > 0 ? generateResults[0].result.content : null,
    results: generateResults,
    elapsed: Date.now() - startTime
  };
}

3. capability-runtime.js — 增强 generate() 方法

/**
 * 内容生成 — 规则驱动 + LLM降级
 * 流程:executeGenerate → (未命中) → LLM Router
 */
async generate(context, options = {}) {
  const { item_type, data, template_id } = context;
  const engine = await this._initRuleEngine();
  const startTime = Date.now();

  // 1. 规则引擎 GENERATE/TRANSFORM
  if (engine) {
    const result = await engine.executeGenerate(
      { item_type, data, template_id },
      this._buildEngineOptions()
    );
    if (result.executed && result.results.length > 0) {
      this._recordRuleEngineHit();
      return this._formatResult('generate', result, {
        source: 'rule_engine',
        durationMs: Date.now() - startTime
      });
    }
  }

  // 2. 降级:LLM Router(生成任务走 Solver 云端大模型)
  const systemPrompt = this._defaultPrompt(item_type, 'generate');
  const llmResult = await this._callLLMViaRouter({
    prompt: JSON.stringify(data),
    systemPrompt,
    taskType: 'generate',
    capability: 'generate',
    context: { item_type, data },
  });
  if (llmResult) {
    return this._formatResult('generate', llmResult, {
      source: 'llm_router',
      durationMs: Date.now() - startTime
    });
  }

  return { capability: 'generate', success: false, error: '规则引擎和 LLM 均不可用' };
}

#### 数据模型

prompt_templates 表(已存在,无需新建):

| 字段 | 类型 | 说明 |

|------|------|------|

| id | TEXT PK | 模板ID |

| name | TEXT | 模板名称 |

| content | TEXT | 模板内容(含 {{变量}} 占位符) |

| variables | TEXT | JSON数组,模板变量列表 |

| prompt_type | TEXT | 模板类型(creation/transformation/analysis) |

| item_type_name | TEXT | 关联ItemType |

| status | TEXT | 状态(active/inactive) |

sciot_rules_v2 表(已存在,新增 GENERATE/TRANSFORM scope 规则):

| 新增规则ID | scope | item_type_name | 说明 |

|------------|-------|----------------|------|

| builtin-generate-001 | generate | null | 通用模板化生成 |

| builtin-transform-001 | transform | null | 通用数据格式转换 |

| builtin-generate-eco-001 | generate | ECO | ECO专用生成 |

| builtin-generate-bom-001 | generate | BOM | BOM专用生成 |

| builtin-generate-document-001 | generate | Document | Document专用生成 |

#### 依赖关系

  • 依赖 prompt_templates 表(已存在)
  • 依赖 sciot_rules_v2 表(已存在)
  • 依赖 _loadBuiltinRules() 注册机制(已存在)
  • 依赖 _executeAction() 脚本执行沙箱(已存在)

#### 技术选型及理由

  • 内置规则 vs 数据库规则:generate/transform 规则优先使用内置规则(硬编码),保证基础可用性;复杂ItemType的生成规则通过数据库配置,支持热更新
  • 模板变量替换:使用正则 {{var}} 模式,简单可靠,与现有 prompt_templates 表的 variables 字段配合
  • GENERATE → TRANSFORM 降级链:先尝试 GENERATE scope,未命中再尝试 TRANSFORM scope,符合业务语义

1.3.2 P0-2: AMLGenerator Relationships 支持

#### 需求概述

AMLGenerator._buildAML() 方法当前不支持 Relationships 节点输出,需要与 AMLBuilder 保持一致的嵌套结构。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/aml-generator.js | 修改 | _buildAML() 方法添加 Relationships 节点输出 |

#### 核心类/函数设计

1. aml-generator.js — 修改 _buildAML() 方法

当前 _buildAML() 方法(第347-384行)仅输出属性XML,需在 前插入 Relationships 节点:

/**
 * 生成 AML XML(★增强:支持 Relationships 节点)
 *
 * 关键规则:
 * - item/foreign 类型字段:直接输出 GUID,不加 CDATA,不加 type 属性
 * - 普通字段:用 CDATA 包裹,防止特殊字符
 * - list 类型字段:直接输出值,不加 CDATA
 * - date/integer/float 类型:直接输出值
 * - ★ relationships 字段:输出 <Relationships> 节点(与 AMLBuilder 保持一致)
 */
_buildAML(data, schema, options) {
    const { itemType } = schema;
    const action = options.action || 'add';
    const { properties } = schema;

    // 构建属性 XML
    const propertiesXml = Object.entries(data)
        .filter(([key, value]) => value !== undefined && value !== null && key !== 'relationships' && key !== '_relationships')
        .map(([key, value]) => {
            const prop = properties[key];
            const dataType = prop?.type || 'string';

            // item/foreign 类型:直接输出 GUID,不加 CDATA
            if (dataType === 'item' || dataType === 'foreign') {
                return `    <${key}>${String(value)}</${key}>`;
            }

            // list / date / integer / float / boolean:直接输出值
            if (['list', 'color list', 'date', 'integer', 'float', 'decimal', 'number', 'boolean'].includes(dataType)) {
                return `    <${key}>${this._escapeXml(String(value))}</${key}>`;
            }

            // 文本类型:用 CDATA 包裹
            const escaped = this._escapeXml(String(value));
            return `    <${key}><![CDATA[${escaped}]]></${key}>`;
        })
        .join('\n');

    // ★ 构建 Relationships XML(与 AMLBuilder.buildRelationshipElement 保持一致)
    let relationshipsXml = '';
    const relationships = data.relationships || data._relationships || [];
    if (Array.isArray(relationships) && relationships.length > 0) {
        relationshipsXml = this._buildRelationshipsXml(relationships);
    }

    // 构建完整 AML(action=add 时不传 id,让 SCSAI 自动生成)
    const idAttr = (action !== 'add' && data.id) ? ` id="${data.id}"` : '';
    const aml = `<AML>
  <Item type="${itemType}" action="${action}"${idAttr}>
${propertiesXml}${relationshipsXml}
  </Item>
</AML>`;

    return aml;
}

/**
 * ★ 新增:构建 Relationships XML
 * 与 AMLBuilder.buildRelationshipElement() 保持一致的嵌套结构
 *
 * 支持三种关系格式:
 * 1. 标准 AMLBuilder 格式:{ relationship_type, related_item_type, related_items }
 * 2. 简化格式:{ type, action, related_id, properties }
 * 3. 嵌套创建格式:{ type, action, related_id: { item_type, properties } }
 */
_buildRelationshipsXml(relationships) {
    let relsXml = '';

    for (const rel of relationships) {
        // 格式1:AMLBuilder 标准格式
        if (rel.relationship_type && rel.related_item_type) {
            relsXml += this._buildAmlBuilderStyleRelation(rel);
            continue;
        }

        // 格式2/3:简化格式
        if (rel.type && rel.action) {
            relsXml += this._buildSimpleStyleRelation(rel);
            continue;
        }

        // 缺少必要字段,跳过并记录 WARNING
        console.warn('[AMLGenerator] 跳过无效关系项:缺少 type 或 action 字段');
    }

    if (relsXml) {
        return '\n    <Relationships>' + relsXml + '\n    </Relationships>';
    }
    return '';
}

/**
 * ★ 新增:构建 AMLBuilder 风格的关系 XML
 * 与 AMLBuilder.buildRelationshipElement() 逻辑一致
 */
_buildAmlBuilderStyleRelation(rel) {
    const { relationship_type, related_item_type, related_items = [] } = rel;
    if (!relationship_type || !related_item_type) return '';

    const referenceOnlyTypes = ['Identity', 'User', 'Group', 'Team'];
    let xml = '';

    for (const item of related_items) {
        xml += `\n      <Item type="${this._escapeXml(relationship_type)}" action="add">`;
        xml += '\n        <related_id>';

        if (item.properties) {
            // 仅引用类型
            if (referenceOnlyTypes.includes(related_item_type)) {
                const queryName = item.properties.name || item.properties.keyed_name || '';
                if (queryName) {
                    xml += `<Item type="${this._escapeXml(related_item_type)}" action="get"><name>${this._escapeXml(queryName)}</name></Item>`;
                } else if (item.id) {
                    xml += `<Item type="${this._escapeXml(related_item_type)}" id="${this._escapeXml(item.id)}" action="get"/>`;
                }
            } else {
                // 嵌套创建
                xml += `<Item type="${this._escapeXml(related_item_type)}" action="add">`;
                for (const [k, v] of Object.entries(item.properties)) {
                    if (v !== null && v !== undefined && typeof v !== 'object') {
                        xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
                    }
                }
                xml += '</Item>';
            }
        } else if (item.id) {
            // 引用已有对象
            xml += `<Item type="${this._escapeXml(related_item_type)}" id="${this._escapeXml(item.id)}" action="get"/>`;
        } else if (item.item_number) {
            xml += `<Item type="${this._escapeXml(related_item_type)}" action="get"><item_number>${this._escapeXml(item.item_number)}</item_number></Item>`;
        }

        xml += '</related_id>';

        // 关系级别附加属性
        if (item.relItemProps) {
            for (const [pn, pd] of Object.entries(item.relItemProps)) {
                if (pd && pd.item_type && pd.action) {
                    xml += `<${pn}><Item type="${this._escapeXml(pd.item_type)}" action="${this._escapeXml(pd.action)}">`;
                    if (pd.properties) {
                        for (const [k, v] of Object.entries(pd.properties)) {
                            if (v !== null && v !== undefined && typeof v !== 'object') {
                                xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
                            }
                        }
                    }
                    xml += '</Item></${pn}>';
                }
            }
        }

        xml += '\n      </Item>';
    }

    return xml;
}

/**
 * ★ 新增:构建简化风格的关系 XML
 * 格式:{ type, action, related_id, properties }
 */
_buildSimpleStyleRelation(rel) {
    const { type, action, related_id, properties = {} } = rel;
    let xml = `\n      <Item type="${this._escapeXml(type)}" action="${this._escapeXml(action)}">`;

    // related_id 处理
    if (related_id) {
        if (typeof related_id === 'object' && related_id.item_type) {
            // 嵌套创建
            xml += '<related_id>';
            xml += `<Item type="${this._escapeXml(related_id.item_type)}" action="add">`;
            if (related_id.properties) {
                for (const [k, v] of Object.entries(related_id.properties)) {
                    if (v !== null && v !== undefined && typeof v !== 'object') {
                        xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
                    }
                }
            }
            xml += '</Item></related_id>';
        } else {
            // GUID 引用
            xml += `<related_id>${this._escapeXml(String(related_id))}</related_id>`;
        }
    }

    // 关系属性
    for (const [k, v] of Object.entries(properties)) {
        if (v !== null && v !== undefined && typeof v !== 'object') {
            xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
        }
    }

    xml += '\n      </Item>';
    return xml;
}

#### 数据模型

无需新增数据表,Relationships 数据通过 data.relationshipsdata._relationships 字段传入。

输入 JSON 格式

{
  "item_type": "Part",
  "action": "add",
  "properties": { "item_number": "P-001", "name": "零件A" },
  "relationships": [
    {
      "relationship_type": "Part BOM",
      "related_item_type": "Part",
      "related_items": [
        { "properties": { "item_number": "P-002", "name": "子零件B" } }
      ]
    }
  ]
}

#### 依赖关系

  • 依赖 AMLBuilder 的 buildRelationshipElement() 逻辑(作为参考,保持一致性)
  • 依赖 _escapeXml() 方法(已存在)
  • capability-runtime.jscreate() 降级路径调用

#### 技术选型及理由

  • 复用 AMLBuilder 逻辑而非直接调用:AMLGenerator 是端到端流程(Schema→验证→AML),直接调用 AMLBuilder 会破坏其内部状态管理;将关系构建逻辑内联,但与 AMLBuilder 保持一致的输出格式
  • 支持两种关系格式:AMLBuilder 标准格式(前端已测试)+ 简化格式(后端LLM降级路径常用),兼容性最大化
  • 过滤 _relationshipsrelationships 字段:避免关系数据被当作普通属性输出到 AML

1.3.3 P0-3: identify 关系发现集成

#### 需求概述

CapabilityRuntime.identify() 在识别查询时集成 RelationshipCapability.identifyRelations(),返回关联对象信息。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/capability-runtime.js | 修改 | identify() 方法添加关系发现调用 |

#### 核心类/函数设计

1. capability-runtime.js — 增强 identify() 方法

/**
 * 识别/查询 — 适用于数据检索、对象识别
 * ★ 增强:集成关系发现,返回 related_objects
 */
async identify(context, options = {}) {
  const { item_type, query_type = 'list', filters = {} } = context;
  const engine = await this._initRuleEngine();
  const startTime = Date.now();
  const includeRelations = options.includeRelations !== false; // 默认开启

  let identifyResult = null;

  // 1. 规则引擎识别
  if (engine) {
    const result = await engine.executeIdentify(
      { item_type, query_type, filters, ...context },
      this._buildEngineOptions()
    );
    if (result.executed !== false) {
      this._recordRuleEngineHit();
      identifyResult = this._formatResult('identify', result, {
        source: 'rule_engine',
        durationMs: Date.now() - startTime
      });
    }
  }

  // 2. 降级:LLM Router
  if (!identifyResult) {
    const systemPrompt = this._defaultPrompt(item_type, 'identify');
    const llmResult = await this._callLLMViaRouter({
      prompt: JSON.stringify(filters),
      systemPrompt,
      taskType: 'identify',
      capability: 'identify',
      context: { item_type, query_type, filters },
    });
    if (llmResult) {
      identifyResult = this._formatResult('identify', llmResult, {
        source: 'llm_router',
        durationMs: Date.now() - startTime
      });
    }
  }

  if (!identifyResult) {
    return { capability: 'identify', success: false, error: '规则引擎和 LLM 均不可用' };
  }

  // ★ 3. 关系发现集成(非阻塞,超时2秒)
  if (includeRelations && item_type) {
    identifyResult.related_objects = [];
    identifyResult.has_more = false;

    try {
      const relCap = this._getRelationshipCapability();
      if (relCap) {
        // 获取查询结果中的对象数据
        const items = identifyResult.result?.query_result?.items
          || identifyResult.result?.items
          || [];
        const itemData = items.length > 0 ? items[0] : (filters || {});

        const relationPromise = relCap.identifyRelations(item_type, itemData);
        const timeoutPromise = new Promise((_, reject) =>
          setTimeout(() => reject(new Error('关系发现超时')), 2000)
        );

        const relations = await Promise.race([relationPromise, timeoutPromise]);

        if (Array.isArray(relations) && relations.length > 0) {
          // 截取前20个,超过标记 has_more
          const maxRelations = 20;
          identifyResult.related_objects = relations.slice(0, maxRelations).map(r => ({
            relationship_type: r.relation_name || r.relation_label || '',
            related_item: {
              type: r.target_type || '',
              hint: r.target_hint || '',
            },
            direction: r.behavior || 'outgoing',
            confidence: r.confidence || 0,
            method: r.method || 'unknown',
          }));
          identifyResult.has_more = relations.length > maxRelations;
        }
      }
    } catch (e) {
      // 关系发现失败不影响主查询
      this._log('identify', item_type, '关系发现失败(非阻塞)', e.message);
      identifyResult.source = identifyResult.source === 'llm_router'
        ? 'llm_router' : 'rule_engine_only';
    }
  }

  return identifyResult;
}

/**
 * ★ 新增:获取 RelationshipCapability 实例(懒加载)
 */
_getRelationshipCapability() {
  try {
    const { getRelationshipCapability } = require('./relationship-capability');
    return getRelationshipCapability();
  } catch (e) {
    this._log('identify', '*', 'RelationshipCapability不可用', e.message);
    return null;
  }
}

#### 数据模型

identify 返回结果(含关系信息)

{
  "capability": "identify",
  "success": true,
  "source": "rule_engine",
  "result": { "query_result": { "items": [...] } },
  "related_objects": [
    {
      "relationship_type": "Part BOM",
      "related_item": { "type": "Part", "hint": "P-001" },
      "direction": "outgoing",
      "confidence": 0.9,
      "method": "rule_engine"
    }
  ],
  "has_more": false
}

#### 依赖关系

  • 依赖 RelationshipCapability.identifyRelations()(已存在)
  • 依赖 _getRelationshipCapability() 懒加载模式(新增,与 _getRelationshipResolver() 模式一致)
  • 不修改 RelationshipCapability 本身

#### 技术选型及理由

  • Promise.race 超时控制:2秒超时限制,避免关系发现阻塞主查询,符合spec中"增量不超过500ms"的性能约束(实际2秒为上限,正常路径应在500ms内完成)
  • 默认开启、可选关闭includeRelations 默认 true,调用方可传 false 跳过关系发现
  • 非阻塞设计:关系发现失败不影响主查询结果返回,related_objects 为空数组

1.3.4 P1-1: compare 关系层对比

#### 需求概述

RuleEngine._computeFieldDiffs() 支持 Relationships 节点的差异对比,输出关系增/删/改。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | _computeFieldDiffs() 添加关系差异;新增 _computeRelationDiffs() |

#### 核心类/函数设计

1. rule-engine.js — 增强 executeCompare() 方法

executeCompare() 方法(第1961行)中,在 _computeFieldDiffs 调用后添加关系差异计算:

async executeCompare(context, options = {}) {
    const startTime = Date.now();
    const { item_type, mode = 'version', item_a, item_b, compare_mappings = [] } = context;
    let dataA, dataB;
    if (mode === 'version') {
      dataA = await this._querySingle(item_type, item_a.id, options);
      dataB = await this._querySingle(item_type, item_b.id, options);
    }
    else if (mode === 'object') {
      dataA = await this._querySingle(item_a.type || item_type, item_a.id, options);
      dataB = await this._querySingle(item_b.type || item_type, item_b.id, options);
    }
    else { dataA = item_a.data || {}; dataB = item_b.data || {}; }

    // 属性差异
    const fieldDiffs = this._computeFieldDiffs(dataA.item || dataA, dataB.item || dataB);

    // ★ 关系差异
    const relationDiffs = this._computeRelationDiffs(
      dataA.item?.Relationships || dataA.Relationships || {},
      dataB.item?.Relationships || dataB.Relationships || {}
    );

    // 合并属性差异和关系差异
    const allDiffs = [...fieldDiffs, ...relationDiffs];

    // ... 后续规则匹配和影响分析逻辑不变,使用 allDiffs 替代 fieldDiffs ...

    const compareRules = await this.getRules({ scope: RULE_SCOPES.COMPARE, item_type });
    const compareResults = [];
    for (const rule of compareRules) {
      if (await this._evaluateCondition(rule, { ...context, data_a: dataA, data_b: dataB })) {
        const compareResult = await this._executeAction(rule, { ...context, data_a: dataA, data_b: dataB }, options);
        compareResults.push({ rule: rule.name, result: compareResult });
      }
    }

    let impactAnalysis = null;
    if (options.llmClient && allDiffs.length > 0) {
      impactAnalysis = await this._generateImpactAnalysis(allDiffs, context, options.llmClient);
    }

    return {
      executed: true, scope: RULE_SCOPES.COMPARE, item_type, mode,
      item_a: { id: item_a.id, label: item_a.label },
      item_b: { id: item_b.id, label: item_b.label },
      summary: {
        total_changes: allDiffs.length,
        added: allDiffs.filter(d => d.change_type === 'added').length,
        removed: allDiffs.filter(d => d.change_type === 'removed').length,
        modified: allDiffs.filter(d => d.change_type === 'modified').length,
        relation_added: allDiffs.filter(d => d.change_type === 'relation_added').length,
        relation_removed: allDiffs.filter(d => d.change_type === 'relation_removed').length,
        relation_modified: allDiffs.filter(d => d.change_type === 'relation_modified').length,
      },
      field_diffs: allDiffs,
      compare_results: compareResults,
      impact_analysis: impactAnalysis,
      elapsed: Date.now() - startTime
    };
}

2. rule-engine.js — 新增 _computeRelationDiffs() 方法

/**
 * ★ 新增:计算 Relationships 差异
 * @param {Object} relsA - 对象A的 Relationships(SCSAI 返回格式)
 * @param {Object} relsB - 对象B的 Relationships(SCSAI 返回格式)
 * @returns {Array} 关系差异数组
 *
 * SCSAI 返回的 Relationships 格式:
 * { Item: [{ type: "Part BOM", id: "xxx", related_id: { Item: {...} }, ... }] }
 * 或 { Item: { type: "Part BOM", ... } }(单个关系)
 */
_computeRelationDiffs(relsA, relsB) {
    const diffs = [];

    // 解析关系列表
    const parseRelItems = (rels) => {
      if (!rels || !rels.Item) return [];
      return Array.isArray(rels.Item) ? rels.Item : [rels.Item];
    };

    const itemsA = parseRelItems(relsA);
    const itemsB = parseRelItems(relsB);

    // 构建索引:type + related_id → item
    const buildIndex = (items) => {
      const index = new Map();
      for (const item of items) {
        const relType = item['@_type'] || item.type || '';
        const relatedId = item.related_id?.Item?.id
          || item.related_id?.['@_id']
          || (typeof item.related_id === 'string' ? item.related_id : '')
          || item.related_id?.id || '';
        const key = `${relType}|${relatedId}`;
        index.set(key, { relType, relatedId, item });
      }
      return index;
    };

    const indexA = buildIndex(itemsA);
    const indexB = buildIndex(itemsB);

    // 检测新增关系
    for (const [key, val] of indexB) {
      if (!indexA.has(key)) {
        diffs.push({
          change_type: 'relation_added',
          relationship_type: val.relType,
          related_item_type: val.item.related_id?.Item?.['@_type'] || val.item.related_id?.Item?.type || '',
          related_item_id: val.relatedId,
          value_a: null,
          value_b: val.item,
        });
      }
    }

    // 检测删除关系
    for (const [key, val] of indexA) {
      if (!indexB.has(key)) {
        diffs.push({
          change_type: 'relation_removed',
          relationship_type: val.relType,
          related_item_type: val.item.related_id?.Item?.['@_type'] || val.item.related_id?.Item?.type || '',
          related_item_id: val.relatedId,
          value_a: val.item,
          value_b: null,
        });
      }
    }

    // 检测修改关系(同一 key 但属性不同)
    for (const [key, valA] of indexA) {
      const valB = indexB.get(key);
      if (valB) {
        const propDiffs = this._computeFieldDiffs(
          this._flattenRelItem(valA.item),
          this._flattenRelItem(valB.item)
        );
        if (propDiffs.length > 0) {
          diffs.push({
            change_type: 'relation_modified',
            relationship_type: valA.relType,
            related_item_type: valA.item.related_id?.Item?.['@_type'] || '',
            related_item_id: valA.relatedId,
            value_a: valA.item,
            value_b: valB.item,
            property_diffs: propDiffs,
          });
        }
      }
    }

    return diffs;
}

/**
 * ★ 新增:展平关系项属性(用于属性级差异对比)
 */
_flattenRelItem(item) {
    const flat = {};
    for (const [k, v] of Object.entries(item)) {
      if (k === 'related_id' || k === 'Relationships' || k === '@_type' || k === 'type') continue;
      if (typeof v !== 'object') flat[k] = v;
      else if (v._text) flat[k] = v._text;
    }
    return flat;
}

#### 数据模型

compare 返回结果(含关系差异)

{
  "field_diffs": [
    { "field": "name", "value_a": "旧名称", "value_b": "新名称", "change_type": "modified" },
    {
      "change_type": "relation_added",
      "relationship_type": "Part BOM",
      "related_item_type": "Part",
      "related_item_id": "ABC123",
      "value_a": null,
      "value_b": { "type": "Part BOM", "related_id": { "Item": { "id": "ABC123" } } }
    },
    {
      "change_type": "relation_removed",
      "relationship_type": "Part BOM",
      "related_item_type": "Part",
      "related_item_id": "DEF456",
      "value_a": { "type": "Part BOM", "related_id": { "Item": { "id": "DEF456" } } },
      "value_b": null
    },
    {
      "change_type": "relation_modified",
      "relationship_type": "Part BOM",
      "related_item_type": "Part",
      "related_item_id": "GHI789",
      "property_diffs": [{ "field": "quantity", "value_a": "5", "value_b": "10", "change_type": "modified" }]
    }
  ],
  "summary": {
    "total_changes": 4,
    "added": 1, "removed": 0, "modified": 1,
    "relation_added": 1, "relation_removed": 1, "relation_modified": 1
  }
}

#### 依赖关系

  • 依赖 _computeFieldDiffs() 方法(已存在,复用于关系属性差异)
  • 依赖 SCSAI 返回的 Relationships 数据结构
  • 不依赖新模块

#### 技术选型及理由

  • Map 索引去重:使用 type|related_id 作为唯一键,O(n) 时间复杂度
  • 兼容 SCSAI 多种返回格式rels.Item 可能是数组或单个对象,统一处理
  • _flattenRelItem 展平:将嵌套的 SCSAI 关系项展平为扁平属性,复用 _computeFieldDiffs 进行属性级对比

1.3.5 P1-2: optimize 自动执行

#### 需求概述

支持 action_type: 'auto_fix' 的优化规则,优化结果自动提交 SCSAI,包含前置校验和失败回滚。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | executeOptimize() 添加 auto_fix 执行逻辑 |

#### 核心类/函数设计

1. rule-engine.js — 增强 executeOptimize() 方法

/**
 * executeOptimize — 优化能力(★增强:支持 auto_fix 自动执行)
 * @param {Object} context - { item_type, item_id, data }
 * @param {Object} options - { SCSAIClient, llmClient }
 * @returns {Object} { executed, scope, item_type, item_id, optimizations, elapsed }
 */
async executeOptimize(context, options = {}) {
    const startTime = Date.now();
    const { item_type, item_id, data } = context;
    const optimizeRules = await this.getRules({ scope: RULE_SCOPES.OPTIMIZE, item_type });
    const optimizations = [];

    // 受保护字段列表(auto_fix 不允许修改)
    const PROTECTED_FIELDS = ['id', 'config_id', 'created_by_id', 'created_on', 'modified_by_id', 'modified_on', 'lock_state'];

    for (const rule of optimizeRules) {
      if (await this._evaluateCondition(rule, context)) {
        const optimizeResult = await this._executeAction(rule, context, options);

        if (optimizeResult.suggested || optimizeResult.fixed) {
          const optimization = {
            rule: rule.name,
            rule_id: rule.id,
            suggestion: optimizeResult.suggestion || '',
            priority: rule.priority,
            action_type: rule.action_type,
          };

          // ★ auto_fix 类型:自动执行优化
          if (rule.action_type === 'auto_fix' && optimizeResult.changes && options.SCSAIClient) {
            const autoFixResult = await this._executeOptimizeAction(
              item_type, item_id, optimizeResult.changes, options, PROTECTED_FIELDS
            );
            optimization.auto_applied = autoFixResult.auto_applied;
            optimization.item_id = autoFixResult.item_id;
            optimization.error = autoFixResult.error;
          } else {
            optimization.auto_apply = optimizeResult.auto_apply || false;
          }

          optimizations.push(optimization);
        }
      }
    }

    optimizations.sort((a, b) => a.priority - b.priority);
    return {
      executed: true,
      scope: RULE_SCOPES.OPTIMIZE,
      item_type,
      item_id,
      optimizations_found: optimizations.length,
      optimizations,
      elapsed: Date.now() - startTime
    };
}

/**
 * ★ 新增:执行 auto_fix 优化动作
 * @param {string} itemType - 对象类型
 * @param {string} itemId - 对象ID
 * @param {Object} changes - 变更字段 { field: newValue }
 * @param {Object} options - { SCSAIClient }
 * @param {string[]} protectedFields - 受保护字段列表
 * @returns {Object} { auto_applied, item_id, error }
 */
async _executeOptimizeAction(itemType, itemId, changes, options, protectedFields) {
    // 1. 前置校验:检查受保护字段
    const protectedChanges = Object.keys(changes).filter(k => protectedFields.includes(k));
    if (protectedChanges.length > 0) {
      this.logger.warn('[executeOptimizeAction] 涉及受保护字段,降级为 suggest:', protectedChanges.join(', '));
      return {
        auto_applied: false,
        error: `涉及受保护字段(${protectedChanges.join(', ')}), 需人工确认`,
        original_changes: changes,
      };
    }

    // 2. 构建 AML 并提交
    try {
      const aml = this._buildRepairAML(itemType, itemId, changes);
      const result = await options.SCSAIClient.applyAML(aml);

      // 3. 提取结果
      const returnedId = result?.Item?.id
        || (result?.items && result.items[0]?.id)
        || result?.id
        || itemId;

      if (result && !result.fault) {
        // 记录审计日志
        this.logger.info('[executeOptimizeAction] auto_fix 成功:', itemType, returnedId);
        return { auto_applied: true, item_id: returnedId };
      }

      // SCSAI 返回错误
      const errorMsg = result?.fault?.string || 'SCSAI 操作失败';
      this.logger.error('[executeOptimizeAction] SCSAI 错误:', errorMsg);
      return { auto_applied: false, error: errorMsg, original_changes: changes };

    } catch (e) {
      this.logger.error('[executeOptimizeAction] 异常:', e.message);
      return { auto_applied: false, error: e.message, original_changes: changes };
    }
}

#### 数据模型

optimize 返回结果(含 auto_fix)

{
  "executed": true,
  "scope": "optimize",
  "item_type": "Part",
  "item_id": "ABC123",
  "optimizations": [
    {
      "rule": "数据标准化",
      "rule_id": "builtin-optimize-001",
      "suggestion": "已标准化数据格式",
      "priority": 2,
      "action_type": "suggest",
      "auto_apply": false
    },
    {
      "rule": "库存周转率优化",
      "rule_id": "builtin-optimize-004",
      "suggestion": "周转率低于2,建议优化采购策略",
      "priority": 2,
      "action_type": "auto_fix",
      "auto_applied": true,
      "item_id": "ABC123"
    }
  ]
}

#### 依赖关系

  • 依赖 _buildRepairAML() 方法(已存在,用于构建 edit AML)
  • 依赖 options.SCSAIClient.applyAML() 方法(已存在)
  • 依赖 _executeAction() 脚本执行沙箱(已存在)

#### 技术选型及理由

  • 受保护字段白名单:硬编码 PROTECTED_FIELDS 列表,防止 auto_fix 修改不可变字段
  • suggest 与 auto_fix 共存:同一 scope 下两种 action_type 按优先级依次执行,互不干扰
  • 降级为 suggest:auto_fix 前置校验失败时降级为 suggest,返回原始变更建议供人工确认

1.3.6 P1-3: repair 关系修复

#### 需求概述

RuleEngine._buildRepairAML() 支持在修复 AML 中包含 Relationships 节点,支持同时创建/修改/删除关系。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | _buildRepairAML() 添加 Relationships 支持 |

#### 核心类/函数设计

1. rule-engine.js — 增强 _buildRepairAML() 方法

当前 _buildRepairAML() 方法(第2015行)仅输出属性XML,需扩展支持 Relationships:

/**
 * 构建修复 AML(★增强:支持 Relationships 节点)
 * @param {string} itemType - 对象类型
 * @param {string} itemId - 对象ID
 * @param {Object} changes - 属性变更 { field: newValue }
 * @param {Object} relationChanges - ★新增:关系变更
 *   {
 *     add_relations: [{ type, related_id, properties }],
 *     edit_relations: [{ type, id, properties }],
 *     delete_relations: [{ type, id }]
 *   }
 * @returns {string} AML 字符串
 */
_buildRepairAML(itemType, itemId, changes, relationChanges = null) {
    // 1. 属性 XML
    const props = Object.entries(changes)
      .filter(([k, v]) => v !== null && v !== undefined)
      .map(([k, v]) => `<${k}>${this._escapeXml(String(v))}</${k}>`)
      .join('');

    // 2. ★ 关系 XML
    let relsXml = '';
    if (relationChanges) {
      relsXml = this._buildRepairRelationshipsXml(relationChanges);
    }

    return `<AML><Item type="${itemType}" action="edit" id="${itemId}">${props}${relsXml}</Item></AML>`;
}

/**
 * ★ 新增:构建修复 AML 中的 Relationships XML
 * @param {Object} relationChanges - 关系变更
 * @returns {string} Relationships XML 片段
 */
_buildRepairRelationshipsXml(relationChanges) {
    const { add_relations = [], edit_relations = [], delete_relations = [] } = relationChanges;
    let xml = '';

    // 新增关系
    for (const rel of add_relations) {
      if (!rel.type) continue; // 跳过缺少 type 的关系
      xml += `<Item type="${this._escapeXml(rel.type)}" action="add">`;
      if (rel.related_id) {
        if (typeof rel.related_id === 'object' && rel.related_id.item_type) {
          // 嵌套创建
          xml += '<related_id>';
          xml += `<Item type="${this._escapeXml(rel.related_id.item_type)}" action="add">`;
          if (rel.related_id.properties) {
            for (const [k, v] of Object.entries(rel.related_id.properties)) {
              if (v !== null && v !== undefined && typeof v !== 'object') {
                xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
              }
            }
          }
          xml += '</Item></related_id>';
        } else {
          // GUID 引用
          xml += `<related_id>${this._escapeXml(String(rel.related_id))}</related_id>`;
        }
      }
      // 关系属性
      if (rel.properties) {
        for (const [k, v] of Object.entries(rel.properties)) {
          if (v !== null && v !== undefined && typeof v !== 'object') {
            xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
          }
        }
      }
      xml += '</Item>';
    }

    // 修改关系
    for (const rel of edit_relations) {
      if (!rel.type || !rel.id) continue;
      xml += `<Item type="${this._escapeXml(rel.type)}" action="edit" id="${this._escapeXml(rel.id)}">`;
      if (rel.properties) {
        for (const [k, v] of Object.entries(rel.properties)) {
          if (v !== null && v !== undefined && typeof v !== 'object') {
            xml += `<${k}>${this._escapeXml(String(v))}</${k}>`;
          }
        }
      }
      xml += '</Item>';
    }

    // 删除关系
    for (const rel of delete_relations) {
      if (!rel.type || !rel.id) continue;
      xml += `<Item type="${this._escapeXml(rel.type)}" action="delete" id="${this._escapeXml(rel.id)}"/>`;
    }

    if (xml) {
      return '<Relationships>' + xml + '</Relationships>';
    }
    return '';
}

2. rule-engine.js — 修改 executeRepair() 中的 _buildRepairAML 调用

executeRepair() 方法(约第1926行)中,将关系变更传入 _buildRepairAML

// 修改前:
// const aml = this._buildRepairAML(item_type, item_id, changes);

// 修改后:
const relationChanges = this._extractRelationChanges(repairs);
const aml = this._buildRepairAML(item_type, item_id, changes, relationChanges);

3. rule-engine.js — 新增 _extractRelationChanges() 辅助方法

/**
 * ★ 新增:从修复结果中提取关系变更
 * @param {Array} repairs - 修复结果数组
 * @returns {Object} { add_relations, edit_relations, delete_relations }
 */
_extractRelationChanges(repairs) {
    const addRelations = [];
    const editRelations = [];
    const deleteRelations = [];

    for (const repair of repairs) {
      const actionConfig = repair.action_config || {};
      // 从 action_config 中提取关系操作
      if (actionConfig.add_relations) {
        addRelations.push(...actionConfig.add_relations);
      }
      if (actionConfig.edit_relations) {
        editRelations.push(...actionConfig.edit_relations);
      }
      if (actionConfig.delete_relations) {
        deleteRelations.push(...actionConfig.delete_relations);
      }
      // 从 action_script 返回结果中提取
      if (repair.result?.add_relations) {
        addRelations.push(...repair.result.add_relations);
      }
      if (repair.result?.edit_relations) {
        editRelations.push(...repair.result.edit_relations);
      }
      if (repair.result?.delete_relations) {
        deleteRelations.push(...repair.result.delete_relations);
      }
    }

    return {
      add_relations: addRelations,
      edit_relations: editRelations,
      delete_relations: deleteRelations,
    };
}

#### 依赖关系

  • 依赖 _buildRepairAML() 方法(已存在,扩展参数)
  • 依赖 _escapeXml() 方法(已存在)
  • executeRepair()_executeOptimizeAction() 调用

#### 技术选型及理由

  • 向后兼容_buildRepairAML 新增第四个参数 relationChanges,默认 null,不影响现有调用
  • 属性修复与关系修复合并:在同一条 AML 中提交,确保 SCSAI 事务原子性
  • 双来源提取:关系变更可来自 action_config(静态配置)和 action_script 返回结果(动态生成),覆盖两种场景

1.3.7 P1-4: create_post 规则扩展

#### 需求概述

为 ECO/BOM/Document/Part/Vendor 等 ItemType 注册 CREATE_POST scope 内置规则,处理创建后的补充操作。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | _loadBuiltinRules() 添加 CREATE_POST 内置规则 |

#### 核心类/函数设计

_loadBuiltinRules() 方法中添加以下规则:

// ===== CREATE_POST 创建后规则 =====

// ECO: 创建后自动创建 Affected Item 关系
rules.push({
  id: 'builtin-create-post-eco-001',
  name: 'ECO: 自动创建 Affected Item 关系',
  scope: RULE_SCOPES.CREATE_POST,
  item_type_name: 'ECO',
  description: 'ECO创建成功后,自动创建 ECO Affected Item 关系',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'ECO' }),
  action_type: 'auto_fix',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  conflict_strategy: 'merge',
  action_script: `
    var itemId = context.item_id;
    var p = context.properties || {};
    if (!itemId) return { modified: false };
    var affectedItems = p.affected_items || [];
    if (affectedItems.length === 0) return { modified: false };
    var addRels = [];
    for (var i = 0; i < affectedItems.length; i++) {
      var ai = affectedItems[i];
      if (ai.id || ai.item_number) {
        addRels.push({
          type: 'ECO Affected Item',
          related_id: ai.id || ai.item_number,
          properties: { change_action: ai.change_action || 'Update' }
        });
      }
    }
    if (addRels.length > 0) {
      return {
        modified: true,
        add_relations: addRels,
        message: '已自动创建 ' + addRels.length + ' 个 Affected Item 关系'
      };
    }
    return { modified: false };
  `,
  is_builtin: 1
});

// BOM: 创建后验证结构完整性
rules.push({
  id: 'builtin-create-post-bom-001',
  name: 'BOM: 结构完整性验证',
  scope: RULE_SCOPES.CREATE_POST,
  item_type_name: 'BOM',
  description: 'BOM创建成功后,验证结构完整性并补全缺失关系',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'BOM' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P1,
  action_script: `
    var p = context.properties || {};
    var warnings = [];
    if (!p.bom_number) warnings.push('BOM编号缺失');
    if (!p.product_name && !p.name) warnings.push('产品名称缺失');
    if (warnings.length > 0) {
      return { suggested: true, suggestion: 'BOM结构验证: ' + warnings.join(', ') };
    }
    return { suggested: false };
  `,
  is_builtin: 1
});

// Document: 创建后自动关联项目/产品
rules.push({
  id: 'builtin-create-post-document-001',
  name: 'Document: 自动关联项目/产品',
  scope: RULE_SCOPES.CREATE_POST,
  item_type_name: 'Document',
  description: 'Document创建成功后,自动关联到对应的项目或产品',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Document' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P1,
  action_script: `
    var p = context.properties || {};
    var suggestions = [];
    if (p.project_name || p.project_id) {
      suggestions.push('建议关联到项目: ' + (p.project_name || p.project_id));
    }
    if (p.product_name || p.product_id) {
      suggestions.push('建议关联到产品: ' + (p.product_name || p.product_id));
    }
    if (suggestions.length > 0) {
      return { suggested: true, suggestion: suggestions.join('; ') };
    }
    return { suggested: false };
  `,
  is_builtin: 1
});

// Part: 创建后编号规范验证与BOM默认关系
rules.push({
  id: 'builtin-create-post-part-001',
  name: 'Part: 编号规范验证与默认关系',
  scope: RULE_SCOPES.CREATE_POST,
  item_type_name: 'Part',
  description: 'Part创建成功后,验证编号格式并建议建立BOM关系',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Part' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P1,
  action_script: `
    var p = context.properties || {};
    var suggestions = [];
    var itemNumber = p.item_number || '';
    if (itemNumber && !/^[A-Z]{2,4}-\\d{3,}$/.test(itemNumber)) {
      suggestions.push('编号格式建议: 前缀(2-4字母)-数字(3位以上), 如 PR-001');
    }
    if (p.classification === 'Assembly' || p.classification === '装配件') {
      suggestions.push('装配件建议建立BOM关系');
    }
    if (suggestions.length > 0) {
      return { suggested: true, suggestion: suggestions.join('; ') };
    }
    return { suggested: false };
  `,
  is_builtin: 1
});

// Vendor: 创建后分类关系
rules.push({
  id: 'builtin-create-post-vendor-001',
  name: 'Vendor: 供应商分类关系',
  scope: RULE_SCOPES.CREATE_POST,
  item_type_name: 'Vendor',
  description: 'Vendor创建成功后,建议创建供应商分类关系',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Vendor' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P2,
  action_script: `
    var p = context.properties || {};
    var category = p.classification || p.vendor_type || p.category || '';
    if (category) {
      return { suggested: true, suggestion: '建议将供应商分类为: ' + category };
    }
    return { suggested: true, suggestion: '建议设置供应商分类(原材料/外协/标准件)' };
  `,
  is_builtin: 1
});

#### 数据模型

新增内置规则清单

| 规则ID | scope | item_type_name | action_type | 说明 |

|--------|-------|----------------|-------------|------|

| builtin-create-post-eco-001 | create_post | ECO | auto_fix | 自动创建Affected Item关系 |

| builtin-create-post-bom-001 | create_post | BOM | suggest | 结构完整性验证 |

| builtin-create-post-document-001 | create_post | Document | suggest | 自动关联项目/产品 |

| builtin-create-post-part-001 | create_post | Part | suggest | 编号规范验证 |

| builtin-create-post-vendor-001 | create_post | Vendor | suggest | 供应商分类关系 |

#### 依赖关系

  • 依赖 _loadBuiltinRules() 注册机制(已存在)
  • 依赖 createItem() 中的 CREATE_POST 执行流程(已存在,第2241-2246行)
  • 依赖 _executeAction() 脚本执行沙箱(已存在)
  • ECO 的 auto_fix 依赖 _buildRepairAML() 的关系支持(P1-3)

#### 技术选型及理由

  • ECO 使用 auto_fix:ECO 的 Affected Item 关系创建是确定性操作,适合自动执行
  • 其他使用 suggest:BOM/Document/Part/Vendor 的后置操作需要人工确认,使用 suggest 返回建议
  • CREATE_POST 失败不回滚主对象:符合spec中"主对象创建不回滚"的约束

1.3.8 P2-1: identify 内置规则扩展

#### 需求概述

为 Part/Vendor/BOM/ECO/Document 等常用 ItemType 注册专用 IDENTIFY scope 内置规则。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/rule-engine.js | 修改 | _loadBuiltinRules() 添加 ItemType 专用 IDENTIFY 规则 |

#### 核心类/函数设计

_loadBuiltinRules() 方法中添加以下规则:

// ===== ItemType 专用 IDENTIFY 识别规则 =====

// Part: 零件识别(含属性模板和分类信息)
rules.push({
  id: 'builtin-identify-part-001',
  name: 'Part: 零件属性模板识别',
  scope: RULE_SCOPES.IDENTIFY,
  item_type_name: 'Part',
  description: '识别Part类型对象,返回零件属性模板和分类信息',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Part' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    return {
      suggested: true,
      suggestion: 'Part零件识别',
      item_type: 'Part',
      template: {
        required_fields: ['item_number', 'name'],
        optional_fields: ['description', 'unit', 'unit_cost', 'manufacturer', 'part_spec', 'classification'],
        classification_options: ['电子类', '机械类', '标准件', '定制件', '装配件']
      }
    };
  `,
  is_builtin: 1
});

// Vendor: 供应商识别(含评分和资质信息)
rules.push({
  id: 'builtin-identify-vendor-001',
  name: 'Vendor: 供应商评分识别',
  scope: RULE_SCOPES.IDENTIFY,
  item_type_name: 'Vendor',
  description: '识别Vendor类型对象,返回供应商评分和资质信息',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Vendor' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    var qualityRating = Number(p.quality_rating || 0);
    var deliveryRating = Number(p.delivery_rating || 0);
    var priceRating = Number(p.price_rating || 0);
    var overallRating = Number(p.overall_rating || 0);
    var avgRating = (qualityRating + deliveryRating + priceRating) / 3 || overallRating;
    var level = avgRating >= 80 ? 'A' : avgRating >= 60 ? 'B' : avgRating >= 40 ? 'C' : 'D';
    return {
      suggested: true,
      suggestion: '供应商评级: ' + level + ' (综合' + avgRating.toFixed(1) + '分)',
      item_type: 'Vendor',
      rating: { quality: qualityRating, delivery: deliveryRating, price: priceRating, overall: avgRating, level: level },
      qualification_fields: ['tax_id', 'business_license', 'iso_certification']
    };
  `,
  is_builtin: 1
});

// BOM: 物料清单识别(含结构和层级信息)
rules.push({
  id: 'builtin-identify-bom-001',
  name: 'BOM: 结构层级识别',
  scope: RULE_SCOPES.IDENTIFY,
  item_type_name: 'BOM',
  description: '识别BOM类型对象,返回BOM结构和层级信息',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'BOM' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    return {
      suggested: true,
      suggestion: 'BOM结构识别',
      item_type: 'BOM',
      structure: {
        bom_number: p.bom_number || '',
        product_name: p.product_name || p.name || '',
        version: p.version || '1.0',
        component_count: p.components ? p.components.length : 0,
        hierarchy_type: p.hierarchy_type || 'flat'
      }
    };
  `,
  is_builtin: 1
});

// ECO: 工程变更单识别(含影响范围和审批状态)
rules.push({
  id: 'builtin-identify-eco-001',
  name: 'ECO: 变更影响范围识别',
  scope: RULE_SCOPES.IDENTIFY,
  item_type_name: 'ECO',
  description: '识别ECO类型对象,返回变更影响范围和审批状态',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'ECO' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    var state = p.state || p.status || 'Unknown';
    var affectedItems = p.affected_items || [];
    return {
      suggested: true,
      suggestion: 'ECO变更识别: 状态=' + state + ', 影响项=' + affectedItems.length,
      item_type: 'ECO',
      change_info: {
        title: p.title || p.name || '',
        state: state,
        change_type: p.change_type || 'Engineering',
        affected_count: affectedItems.length,
        priority: p.priority || 'Medium'
      }
    };
  `,
  is_builtin: 1
});

// Document: 文档识别(含分类和关联对象)
rules.push({
  id: 'builtin-identify-document-001',
  name: 'Document: 文档分类识别',
  scope: RULE_SCOPES.IDENTIFY,
  item_type_name: 'Document',
  description: '识别Document类型对象,返回文档分类和关联对象',
  condition: JSON.stringify({ type: 'item_type_match', item_type: 'Document' }),
  action_type: 'suggest',
  severity: RULE_SEVERITIES.INFO,
  priority: RULE_PRIORITIES.P0,
  action_script: `
    var p = context.properties || context.data || {};
    return {
      suggested: true,
      suggestion: '文档分类识别',
      item_type: 'Document',
      doc_info: {
        title: p.title || p.name || '',
        document_type: p.document_type || 'Specification',
        classification: p.classification || 'General',
        related_objects: p.related_objects || []
      }
    };
  `,
  is_builtin: 1
});

#### 依赖关系

  • 依赖 _loadBuiltinRules() 注册机制(已存在)
  • 依赖 executeIdentify() 的规则匹配流程(已存在)
  • 依赖 _executeAction() 脚本执行沙箱(已存在)

#### 技术选型及理由

  • 专用规则优先级 P0:ItemType 专用规则优先于通用 builtin-identify-001(P1),确保专用规则先匹配
  • 返回结构化模板:每个专用规则返回 templatestructure 等结构化信息,供前端展示
  • 条件匹配 item_type_match:通过 item_type_name 字段自动过滤,无需额外条件脚本

1.3.9 P2-2: RelationshipResolver SCSAI 关系查询

#### 需求概述

RelationshipResolver.discoverRelations() 添加 SCSAI 关系查询,与本地关系发现结果去重。

#### 修改文件

| 文件路径 | 修改类型 | 说明 |

|---------|---------|------|

| server/core/relationship-resolver.js | 修改 | discoverRelations() 添加 SCSAI 关系查询和去重逻辑 |

#### 核心类/函数设计

1. relationship-resolver.js — 增强 discoverRelations() 方法

在现有 discoverRelations() 方法(第247行)中,在本地关系发现之前添加 SCSAI 关系查询:

/**
 * 在一组对象中自动发现父子关系
 * ★ 增强:添加 SCSAI 已有关系查询和去重
 * @param {string} itemType - 对象类型
 * @param {Array<Object>} items - 对象数组
 * @returns {Object} { relations, graph, existing_relations, new_relations }
 */
async discoverRelations(itemType, items) {
    if (!Array.isArray(items) || items.length < 2) {
      return { relations: [], graph: { nodes: items?.length || 0, edges: 0 }, existing_relations: [], new_relations: [] };
    }

    const type = itemType || 'Part';
    const rc = getRelationshipCapability();

    // ★ 1. 查询 SCSAI 已有关系
    let existingRelations = [];
    try {
      existingRelations = await this._queryExistingRelations(type, items);
    } catch (e) {
      console.warn('[discoverRelations] SCSAI关系查询失败(非阻塞):', e.message);
    }

    // 2. 本地关系发现(现有逻辑保持不变)
    // ... 现有的 numberIndex/nameIndex 构建和字段匹配逻辑 ...

    // 3. ★ 去重:候选关系 vs 已有关系
    const newRelations = [];
    for (const rel of relations) {
      const isDuplicate = existingRelations.some(existing => {
        const sameType = existing.relationship_type === rel.relation_type;
        const sameTarget = existing.related_id === items[rel.child_index]?.id
          || existing.related_item_number === items[rel.child_index]?.item_number;
        return sameType && sameTarget;
      });

      if (!isDuplicate) {
        newRelations.push(rel);
      } else {
        rel.already_exists = true;
      }
    }

    // ... 现有的图构建逻辑 ...

    return {
      relations,
      graph: { nodes: items.length, edges: relations.length },
      existing_relations: existingRelations,
      new_relations: newRelations,
    };
}

/**
 * ★ 新增:查询 SCSAI 中已有关系
 * @param {string} itemType - 对象类型
 * @param {Array<Object>} items - 对象数组
 * @returns {Promise<Array>} 已有关系列表
 */
async _queryExistingRelations(itemType, items) {
    const client = getSCSAIClient();
    if (!client) return [];

    const existingRelations = [];
    const SCSAI_QUERY_TIMEOUT = 3000; // 3秒超时

    for (const item of items) {
      const itemId = item.id;
      const itemNumber = item.item_number || item.part_number || '';

      if (!itemId && !itemNumber) continue;

      try {
        // 构建查询 AML:获取对象的所有关系
        let queryAml;
        if (itemId) {
          queryAml = `<AML><Item type="${itemType}" action="get" id="${escapeXml(itemId)}" select="id,item_number">` +
            `<Relationships><Item action="get" select="id,related_id,source_id"/></Relationships>` +
            `</Item></AML>`;
        } else {
          queryAml = `<AML><Item type="${itemType}" action="get" select="id,item_number">` +
            `<item_number>${escapeXml(itemNumber)}</item_number>` +
            `<Relationships><Item action="get" select="id,related_id,source_id"/></Relationships>` +
            `</Item></AML>`;
        }

        const queryPromise = client.sendAML(queryAml);
        const timeoutPromise = new Promise((_, reject) =>
          setTimeout(() => reject(new Error('SCSAI查询超时')), SCSAI_QUERY_TIMEOUT)
        );

        const result = await Promise.race([queryPromise, timeoutPromise]);

        if (result.success && result.items && result.items.length > 0) {
          const mainItem = result.items[0];
          const rels = mainItem.Relationships?.Item || [];
          const relArray = Array.isArray(rels) ? rels : [rels];

          for (const rel of relArray) {
            existingRelations.push({
              relationship_type: rel['@_type'] || rel.type || '',
              relationship_id: rel.id || rel['@_id'] || '',
              related_id: rel.related_id?.Item?.id
                || rel.related_id?.id
                || (typeof rel.related_id === 'string' ? rel.related_id : ''),
              related_item_type: rel.related_id?.Item?.['@_type']
                || rel.related_id?.Item?.type || '',
              related_item_number: rel.related_id?.Item?.item_number || '',
              source_item_id: mainItem.id,
            });
          }
        }
      } catch (e) {
        // 单个对象查询失败不阻断
        console.warn('[queryExistingRelations] 查询失败:', e.message);
      }
    }

    return existingRelations;
}

#### 数据模型

discoverRelations 返回结果(含已有关系)

{
  "relations": [
    {
      "parent_index": 0,
      "child_index": 1,
      "relation_type": "Part BOM",
      "field_hint": "bom_name",
      "properties": { "quantity": 5 },
      "already_exists": false
    }
  ],
  "graph": { "nodes": 3, "edges": 1 },
  "existing_relations": [
    {
      "relationship_type": "Part BOM",
      "relationship_id": "REL001",
      "related_id": "ITEM002",
      "related_item_type": "Part",
      "related_item_number": "P-002",
      "source_item_id": "ITEM001"
    }
  ],
  "new_relations": [
    {
      "parent_index": 0,
      "child_index": 1,
      "relation_type": "Part BOM",
      "field_hint": "bom_name",
      "properties": { "quantity": 5 }
    }
  ]
}

#### 依赖关系

  • 依赖 getSCSAIClient() 获取 SCSAI 客户端(已存在)
  • 依赖 client.sendAML() 查询 SCSAI(已存在)
  • 依赖 RelationshipCapability 本地关系发现(已存在)
  • 不修改 RelationshipCapability 本身

#### 技术选型及理由

  • 逐对象查询而非批量查询:SCSAI AML 不支持批量关系查询,逐对象查询更可靠
  • 3秒超时:与spec中"SCSAI查询超时3秒"一致,使用 Promise.race 实现
  • 去重基于 relationship_type + related_id:简单可靠,避免重复创建
  • 非阻塞:SCSAI 查询失败时返回空 existing_relations,本地发现继续执行

2. 接口设计

2.1 总体设计

六大能力增强不新增独立的 HTTP API 路由,而是通过增强现有 CapabilityRuntimeUnifiedRuleEngine 的内部方法实现。所有增强通过现有的 /api/capability 路由暴露。

2.1.1 接口调用路径

HTTP Request → server.js handleRequest()
  → /api/capability (POST)
    → CapabilityDispatcher.execute()
      → CapabilityRuntime.{capability}()
        → UnifiedRuleEngine.execute{Capability}()
          → SCSAI / LLM Router

2.2 接口清单

2.2.1 generate 能力接口(增强)

请求

POST /api/capability
{
  "capability": "generate",
  "params": {
    "item_type": "ECO",
    "data": { "title": "工程变更单", "change_reason": "设计优化" },
    "template_id": "tpl-eco-001"
  }
}

响应

{
  "success": true,
  "capability": "generate",
  "source": "rule_engine",
  "result": {
    "executed": true,
    "scope": "generate",
    "item_type": "ECO",
    "generated_content": "{...}",
    "results": [
      {
        "rule": "ECO: 工程变更单生成",
        "rule_id": "builtin-generate-eco-001",
        "result": { "generated": true, "content": "...", "template": "eco_standard" }
      }
    ]
  }
}

2.2.2 identify 能力接口(增强)

请求

POST /api/capability
{
  "capability": "identify",
  "params": {
    "item_type": "Part",
    "query_type": "list",
    "filters": { "classification": "电子类" }
  },
  "options": { "includeRelations": true }
}

响应

{
  "success": true,
  "capability": "identify",
  "source": "rule_engine",
  "result": { "query_result": { "items": [...] } },
  "related_objects": [
    {
      "relationship_type": "Part BOM",
      "related_item": { "type": "Part", "hint": "P-001" },
      "direction": "outgoing",
      "confidence": 0.9,
      "method": "rule_engine"
    }
  ],
  "has_more": false
}

2.2.3 compare 能力接口(增强)

请求

POST /api/capability
{
  "capability": "compare",
  "params": {
    "item_type": "Part",
    "item_a": { "type": "Part", "id": "ID001" },
    "item_b": { "type": "Part", "id": "ID002" },
    "mode": "version"
  }
}

响应

{
  "success": true,
  "capability": "compare",
  "source": "rule_engine",
  "result": {
    "field_diffs": [
      { "field": "name", "value_a": "旧名称", "value_b": "新名称", "change_type": "modified" },
      {
        "change_type": "relation_added",
        "relationship_type": "Part BOM",
        "related_item_type": "Part",
        "related_item_id": "ABC123",
        "value_a": null,
        "value_b": { "...": "..." }
      }
    ],
    "summary": {
      "total_changes": 2,
      "added": 0, "removed": 0, "modified": 1,
      "relation_added": 1, "relation_removed": 0, "relation_modified": 0
    }
  }
}

2.2.4 optimize 能力接口(增强)

请求

POST /api/capability
{
  "capability": "optimize",
  "params": {
    "item_type": "Part",
    "item_id": "ID001",
    "data": { "unit_cost": 1500 }
  }
}

响应

{
  "success": true,
  "capability": "optimize",
  "source": "rule_engine",
  "result": {
    "optimizations": [
      {
        "rule": "数据标准化",
        "action_type": "auto_fix",
        "auto_applied": true,
        "item_id": "ID001"
      }
    ]
  }
}

4. 数据模型

4.1 设计目标

  1. 不新增数据库表:所有增强基于现有 sciot_rules_v2prompt_templatessciot_rule_history
  2. 新增内置规则:通过 _loadBuiltinRules() 硬编码注册,_syncBuiltinRules() 同步到数据库
  3. 兼容现有数据:新增字段和规则不破坏现有数据结构

4.2 模型实现

4.2.1 新增内置规则清单

| 规则ID | scope | item_type_name | action_type | 需求ID |

|--------|-------|----------------|-------------|--------|

| builtin-generate-001 | generate | null | suggest | P0-1 |

| builtin-transform-001 | transform | null | suggest | P0-1 |

| builtin-generate-eco-001 | generate | ECO | suggest | P0-1 |

| builtin-generate-bom-001 | generate | BOM | suggest | P0-1 |

| builtin-generate-document-001 | generate | Document | suggest | P0-1 |

| builtin-create-post-eco-001 | create_post | ECO | auto_fix | P1-4 |

| builtin-create-post-bom-001 | create_post | BOM | suggest | P1-4 |

| builtin-create-post-document-001 | create_post | Document | suggest | P1-4 |

| builtin-create-post-part-001 | create_post | Part | suggest | P1-4 |

| builtin-create-post-vendor-001 | create_post | Vendor | suggest | P1-4 |

| builtin-identify-part-001 | identify | Part | suggest | P2-1 |

| builtin-identify-vendor-001 | identify | Vendor | suggest | P2-1 |

| builtin-identify-bom-001 | identify | BOM | suggest | P2-1 |

| builtin-identify-eco-001 | identify | ECO | suggest | P2-1 |

| builtin-identify-document-001 | identify | Document | suggest | P2-1 |

4.2.2 identify 返回结果 JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "IdentifyResult",
  "type": "object",
  "properties": {
    "capability": { "const": "identify" },
    "success": { "type": "boolean" },
    "source": { "enum": ["rule_engine", "llm_router", "rule_engine_only"] },
    "result": { "type": "object" },
    "related_objects": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "relationship_type": { "type": "string" },
          "related_item": {
            "type": "object",
            "properties": {
              "type": { "type": "string" },
              "hint": { "type": "string" }
            }
          },
          "direction": { "type": "string", "enum": ["outgoing", "incoming", "bidirectional"] },
          "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
          "method": { "type": "string", "enum": ["rule_engine", "template", "data_hint", "unknown"] }
        }
      }
    },
    "has_more": { "type": "boolean" }
  }
}

4.2.3 compare 差异结果 JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "CompareFieldDiff",
  "oneOf": [
    {
      "title": "属性差异",
      "type": "object",
      "properties": {
        "field": { "type": "string" },
        "value_a": {},
        "value_b": {},
        "change_type": { "enum": ["added", "removed", "modified"] }
      }
    },
    {
      "title": "关系差异",
      "type": "object",
      "properties": {
        "change_type": { "enum": ["relation_added", "relation_removed", "relation_modified"] },
        "relationship_type": { "type": "string" },
        "related_item_type": { "type": "string" },
        "related_item_id": { "type": "string" },
        "value_a": {},
        "value_b": {},
        "property_diffs": { "type": "array" }
      },
      "required": ["change_type", "relationship_type"]
    }
  ]
}

4.2.4 AML Relationships 节点格式

<!-- AMLBuilder 标准格式(前端已测试) -->
<AML>
  <Item type="Part" action="add">
    <item_number>P-001</item_number>
    <name>零件A</name>
    <Relationships>
      <Item type="Part BOM" action="add">
        <related_id>
          <Item type="Part" action="add">
            <item_number>P-002</item_number>
            <name>子零件B</name>
          </Item>
        </related_id>
        <quantity>5</quantity>
      </Item>
    </Relationships>
  </Item>
</AML>

<!-- 修复 AML 中的 Relationships(P1-3) -->
<AML>
  <Item type="Part" action="edit" id="EXISTING_ID">
    <name>修改后的名称</name>
    <Relationships>
      <Item type="Part BOM" action="add">
        <related_id>NEW_PART_ID</related_id>
      </Item>
      <Item type="Part BOM" action="edit" id="REL_ID_TO_EDIT">
        <quantity>10</quantity>
      </Item>
      <Item type="Part BOM" action="delete" id="REL_ID_TO_DELETE"/>
    </Relationships>
  </Item>
</AML>

附录

A. 修改文件汇总

| 文件路径 | 修改类型 | 涉及需求 | 修改要点 |

|---------|---------|---------|---------|

| server/core/rule-engine.js | 修改 | P0-1, P1-1, P1-2, P1-3, P1-4, P2-1 | 新增内置规则、executeGenerate、_computeRelationDiffs、_executeOptimizeAction、_buildRepairAML增强、_buildRepairRelationshipsXml、_extractRelationChanges |

| server/core/capability-runtime.js | 修改 | P0-1, P0-3 | generate()集成规则引擎、identify()集成关系发现、_getRelationshipCapability() |

| server/core/aml-generator.js | 修改 | P0-2 | _buildAML()添加Relationships、_buildRelationshipsXml、_buildAmlBuilderStyleRelation、_buildSimpleStyleRelation |

| server/core/relationship-resolver.js | 修改 | P2-2 | discoverRelations()添加SCSAI查询、_queryExistingRelations()、去重逻辑 |

B. 新增文件汇总

无新增文件。所有增强通过修改现有文件实现。

C. 技术约束遵守确认

约束遵守情况
项目基于pnpm✅ 不涉及包管理变更
server.js POST路由需先collectBody(req)✅ 不修改server.js路由层
module.exports = CapabilityDispatcher✅ 不修改导出方式
FTS5不可用✅ 不使用FTS5
jieba等中文分词包编译失败✅ 不引入中文分词包
前端修改后需npm run build✅ 本次不涉及前端修改
AMLGenerator与AMLBuilder一致性✅ Relationships输出格式与AMLBuilder保持一致

D. 实现优先级与依赖关系

P0-1 (generate规则驱动) ── 无前置依赖
P0-2 (AMLGenerator Relationships) ── 无前置依赖
P0-3 (identify关系发现) ── 无前置依赖
    │
    ▼
P1-1 (compare关系差异) ── 依赖 P0-2(关系数据格式定义)
P1-2 (optimize自动执行) ── 依赖 P1-3(_buildRepairAML增强)
P1-3 (repair关系修复) ── 无前置依赖
P1-4 (create_post规则扩展) ── 依赖 P1-3(ECO auto_fix需关系AML支持)
    │
    ▼
P2-1 (identify内置规则扩展) ── 无前置依赖
P2-2 (RelationshipResolver SCSAI查询) ── 无前置依赖

建议实施顺序:P0-1 → P0-2 → P0-3 → P1-3 → P1-2 → P1-1 → P1-4 → P2-1 → P2-2

← 返回案例列表
分享:
🤖 Try Now →
🤖
🎁