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.relationships 或 data._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.js的create()降级路径调用
#### 技术选型及理由
- 复用 AMLBuilder 逻辑而非直接调用:AMLGenerator 是端到端流程(Schema→验证→AML),直接调用 AMLBuilder 会破坏其内部状态管理;将关系构建逻辑内联,但与 AMLBuilder 保持一致的输出格式
- 支持两种关系格式:AMLBuilder 标准格式(前端已测试)+ 简化格式(后端LLM降级路径常用),兼容性最大化
- 过滤
_relationships和relationships字段:避免关系数据被当作普通属性输出到 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),确保专用规则先匹配 - 返回结构化模板:每个专用规则返回
template或structure等结构化信息,供前端展示 - 条件匹配
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 路由,而是通过增强现有 CapabilityRuntime 和 UnifiedRuleEngine 的内部方法实现。所有增强通过现有的 /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 设计目标
- 不新增数据库表:所有增强基于现有
sciot_rules_v2、prompt_templates、sciot_rule_history表 - 新增内置规则:通过
_loadBuiltinRules()硬编码注册,_syncBuiltinRules()同步到数据库 - 兼容现有数据:新增字段和规则不破坏现有数据结构
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
BossAgents