113 lines
4.0 KiB
JavaScript
113 lines
4.0 KiB
JavaScript
|
|
const path = require('path');
|
||
|
|
const { performance } = require('perf_hooks');
|
||
|
|
|
||
|
|
require('dotenv').config({ path: path.join(__dirname, '../.env') });
|
||
|
|
|
||
|
|
const ToolExecutor = require('../services/toolExecutor');
|
||
|
|
|
||
|
|
const realTestQueries = [
|
||
|
|
{ name: 'Product - Q10', query: 'Q10辅酵素氧修护有什么作用' },
|
||
|
|
{ name: 'Product - IB5', query: 'IB5口腔免疫喷雾怎么使用' },
|
||
|
|
{ name: 'Product - CC胶囊', query: 'CC胶囊适合什么人使用' },
|
||
|
|
{ name: 'Company - 邓白氏', query: '德国PM的邓白氏认证是多少分' },
|
||
|
|
{ name: 'Technology - 火炉原理', query: '请详细解释一下火炉原理' },
|
||
|
|
{ name: 'Training - 新人起步', query: '培训新人起步三关是什么' },
|
||
|
|
{ name: 'Product - 关节套装', query: '关节套装有什么功效' },
|
||
|
|
{ name: 'Company - 培安烟台', query: '培安烟台是什么' },
|
||
|
|
{ name: 'Product - 儿童倍适', query: '儿童倍适有什么成分' },
|
||
|
|
{ name: 'Science - 阿育吠陀', query: '阿育吠陀医学原理是什么' }
|
||
|
|
];
|
||
|
|
|
||
|
|
async function runRealKBTest() {
|
||
|
|
console.log('='.repeat(80));
|
||
|
|
console.log('VIKING REAL KNOWLEDGE BASE PERFORMANCE TEST');
|
||
|
|
console.log('='.repeat(80));
|
||
|
|
console.log('');
|
||
|
|
|
||
|
|
console.log('Warming up...');
|
||
|
|
for (let i = 0; i < 2; i++) {
|
||
|
|
for (const q of realTestQueries) {
|
||
|
|
try {
|
||
|
|
await ToolExecutor.searchKnowledge({ query: q.query, response_mode: 'answer' }, []);
|
||
|
|
} catch (e) {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
console.log('Warmup complete!\n');
|
||
|
|
|
||
|
|
console.log('Running latency tests (5 iterations each)...\n');
|
||
|
|
|
||
|
|
const allResults = [];
|
||
|
|
|
||
|
|
for (const { name, query } of realTestQueries) {
|
||
|
|
console.log(`Testing: ${name}`);
|
||
|
|
const latencies = [];
|
||
|
|
const hits = [];
|
||
|
|
|
||
|
|
for (let i = 0; i < 5; i++) {
|
||
|
|
const start = performance.now();
|
||
|
|
let result;
|
||
|
|
try {
|
||
|
|
result = await ToolExecutor.searchKnowledge({ query, response_mode: 'answer' }, []);
|
||
|
|
const latency = performance.now() - start;
|
||
|
|
latencies.push(latency);
|
||
|
|
hits.push(!!result.hit);
|
||
|
|
console.log(` Iteration ${i + 1}: ${latency.toFixed(2)}ms, hit=${result.hit}, source=${result.source}`);
|
||
|
|
} catch (e) {
|
||
|
|
console.log(` Iteration ${i + 1} error: ${e.message}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const avgLatency = latencies.length ? latencies.reduce((a, b) => a + b, 0) / latencies.length : 0;
|
||
|
|
const p50 = percentile(latencies, 50);
|
||
|
|
const p95 = percentile(latencies, 95);
|
||
|
|
const hitRate = hits.length ? hits.filter(h => h).length / hits.length : 0;
|
||
|
|
|
||
|
|
allResults.push({
|
||
|
|
name,
|
||
|
|
query,
|
||
|
|
avgLatency,
|
||
|
|
p50,
|
||
|
|
p95,
|
||
|
|
hitRate,
|
||
|
|
latencies
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log(` → Avg: ${avgLatency.toFixed(2)}ms, P95: ${p95.toFixed(2)}ms, Hit Rate: ${(hitRate * 100).toFixed(1)}%\n`);
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('='.repeat(80));
|
||
|
|
console.log('SUMMARY');
|
||
|
|
console.log('='.repeat(80));
|
||
|
|
|
||
|
|
const totalAvg = allResults.reduce((a, b) => a + b.avgLatency, 0) / allResults.length;
|
||
|
|
const totalP95 = percentile(allResults.flatMap(r => r.latencies), 95);
|
||
|
|
const totalHitRate = allResults.reduce((a, b) => a + b.hitRate, 0) / allResults.length;
|
||
|
|
|
||
|
|
console.log(`\nOverall Average Latency: ${totalAvg.toFixed(2)}ms`);
|
||
|
|
console.log(`Overall P95 Latency: ${totalP95.toFixed(2)}ms`);
|
||
|
|
console.log(`Overall Hit Rate: ${(totalHitRate * 100).toFixed(1)}%`);
|
||
|
|
|
||
|
|
console.log('\nTop 3 fastest queries:');
|
||
|
|
allResults.sort((a, b) => a.avgLatency - b.avgLatency).slice(0, 3).forEach((r, i) => {
|
||
|
|
console.log(` ${i + 1}. ${r.name}: ${r.avgLatency.toFixed(2)}ms`);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log('\nTop 3 slowest queries:');
|
||
|
|
allResults.sort((a, b) => b.avgLatency - a.avgLatency).slice(0, 3).forEach((r, i) => {
|
||
|
|
console.log(` ${i + 1}. ${r.name}: ${r.avgLatency.toFixed(2)}ms`);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log('\n' + '='.repeat(80));
|
||
|
|
|
||
|
|
return allResults;
|
||
|
|
}
|
||
|
|
|
||
|
|
function percentile(arr, p) {
|
||
|
|
if (arr.length === 0) return 0;
|
||
|
|
const sorted = [...arr].sort((a, b) => a - b);
|
||
|
|
const index = Math.ceil((p / 100) * sorted.length) - 1;
|
||
|
|
return sorted[Math.max(0, index)];
|
||
|
|
}
|
||
|
|
|
||
|
|
runRealKBTest().catch(console.error);
|