bookworm-smart-assistant/scripts/archive/route-weights-report.js

100 lines
3.0 KiB
JavaScript
Raw Permalink Normal View History

#!/usr/bin/env node
/**
* v5.6 T10: 路由权重看板报告
* 分析 debug/route-weights.json 的权重分布和异常
*
* 使用: node scripts/route-weights-report.js [--json]
*/
const fs = require('fs');
const path = require('path');
let debugDir;
try {
debugDir = require('./paths.config.js').PATHS.debugDir;
} catch {
debugDir = path.resolve(__dirname, '..', 'debug');
}
function loadWeights() {
const f = path.join(debugDir, 'route-weights.json');
try {
if (!fs.existsSync(f)) return null;
return JSON.parse(fs.readFileSync(f, 'utf8'));
} catch { return null; }
}
function analyze(weights) {
if (!weights || !weights.deltas) return { status: 'empty', count: 0, deltas: {} };
const deltas = weights.deltas;
const entries = Object.entries(deltas);
const count = entries.length;
if (count === 0) return { status: 'empty', count: 0, deltas: {} };
const values = entries.map(([, v]) => v);
const maxAbs = Math.max(...values.map(Math.abs));
const positives = entries.filter(([, v]) => v > 0);
const negatives = entries.filter(([, v]) => v < 0);
const nearLimit = entries.filter(([, v]) => Math.abs(v) >= 0.4);
const sorted = [...entries].sort((a, b) => b[1] - a[1]);
const topBoosts = sorted.slice(0, 5);
const topPenalties = sorted.slice(-5).reverse();
return {
status: maxAbs >= 0.4 ? 'saturating' : maxAbs >= 0.2 ? 'active' : 'stable',
count,
positives: positives.length,
negatives: negatives.length,
maxAbsDelta: maxAbs,
nearLimit: nearLimit.map(([k, v]) => ({ skill: k, delta: v })),
topBoosts: topBoosts.map(([k, v]) => ({ skill: k, delta: v })),
topPenalties: topPenalties.map(([k, v]) => ({ skill: k, delta: v })),
lastUpdated: weights.lastUpdated || null,
snapshotTs: weights.snapshotTs || null,
};
}
function printReport(report) {
console.log('=== 路由权重看板 ===');
console.log('状态:', report.status);
console.log('权重条目:', report.count, '(正:', report.positives, '/ 负:', report.negatives, ')');
console.log('最大偏移:', report.maxAbsDelta?.toFixed(3) || 'N/A');
if (report.nearLimit?.length > 0) {
console.log('\n--- 接近限幅 (|delta| >= 0.4) ---');
for (const { skill, delta } of report.nearLimit) {
console.log(' ', skill, ':', delta > 0 ? '+' : '', delta.toFixed(3));
}
}
if (report.topBoosts?.length > 0) {
console.log('\n--- Top 5 增强 ---');
for (const { skill, delta } of report.topBoosts) {
console.log(' ', skill, ': +' + delta.toFixed(3));
}
}
if (report.topPenalties?.length > 0) {
console.log('\n--- Top 5 惩罚 ---');
for (const { skill, delta } of report.topPenalties) {
console.log(' ', skill, ':', delta.toFixed(3));
}
}
console.log('\n上次更新:', report.lastUpdated || 'N/A');
}
if (require.main === module) {
const weights = loadWeights();
const report = analyze(weights);
if (process.argv.includes('--json')) {
console.log(JSON.stringify(report, null, 2));
} else {
printReport(report);
}
}
module.exports = { loadWeights, analyze };