Files
AIclinicalresearch/backend/scripts/verify-llm-models.ts
HaHafeng 8eef9e0544 feat(asl): Complete Week 4 - Results display and Excel export with hybrid solution
Features:
- Backend statistics API (cloud-native Prisma aggregation)
- Results page with hybrid solution (AI consensus + human final decision)
- Excel export (frontend generation, zero disk write, cloud-native)
- PRISMA-style exclusion reason analysis with bar chart
- Batch selection and export (3 export methods)
- Fixed logic contradiction (inclusion does not show exclusion reason)
- Optimized table width (870px, no horizontal scroll)

Components:
- Backend: screeningController.ts - add getProjectStatistics API
- Frontend: ScreeningResults.tsx - complete results page (hybrid solution)
- Frontend: excelExport.ts - Excel export utility (40 columns full info)
- Frontend: ScreeningWorkbench.tsx - add navigation button
- Utils: get-test-projects.mjs - quick test tool

Architecture:
- Cloud-native: backend aggregation reduces network transfer
- Cloud-native: frontend Excel generation (zero file persistence)
- Reuse platform: global prisma instance, logger
- Performance: statistics API < 500ms, Excel export < 3s (1000 records)

Documentation:
- Update module status guide (add Week 4 features)
- Update task breakdown (mark Week 4 completed)
- Update API design spec (add statistics API)
- Update database design (add field usage notes)
- Create Week 4 development plan
- Create Week 4 completion report
- Create technical debt list

Test:
- End-to-end flow test passed
- All features verified
- Performance test passed
- Cloud-native compliance verified

Ref: Week 4 Development Plan
Scope: ASL Module MVP - Title Abstract Screening Results
Cloud-Native: Backend aggregation + Frontend Excel generation
2025-11-21 20:12:38 +08:00

105 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* LLM模型验证脚本
* 用于验证实际接入的是哪个版本的模型
*/
import { LLMFactory } from '../src/common/llm/adapters/LLMFactory.js';
import { logger } from '../src/common/logging/index.js';
const TEST_PROMPT = "请用一句话简单介绍你自己,包括你的模型名称和版本。";
async function verifyModel(modelType: string, expectedModel: string) {
console.log(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(`🔍 验证模型: ${modelType}`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
try {
const adapter = LLMFactory.getAdapter(modelType as any);
console.log(`✅ 适配器创建成功`);
console.log(` 模型名称: ${adapter.modelName}`);
console.log(` 期望模型: ${expectedModel}`);
console.log(` 匹配状态: ${adapter.modelName === expectedModel ? '✅ 正确' : '❌ 不匹配'}`);
console.log(`\n🚀 发送测试请求...`);
const startTime = Date.now();
const response = await adapter.chat([
{ role: 'user', content: TEST_PROMPT }
]);
const duration = Date.now() - startTime;
console.log(`\n📊 响应结果:`);
console.log(` 实际返回模型: ${response.model}`);
console.log(` 响应时间: ${duration}ms`);
console.log(` Token使用:`);
console.log(` - 输入: ${response.usage?.promptTokens || 0}`);
console.log(` - 输出: ${response.usage?.completionTokens || 0}`);
console.log(` - 总计: ${response.usage?.totalTokens || 0}`);
console.log(`\n💬 模型回复:`);
console.log(` "${response.content}"`);
// 验证是否匹配
if (response.model === expectedModel) {
console.log(`\n✅ 验证通过!实际调用的就是 ${expectedModel}`);
return true;
} else {
console.log(`\n⚠ 警告!期望 ${expectedModel},实际返回 ${response.model}`);
return false;
}
} catch (error) {
console.error(`\n❌ 验证失败:`, error);
return false;
}
}
async function main() {
console.log('\n🔬 ASL模块LLM模型验证工具');
console.log('=' .repeat(60));
console.log('用途: 验证实际接入的模型版本是否正确\n');
const models = [
{ type: 'deepseek-v3', expected: 'deepseek-chat', description: 'DeepSeek-V3' },
{ type: 'qwen3-72b', expected: 'qwen-max', description: 'Qwen最新最强模型' },
];
const results: { model: string; passed: boolean }[] = [];
for (const model of models) {
const passed = await verifyModel(model.type, model.expected);
results.push({ model: model.description, passed });
// 避免API限流
await new Promise(resolve => setTimeout(resolve, 2000));
}
// 总结
console.log('\n\n' + '='.repeat(60));
console.log('📊 验证总结');
console.log('='.repeat(60));
results.forEach(r => {
console.log(`${r.passed ? '✅' : '❌'} ${r.model}: ${r.passed ? '通过' : '未通过'}`);
});
const allPassed = results.every(r => r.passed);
if (allPassed) {
console.log('\n🎉 所有模型验证通过!');
} else {
console.log('\n⚠ 部分模型验证未通过,请检查配置!');
}
console.log('='.repeat(60) + '\n');
}
main().catch(console.error);