148 lines
4.2 KiB
JavaScript
148 lines
4.2 KiB
JavaScript
|
|
/**
|
|||
|
|
* scripts/dc-agent-behavior.js
|
|||
|
|
* DC-03 · Agent 行为记录器
|
|||
|
|
*
|
|||
|
|
* 采集时机:每次铸渊处理 Notion 工单回写后附带写入
|
|||
|
|
* 存储位置:data/dc-reports/agent-behavior-YYYY-MM.json(按月累积)
|
|||
|
|
*
|
|||
|
|
* 用法:
|
|||
|
|
* 1. 作为模块引入:
|
|||
|
|
* const { appendAgentBehaviorLog } = require('./dc-agent-behavior');
|
|||
|
|
* appendAgentBehaviorLog({ type: '规则同步', auto_resolved: true, processing_sec: 18 });
|
|||
|
|
*
|
|||
|
|
* 2. 命令行调用:
|
|||
|
|
* node scripts/dc-agent-behavior.js --type "规则同步" --auto --sec 18
|
|||
|
|
* node scripts/dc-agent-behavior.js --type "工单回执" --human --sec 45 --llm-calls 3 --tokens 1200
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
'use strict';
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
|
|||
|
|
const ROOT = path.resolve(__dirname, '..');
|
|||
|
|
const DC_DIR = path.join(ROOT, 'data/dc-reports');
|
|||
|
|
|
|||
|
|
const BEIJING_OFFSET_MS = 8 * 3600 * 1000;
|
|||
|
|
|
|||
|
|
// ━━━ 获取当月标识 ━━━
|
|||
|
|
|
|||
|
|
function getCurrentMonth() {
|
|||
|
|
const now = new Date();
|
|||
|
|
return new Date(now.getTime() + BEIJING_OFFSET_MS).toISOString().slice(0, 7);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 加载或初始化月度文件 ━━━
|
|||
|
|
|
|||
|
|
function loadMonthlyReport(month) {
|
|||
|
|
const filePath = path.join(DC_DIR, `agent-behavior-${month}.json`);
|
|||
|
|
try {
|
|||
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|||
|
|
} catch {
|
|||
|
|
return {
|
|||
|
|
month: month,
|
|||
|
|
tickets: [],
|
|||
|
|
llm_calls_total: 0,
|
|||
|
|
avg_tokens_per_call: 0,
|
|||
|
|
human_intervention_rate: 0
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 重新计算统计指标 ━━━
|
|||
|
|
|
|||
|
|
function recalcStats(report) {
|
|||
|
|
const total = report.tickets.length;
|
|||
|
|
if (total === 0) return;
|
|||
|
|
|
|||
|
|
const humanCount = report.tickets.filter(t => t.human_intervention).length;
|
|||
|
|
report.human_intervention_rate = parseFloat((humanCount / total).toFixed(2));
|
|||
|
|
// llm_calls_total 和 avg_tokens_per_call 在 append 时累加
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 核心:追加行为记录 ━━━
|
|||
|
|
|
|||
|
|
function appendAgentBehaviorLog(ticketData) {
|
|||
|
|
fs.mkdirSync(DC_DIR, { recursive: true });
|
|||
|
|
|
|||
|
|
const month = ticketData.month || getCurrentMonth();
|
|||
|
|
const report = loadMonthlyReport(month);
|
|||
|
|
|
|||
|
|
const record = {
|
|||
|
|
type: ticketData.type || 'unknown',
|
|||
|
|
auto_resolved: ticketData.auto_resolved !== false,
|
|||
|
|
human_intervention: ticketData.human_intervention === true,
|
|||
|
|
processing_sec: ticketData.processing_sec || 0,
|
|||
|
|
timestamp: new Date().toISOString()
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
report.tickets.push(record);
|
|||
|
|
|
|||
|
|
// 累加 LLM 调用统计
|
|||
|
|
if (ticketData.llm_calls) {
|
|||
|
|
const prevTotal = report.llm_calls_total;
|
|||
|
|
report.llm_calls_total += ticketData.llm_calls;
|
|||
|
|
|
|||
|
|
if (ticketData.tokens_per_call) {
|
|||
|
|
// 加权平均
|
|||
|
|
const prevTokens = report.avg_tokens_per_call * prevTotal;
|
|||
|
|
const newTokens = ticketData.tokens_per_call * ticketData.llm_calls;
|
|||
|
|
report.avg_tokens_per_call = Math.round(
|
|||
|
|
(prevTokens + newTokens) / report.llm_calls_total
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
recalcStats(report);
|
|||
|
|
|
|||
|
|
const filePath = path.join(DC_DIR, `agent-behavior-${month}.json`);
|
|||
|
|
fs.writeFileSync(filePath, JSON.stringify(report, null, 2));
|
|||
|
|
|
|||
|
|
console.log(`🤖 DC-03 · 行为记录已追加: ${record.type} (${month})`);
|
|||
|
|
return report;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ CLI 模式 ━━━
|
|||
|
|
|
|||
|
|
function parseCli() {
|
|||
|
|
const args = process.argv.slice(2);
|
|||
|
|
if (args.length === 0) return null;
|
|||
|
|
|
|||
|
|
const data = {};
|
|||
|
|
for (let i = 0; i < args.length; i++) {
|
|||
|
|
switch (args[i]) {
|
|||
|
|
case '--type':
|
|||
|
|
data.type = args[++i]; break;
|
|||
|
|
case '--auto':
|
|||
|
|
data.auto_resolved = true; break;
|
|||
|
|
case '--human':
|
|||
|
|
data.human_intervention = true;
|
|||
|
|
data.auto_resolved = false; break;
|
|||
|
|
case '--sec':
|
|||
|
|
data.processing_sec = parseInt(args[++i], 10) || 0; break;
|
|||
|
|
case '--llm-calls':
|
|||
|
|
data.llm_calls = parseInt(args[++i], 10) || 0; break;
|
|||
|
|
case '--tokens':
|
|||
|
|
data.tokens_per_call = parseInt(args[++i], 10) || 0; break;
|
|||
|
|
case '--month':
|
|||
|
|
data.month = args[++i]; break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return data.type ? data : null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ━━━ 入口 ━━━
|
|||
|
|
|
|||
|
|
if (require.main === module) {
|
|||
|
|
const cliData = parseCli();
|
|||
|
|
if (cliData) {
|
|||
|
|
appendAgentBehaviorLog(cliData);
|
|||
|
|
} else {
|
|||
|
|
console.log('用法: node dc-agent-behavior.js --type "类型" [--auto|--human] [--sec N] [--llm-calls N] [--tokens N]');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { appendAgentBehaviorLog };
|