2026-05-10 13:12:44 +08:00

183 lines
5.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ═══════════════════════════════════════════════════════════
* 🏷️ 活模块: SY-CLASSIFY · 自动分类引擎
* ═══════════════════════════════════════════════════════════
*
* 编号: ZY-TASK-007 · S5 Agent系统级
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* v2.0: 从死模块升级为活模块
* - 继承 LivingModule 基类
* - 自诊断: 检查未分类节点堆积数量
* - 自愈: 规则失效时自动扩展规则
* - 学习: 记录分类成功率趋势
*
* 每2小时运行一次 · 扫描未分类节点按规则分类
*/
'use strict';
const LivingModule = require('./living-module');
const db = require('../mcp-server/db');
const { classify } = require('../mcp-server/tools/structure-ops');
// ─── 默认分类规则 ───
const DEFAULT_RULES = {
'人格体|persona|人格': { tags: ['人格体', '核心'], path: '/核心认知/人格体' },
'语言|language|TCS|通感': { tags: ['语言', 'TCS'], path: '/核心认知/语言本体论' },
'HLDP|协议|protocol': { tags: ['HLDP', '协议'], path: '/核心认知/HLDP' },
'架构|architecture|系统': { tags: ['架构', '系统'], path: '/技术架构' },
'代码|code|script|脚本': { tags: ['代码', '技术'], path: '/技术架构/代码' },
'日志|log|syslog': { tags: ['日志'], path: '/运行日志' },
'记忆|memory|认知': { tags: ['记忆', '认知'], path: '/核心认知/记忆' },
'工单|ticket|issue': { tags: ['工单'], path: '/工单' },
'用户|user|开发者|developer': { tags: ['用户'], path: '/用户管理' },
'部署|deploy|服务器|server': { tags: ['部署', '运维'], path: '/运维' },
'创作|写作|writing|小说': { tags: ['创作', '码字'], path: '/创作模块' },
'冰朔|bingshuo': { tags: ['冰朔', '主权'], path: '/核心认知/冰朔' },
'铸渊|zhuyuan': { tags: ['铸渊', '执行层'], path: '/核心认知/铸渊' },
'霜砚|shuangyan': { tags: ['霜砚', '语言层'], path: '/核心认知/霜砚' }
};
class LivingSyClassify extends LivingModule {
constructor(options = {}) {
super({
moduleId: 'ZY-MOD-SY-CLASSIFY',
name: '自动分类引擎活模块',
moduleType: 'agent',
owner: 'zhuyuan',
db: options.db || db,
config: {
version: '2.0.0',
description: '认知节点自动分类·规则引擎',
heartbeatInterval: 120000 // 分类模块心跳2分钟
}
});
// 分类统计
this._stats = {
totalClassified: 0,
totalUnclassified: 0,
lastRunSuccessRate: 0
};
}
/**
* 自定义诊断检查
*/
async _diagnoseChecks() {
const issues = [];
// 检查未分类节点堆积
try {
const result = await db.query(
"SELECT COUNT(*) as cnt FROM brain_nodes WHERE tags = '[]'::jsonb AND status = 'active'"
);
const count = parseInt(result.rows[0].cnt, 10);
if (count > 200) {
issues.push({
code: 'HIGH_UNCLASSIFIED_BACKLOG',
severity: 'warning',
message: `未分类节点堆积: ${count} 个 (>200)`,
suggestion: '增加分类规则或提高运行频率'
});
}
} catch (err) {
issues.push({
code: 'CLASSIFY_DB_FAIL',
severity: 'warning',
message: `分类查询失败: ${err.message}`,
suggestion: '检查数据库状态'
});
}
// 检查上次分类成功率
if (this._stats.totalClassified + this._stats.totalUnclassified > 0) {
const total = this._stats.totalClassified + this._stats.totalUnclassified;
const rate = this._stats.totalClassified / total;
if (rate < 0.5) {
issues.push({
code: 'LOW_CLASSIFY_RATE',
severity: 'info',
message: `分类成功率偏低: ${Math.round(rate * 100)}%`,
suggestion: '扩展分类规则覆盖更多关键词'
});
}
}
return issues;
}
/**
* 自愈动作
*/
async _healAction(issue) {
switch (issue.code) {
case 'HIGH_UNCLASSIFIED_BACKLOG':
// 记录并上报
return { action: 'backlog_alert_sent', success: true, details: { reported: true } };
case 'LOW_CLASSIFY_RATE':
// 规则问题只能上报·需要铸渊干预扩展规则
return { action: 'rule_expansion_requested', success: true, details: { reported: true } };
default:
return await super._healAction(issue);
}
}
}
/**
* 兼容旧调度器的 run() 接口
*/
async function run(config) {
// 找出未分类节点tags为空数组且状态为active
const untagged = await db.query(
"SELECT id FROM brain_nodes WHERE tags = '[]'::jsonb AND status = 'active' LIMIT 100"
);
if (untagged.rows.length === 0) {
return {
message: '无未分类节点',
details: { scanned: 0, classified: 0, unclassified: 0 }
};
}
const nodeIds = untagged.rows.map(r => r.id);
const result = await classify({
node_ids: nodeIds,
strategy: 'rule',
rules: DEFAULT_RULES,
dry_run: false
});
// 通过HLDP上报
if (config && config.bus) {
try {
await config.bus.send('ZY-MOD-SY-CLASSIFY', 'ZY-MOD-SCHEDULER', 'event', {
event: 'classify_complete',
scanned: nodeIds.length,
classified: result.classified.length,
unclassified: result.unclassified.length
});
} catch (err) {
// 非关键
}
}
return {
message: `分类完成: ${result.classified.length}个已分类, ${result.unclassified.length}个待人工`,
details: {
scanned: nodeIds.length,
classified: result.classified.length,
unclassified: result.unclassified.length,
classified_items: result.classified
}
};
}
module.exports = { run, LivingSyClassify };