108 lines
3.7 KiB
JavaScript
108 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Task3 补丁 — 2026-04-20 路由精准度审查
|
||
*
|
||
* 问题: 2-3 字短查询(token 数 ≤3)信息量不足,BM25 仍可算出 confidence=1.0,
|
||
* 导致 100% 置信度过拟合(如"自动修复"→ browser-automation-expert 100%)。
|
||
*
|
||
* 修复方案: 在 route-engine.js 返回结果前加一层置信度上限:
|
||
* 若 queryTokens.length ≤ 3,则 confidence = min(confidence, 0.8)
|
||
* 并写入调试日志便于后续观察。
|
||
*
|
||
* 最小侵入: 仅在 return 语句前插入 4 行代码。
|
||
*
|
||
* 幂等: sentinel = 'CONFIDENCE_CAP_SHORT_QUERY_PATCH_2026_04_20'
|
||
*/
|
||
'use strict';
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const SCRIPTS_DIR = path.join(__dirname, '..');
|
||
const TARGET = path.join(SCRIPTS_DIR, 'route-engine.js');
|
||
const SENTINEL = 'CONFIDENCE_CAP_SHORT_QUERY_PATCH_2026_04_20';
|
||
|
||
function main() {
|
||
if (!fs.existsSync(TARGET)) {
|
||
console.error('[patch-task3] 目标文件不存在:', TARGET);
|
||
process.exit(1);
|
||
}
|
||
|
||
const before = fs.readFileSync(TARGET, 'utf8');
|
||
|
||
// 幂等检查
|
||
if (before.includes(SENTINEL)) {
|
||
console.log('[patch-task3] 已打过补丁 (发现 sentinel),跳过');
|
||
process.exit(0);
|
||
}
|
||
|
||
// 锚点: return 语句前的 confidence 计算行
|
||
const anchor =
|
||
' const confidence = normalized[0]?.confidence || 0;\n' +
|
||
'\n' +
|
||
' return {';
|
||
|
||
if (!before.includes(anchor)) {
|
||
console.error('[patch-task3] 找不到 confidence 计算锚点,route-engine.js 结构已变更');
|
||
process.exit(2);
|
||
}
|
||
|
||
// 注入: confidence 上限 + debug log
|
||
const injection =
|
||
' const confidence = normalized[0]?.confidence || 0;\n' +
|
||
'\n' +
|
||
' // ' + SENTINEL + '\n' +
|
||
' // 短查询置信度上限: token 数 ≤3 时 confidence 不超过 0.8,防 BM25 过拟合\n' +
|
||
' let _finalConfidence = confidence;\n' +
|
||
' if (queryTokens.size <= 3 && _finalConfidence > 0.8) {\n' +
|
||
' _finalConfidence = 0.8;\n' +
|
||
' try {\n' +
|
||
' const logLine = JSON.stringify({\n' +
|
||
' t: Date.now(), event: \'confidence_cap\',\n' +
|
||
' tokens: queryTokens.size, original: confidence, capped: 0.8,\n' +
|
||
' primary: normalized[0] && normalized[0].name,\n' +
|
||
' }) + \'\\n\';\n' +
|
||
' fs.appendFileSync(path.join(DEBUG_DIR, \'confidence-cap.log\'), logLine);\n' +
|
||
' } catch {}\n' +
|
||
' }\n' +
|
||
'\n' +
|
||
' return {';
|
||
|
||
const after = before.replace(anchor, injection);
|
||
|
||
// 同时将 return 对象中的 confidence 替换为 _finalConfidence
|
||
const returnAnchor = ' primary, candidates, confidence, chain, composable,';
|
||
if (!after.includes(returnAnchor)) {
|
||
console.error('[patch-task3] 找不到 return 对象中的 confidence 字段');
|
||
process.exit(3);
|
||
}
|
||
const finalAfter = after.replace(
|
||
returnAnchor,
|
||
' primary, candidates, confidence: _finalConfidence, chain, composable,'
|
||
);
|
||
|
||
// ==== 原子写入 (.bak 备份 + tmp 文件) ====
|
||
const bakFile = TARGET + '.bak.task3.' + Date.now();
|
||
fs.copyFileSync(TARGET, bakFile);
|
||
console.log('[patch-task3] 备份已写入:', bakFile);
|
||
|
||
const tmpFile = TARGET + '.tmp';
|
||
fs.writeFileSync(tmpFile, finalAfter, 'utf8');
|
||
fs.renameSync(tmpFile, TARGET);
|
||
console.log('[patch-task3] 补丁已应用到:', TARGET);
|
||
|
||
// 验证
|
||
const verify = fs.readFileSync(TARGET, 'utf8');
|
||
if (!verify.includes(SENTINEL)) {
|
||
console.error('[patch-task3] 验证失败: sentinel 未找到!');
|
||
process.exit(4);
|
||
}
|
||
if (!verify.includes('_finalConfidence')) {
|
||
console.error('[patch-task3] 验证失败: _finalConfidence 未注入!');
|
||
process.exit(5);
|
||
}
|
||
console.log('[patch-task3] PASS — sentinel + _finalConfidence 验证通过');
|
||
}
|
||
|
||
main();
|