From b26c2258cfddb07d2d85040108576e202e5fe13d Mon Sep 17 00:00:00 2001 From: let5sne Date: Fri, 10 Jul 2026 00:19:48 +0800 Subject: [PATCH] test(aihr): tighten demo question verification --- docs/20260708/发布会演示候选题单.md | 2 +- scripts/verify-demo-questions.mjs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/20260708/发布会演示候选题单.md b/docs/20260708/发布会演示候选题单.md index 4609fc58..ee84dc21 100644 --- a/docs/20260708/发布会演示候选题单.md +++ b/docs/20260708/发布会演示候选题单.md @@ -57,7 +57,7 @@ | E17 | 印章管理 | 社区活动要盖章,生活顾问或项目应该怎么申请和留痕? | `南京银城物业服务有限公司印章管理办法.pdf` | 行政制度 | | E18 | 公车管理 | 项目借用公车或发生车辆事故,需要注意哪些审批和登记? | `南京银城物业服务有限公司公车管理制度.pdf` | 行政制度 | | E19 | 档案管理 | 项目档案归档、借阅、移交时有哪些要求? | `南京银城物业服务有限公司档案管理制度.pdf` | 行政制度 | -| E20 | 信息安全 | 业主电话、客户资料能不能随便发到微信群,生活顾问应注意什么? | `信息安全管理培训.pptx` | 红线测试 | +| E20 | 信息安全 | 生活顾问能不能泄露客户资料或隐私,哪些行为属于价值观红线? | `人事规章制度修订-BI规范&人事规章制度.pptx` | 红线测试 | | E21 | 员工自助 | 员工自助系统里常见人事、考勤事项应该怎么操作? | `员工自助操作手册2025_10.pdf` | 员工支持 | | E22 | 职业安全 | 一线员工在现场作业中有哪些职业安全要求? | `员工职业安全(潘晓丽)25.3.13.pptx` | 员工支持 | | E23 | 租售业务 | 生活顾问遇到业主咨询租售业务时,如何记录和跟进? | `租售业务培训(住宅)250305(1).pptx` | 非物业务 | diff --git a/scripts/verify-demo-questions.mjs b/scripts/verify-demo-questions.mjs index 9b689ebd..fda7fe9f 100755 --- a/scripts/verify-demo-questions.mjs +++ b/scripts/verify-demo-questions.mjs @@ -11,6 +11,7 @@ const args = new Map(process.argv.slice(2).map((arg) => { })); const baseUrl = args.get('base-url') || process.env.AIHR_BASE_URL || 'https://wygj-api.localhost'; +const verbose = args.has('verbose'); const parsedBaseUrl = new URL(baseUrl); if (parsedBaseUrl.protocol === 'https:' && parsedBaseUrl.hostname.endsWith('.localhost') && !process.env.NODE_EXTRA_CA_CERTS) { // ponytail: local portless CA is not visible to Node fetch; only relax TLS for .localhost dev verification. @@ -18,6 +19,7 @@ if (parsedBaseUrl.protocol === 'https:' && parsedBaseUrl.hostname.endsWith('.loc } const file = path.resolve(root, args.get('file') || 'docs/20260708/发布会演示候选题单.md'); const prefixes = (args.get('prefix') || 'Q').split(',').map((item) => item.trim()).filter(Boolean); +const ids = new Set((args.get('ids') || '').split(',').map((item) => item.trim()).filter(Boolean)); const limit = Number(args.get('limit') || 0); function readEnv(filePath) { @@ -130,6 +132,7 @@ function parseQuestions(markdown) { if (!line.startsWith('|')) continue; const cells = line.split('|').slice(1, -1).map((cell) => cell.trim()); if (cells.length < 5 || !/^[A-Z]\d+$/u.test(cells[0])) continue; + if (ids.size && !ids.has(cells[0])) continue; if (!prefixes.some((prefix) => cells[0].startsWith(prefix))) continue; rows.push({ id: cells[0], @@ -150,6 +153,13 @@ function hasExpectedSource(result, expectedSources) { return expectedSources.some((source) => haystack.includes(source.replace(/\s+/g, ' ').trim())); } +function evidenceTitles(result) { + return [ + ...(result.docs || []).map((item) => item.title || item.docName || item.name || ''), + ...(result.snippets || []).map((item) => item.title || item.docName || item.name || '') + ].filter(Boolean); +} + const questions = parseQuestions(fs.readFileSync(file, 'utf8')); if (!questions.length) { console.error(`FAIL: no questions found in ${file} for prefix ${prefixes.join(',')}`); @@ -187,8 +197,14 @@ for (const item of questions) { if (!sourceOk) { warned += 1; console.log(`WARN ${item.id} ${item.scene}: answered, but top evidence missed listed source`); + if (verbose) { + console.log(` evidence: ${evidenceTitles(data).join(' | ') || '-'}`); + } } else { console.log(`OK ${item.id} ${item.scene}`); + if (verbose) { + console.log(` evidence: ${evidenceTitles(data).join(' | ') || '-'}`); + } } }