#!/usr/bin/env node 'use strict'; // RAG 检索评测:不调 LLM,只验证 search_kb 的 top 命中。 const fs = require('fs'); const path = require('path'); const { loadConfig } = require('../bridge/src/config'); const { createRetriever } = require('../bridge/src/rag'); const ROOT = path.resolve(__dirname, '..'); const env = {}; for (const line of fs.readFileSync(path.join(ROOT, '.env'), 'utf8').split('\n')) { if (!line.includes('=') || line.trim().startsWith('#')) continue; const i = line.indexOf('='); env[line.slice(0, i).trim()] = line.slice(i + 1).trim(); } const cfg = loadConfig({ ...env, ...process.env }); if (!cfg.ragPgUrl) throw new Error('RAG_PG_URL is not configured'); const CASES = [ ['minimum order value', 'minimum order'], ['how to request a refund', 'refund'], ['shipping costs', 'shipping cost'], ['pre order', 'pre-order'], ['factory direct MOQ', 'minimum order quantity'], ['membership discount', 'membership'], ['VAT refund', 'vat'], ['jewelry discolor', 'discolor'], ['最低起订量', 'minimum order'], ]; (async () => { const retriever = createRetriever(cfg); let failed = 0; for (const [query, expected] of CASES) { const hits = await retriever.searchKB(query, 5); const ok = hits.some((h) => `${h.question} ${h.answer}`.toLowerCase().includes(expected.toLowerCase())); if (!ok) failed += 1; console.log(`${ok ? 'PASS' : 'FAIL'} ${query} -> ${expected} ${ok ? '' : JSON.stringify(hits.map((h) => h.question).slice(0, 3))}`); } console.log(`\n${CASES.length - failed}/${CASES.length} passed`); await retriever.pool.end().catch(() => {}); process.exit(failed ? 1 : 0); })().catch((err) => { console.error('[eval-retrieval]', err.message); process.exit(1); });