oh-my-knowledge 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -63
- package/README.zh.md +64 -62
- package/dist/src/analysis/report-diagnostics.d.ts +28 -3
- package/dist/src/analysis/report-diagnostics.d.ts.map +1 -1
- package/dist/src/analysis/report-diagnostics.js +201 -81
- package/dist/src/analysis/report-diagnostics.js.map +1 -1
- package/dist/src/analysis/sample-diagnostics.d.ts +9 -2
- package/dist/src/analysis/sample-diagnostics.d.ts.map +1 -1
- package/dist/src/analysis/sample-diagnostics.js +224 -25
- package/dist/src/analysis/sample-diagnostics.js.map +1 -1
- package/dist/src/authoring/evolver.d.ts +7 -2
- package/dist/src/authoring/evolver.d.ts.map +1 -1
- package/dist/src/authoring/evolver.js +43 -9
- package/dist/src/authoring/evolver.js.map +1 -1
- package/dist/src/authoring/generator.d.ts +24 -0
- package/dist/src/authoring/generator.d.ts.map +1 -1
- package/dist/src/authoring/generator.js +67 -5
- package/dist/src/authoring/generator.js.map +1 -1
- package/dist/src/cli/coverage-renderer.d.ts +15 -0
- package/dist/src/cli/coverage-renderer.d.ts.map +1 -0
- package/dist/src/cli/coverage-renderer.js +74 -0
- package/dist/src/cli/coverage-renderer.js.map +1 -0
- package/dist/src/cli/i18n-dict.d.ts +1 -1
- package/dist/src/cli/i18n-dict.d.ts.map +1 -1
- package/dist/src/cli/i18n-dict.js +62 -40
- package/dist/src/cli/i18n-dict.js.map +1 -1
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/{cli.js → cli/index.js} +123 -384
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/parse-run-config.d.ts +56 -0
- package/dist/src/cli/parse-run-config.d.ts.map +1 -0
- package/dist/src/cli/parse-run-config.js +195 -0
- package/dist/src/cli/parse-run-config.js.map +1 -0
- package/dist/src/cli/progress.d.ts +25 -0
- package/dist/src/cli/progress.d.ts.map +1 -0
- package/dist/src/cli/progress.js +62 -0
- package/dist/src/cli/progress.js.map +1 -0
- package/dist/src/cli/update-check.d.ts +3 -0
- package/dist/src/cli/update-check.d.ts.map +1 -0
- package/dist/src/cli/update-check.js +37 -0
- package/dist/src/cli/update-check.js.map +1 -0
- package/dist/src/eval-core/cache.d.ts +7 -5
- package/dist/src/eval-core/cache.d.ts.map +1 -1
- package/dist/src/eval-core/cache.js +11 -7
- package/dist/src/eval-core/cache.js.map +1 -1
- package/dist/src/eval-core/comparability.d.ts +11 -0
- package/dist/src/eval-core/comparability.d.ts.map +1 -0
- package/dist/src/eval-core/comparability.js +271 -0
- package/dist/src/eval-core/comparability.js.map +1 -0
- package/dist/src/eval-core/dependency-checker.d.ts +1 -1
- package/dist/src/eval-core/dependency-checker.js +1 -1
- package/dist/src/eval-core/evaluation-execution.d.ts +5 -2
- package/dist/src/eval-core/evaluation-execution.d.ts.map +1 -1
- package/dist/src/eval-core/evaluation-execution.js +29 -21
- package/dist/src/eval-core/evaluation-execution.js.map +1 -1
- package/dist/src/eval-core/evaluation-job.d.ts +2 -2
- package/dist/src/eval-core/evaluation-job.d.ts.map +1 -1
- package/dist/src/eval-core/evaluation-job.js +2 -2
- package/dist/src/eval-core/evaluation-job.js.map +1 -1
- package/dist/src/eval-core/evaluation-reporting.d.ts +3 -1
- package/dist/src/eval-core/evaluation-reporting.d.ts.map +1 -1
- package/dist/src/eval-core/evaluation-reporting.js +65 -5
- package/dist/src/eval-core/evaluation-reporting.js.map +1 -1
- package/dist/src/eval-core/execution-strategy.js +6 -6
- package/dist/src/eval-core/execution-strategy.js.map +1 -1
- package/dist/src/eval-core/schema.d.ts.map +1 -1
- package/dist/src/eval-core/schema.js +14 -1
- package/dist/src/eval-core/schema.js.map +1 -1
- package/dist/src/eval-core/verdict.d.ts +3 -3
- package/dist/src/eval-core/verdict.js +3 -3
- package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts +111 -0
- package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts.map +1 -0
- package/dist/src/eval-workflows/batch-evaluation-workflow.js +215 -0
- package/dist/src/eval-workflows/batch-evaluation-workflow.js.map +1 -0
- package/dist/src/eval-workflows/evaluation-pipeline.d.ts +7 -5
- package/dist/src/eval-workflows/evaluation-pipeline.d.ts.map +1 -1
- package/dist/src/eval-workflows/evaluation-pipeline.js +13 -8
- package/dist/src/eval-workflows/evaluation-pipeline.js.map +1 -1
- package/dist/src/eval-workflows/evaluation-preparation.d.ts +10 -8
- package/dist/src/eval-workflows/evaluation-preparation.d.ts.map +1 -1
- package/dist/src/eval-workflows/evaluation-preparation.js +8 -4
- package/dist/src/eval-workflows/evaluation-preparation.js.map +1 -1
- package/dist/src/eval-workflows/run-evaluation.d.ts +23 -20
- package/dist/src/eval-workflows/run-evaluation.d.ts.map +1 -1
- package/dist/src/eval-workflows/run-evaluation.js +34 -25
- package/dist/src/eval-workflows/run-evaluation.js.map +1 -1
- package/dist/src/executors/claude-cli.d.ts.map +1 -1
- package/dist/src/executors/claude-cli.js +12 -7
- package/dist/src/executors/claude-cli.js.map +1 -1
- package/dist/src/executors/claude-sdk.d.ts +1 -1
- package/dist/src/executors/claude-sdk.js +1 -1
- package/dist/src/executors/codex-cli-trace.d.ts +10 -0
- package/dist/src/executors/codex-cli-trace.d.ts.map +1 -0
- package/dist/src/executors/codex-cli-trace.js +123 -0
- package/dist/src/executors/codex-cli-trace.js.map +1 -0
- package/dist/src/executors/codex-cli.d.ts +18 -0
- package/dist/src/executors/codex-cli.d.ts.map +1 -0
- package/dist/src/executors/codex-cli.js +254 -0
- package/dist/src/executors/codex-cli.js.map +1 -0
- package/dist/src/executors/codex-sdk.d.ts +18 -0
- package/dist/src/executors/codex-sdk.d.ts.map +1 -0
- package/dist/src/executors/codex-sdk.js +214 -0
- package/dist/src/executors/codex-sdk.js.map +1 -0
- package/dist/src/executors/gemini.d.ts.map +1 -1
- package/dist/src/executors/gemini.js +28 -24
- package/dist/src/executors/gemini.js.map +1 -1
- package/dist/src/executors/index.d.ts.map +1 -1
- package/dist/src/executors/index.js +7 -2
- package/dist/src/executors/index.js.map +1 -1
- package/dist/src/executors/runtime-fingerprint.d.ts +7 -0
- package/dist/src/executors/runtime-fingerprint.d.ts.map +1 -0
- package/dist/src/executors/runtime-fingerprint.js +277 -0
- package/dist/src/executors/runtime-fingerprint.js.map +1 -0
- package/dist/src/executors/script.d.ts.map +1 -1
- package/dist/src/executors/script.js +48 -56
- package/dist/src/executors/script.js.map +1 -1
- package/dist/src/executors/shared.d.ts +78 -1
- package/dist/src/executors/shared.d.ts.map +1 -1
- package/dist/src/executors/shared.js +203 -1
- package/dist/src/executors/shared.js.map +1 -1
- package/dist/src/grading/assertions.d.ts.map +1 -1
- package/dist/src/grading/assertions.js +21 -6
- package/dist/src/grading/assertions.js.map +1 -1
- package/dist/src/grading/gold-dataset.d.ts +1 -1
- package/dist/src/grading/gold-dataset.js +1 -1
- package/dist/src/grading/index.d.ts.map +1 -1
- package/dist/src/grading/index.js +11 -0
- package/dist/src/grading/index.js.map +1 -1
- package/dist/src/grading/judge.d.ts.map +1 -1
- package/dist/src/grading/judge.js +75 -6
- package/dist/src/grading/judge.js.map +1 -1
- package/dist/src/inputs/eval-config.js +2 -2
- package/dist/src/inputs/eval-config.js.map +1 -1
- package/dist/src/inputs/load-samples.d.ts.map +1 -1
- package/dist/src/inputs/load-samples.js +30 -4
- package/dist/src/inputs/load-samples.js.map +1 -1
- package/dist/src/inputs/skill-loader.d.ts +2 -2
- package/dist/src/inputs/skill-loader.d.ts.map +1 -1
- package/dist/src/inputs/skill-loader.js +2 -2
- package/dist/src/inputs/skill-loader.js.map +1 -1
- package/dist/src/renderer/html-renderer.d.ts +5 -4
- package/dist/src/renderer/html-renderer.d.ts.map +1 -1
- package/dist/src/renderer/html-renderer.js +217 -93
- package/dist/src/renderer/html-renderer.js.map +1 -1
- package/dist/src/renderer/layout.d.ts +2 -1
- package/dist/src/renderer/layout.d.ts.map +1 -1
- package/dist/src/renderer/layout.js +30 -42
- package/dist/src/renderer/layout.js.map +1 -1
- package/dist/src/renderer/summary.d.ts +3 -3
- package/dist/src/renderer/summary.d.ts.map +1 -1
- package/dist/src/renderer/summary.js +232 -55
- package/dist/src/renderer/summary.js.map +1 -1
- package/dist/src/renderer/trends.d.ts.map +1 -1
- package/dist/src/renderer/trends.js +5 -3
- package/dist/src/renderer/trends.js.map +1 -1
- package/dist/src/server/report-server.js +4 -4
- package/dist/src/server/report-server.js.map +1 -1
- package/dist/src/server/report-store.d.ts +7 -5
- package/dist/src/server/report-store.d.ts.map +1 -1
- package/dist/src/server/report-store.js +39 -11
- package/dist/src/server/report-store.js.map +1 -1
- package/dist/src/types/eval.d.ts +27 -5
- package/dist/src/types/eval.d.ts.map +1 -1
- package/dist/src/types/executor.d.ts +5 -0
- package/dist/src/types/executor.d.ts.map +1 -1
- package/dist/src/types/judge.d.ts +10 -0
- package/dist/src/types/judge.d.ts.map +1 -1
- package/dist/src/types/report.d.ts +151 -29
- package/dist/src/types/report.d.ts.map +1 -1
- package/dist/src/types/storage.d.ts +7 -7
- package/dist/src/types/storage.d.ts.map +1 -1
- package/package.json +14 -5
- package/dist/src/cli.d.ts +0 -3
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js.map +0 -1
- package/dist/src/eval-workflows/each-evaluation-workflow.d.ts +0 -153
- package/dist/src/eval-workflows/each-evaluation-workflow.d.ts.map +0 -1
- package/dist/src/eval-workflows/each-evaluation-workflow.js +0 -178
- package/dist/src/eval-workflows/each-evaluation-workflow.js.map +0 -1
- package/dist/src/executors/openai-cli.d.ts +0 -3
- package/dist/src/executors/openai-cli.d.ts.map +0 -1
- package/dist/src/executors/openai-cli.js +0 -60
- package/dist/src/executors/openai-cli.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { e, fmtNum, fmtCost, fmtDuration, COLORS, t } from './layout.js';
|
|
2
|
+
import { generateAnalysisSummary } from '../analysis/report-diagnostics.js';
|
|
2
3
|
import { pValueCategory } from '../eval-core/statistics.js';
|
|
3
4
|
import { computeVerdict } from '../eval-core/verdict.js';
|
|
4
5
|
/**
|
|
@@ -10,19 +11,6 @@ import { computeVerdict } from '../eval-core/verdict.js';
|
|
|
10
11
|
* UNDERPOWERED / NOISE / CAUTIOUS — none of which are "ship" but none of which
|
|
11
12
|
* are "regress" either. SOLO is grey because it's an info pill, not a verdict.
|
|
12
13
|
*/
|
|
13
|
-
// v0.21 B.4 — verdict level → status icon. PROGRESS/REGRESS 用实心点强信号,
|
|
14
|
-
// CAUTIOUS 三角(警示),NOISE 空心圆(有信号但无效果),UNDERPOWERED 部分填充
|
|
15
|
-
// (不够数据),SOLO 描边圆(单变体非对比).
|
|
16
|
-
function levelIcon(level) {
|
|
17
|
-
switch (level) {
|
|
18
|
-
case 'PROGRESS': return '●';
|
|
19
|
-
case 'REGRESS': return '●';
|
|
20
|
-
case 'CAUTIOUS': return '▲';
|
|
21
|
-
case 'NOISE': return '◌';
|
|
22
|
-
case 'UNDERPOWERED': return '◔';
|
|
23
|
-
case 'SOLO': return '○';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
14
|
// v0.21 B.4 — verdict 一句话总结. 把 level 标签 + Δ 数字 + action 推荐 + 原因
|
|
27
15
|
// 压成一个完整的中文/英文句子, 用 variant 名直接说"X 比 Y 怎么样, 怎么办".
|
|
28
16
|
// 用户读完一句话就懂结论, 不需要先学 jargon (Δ / CI / NOISE / SHIP).
|
|
@@ -36,7 +24,7 @@ function verdictOneLine(level, lang, treatment, control) {
|
|
|
36
24
|
case 'CAUTIOUS': return `${t} 比 ${c} 略好 — 但建议再仔细看,差距很小或某层未达标`;
|
|
37
25
|
case 'REGRESS': return `${t} 比 ${c} 明显更差 — 不要发布`;
|
|
38
26
|
case 'NOISE': return `${t} 和 ${c} 没看出明显差别 — 可以多加几条用例再试`;
|
|
39
|
-
case 'UNDERPOWERED': return
|
|
27
|
+
case 'UNDERPOWERED': return `评测用例数太少,看不出 ${t} 和 ${c} 的差别 — 多跑几个再看`;
|
|
40
28
|
case 'SOLO': return `只跑了一组,需要加对照组才能对比`;
|
|
41
29
|
}
|
|
42
30
|
}
|
|
@@ -75,7 +63,7 @@ export function levelTooltip(level, lang) {
|
|
|
75
63
|
case 'REGRESS': return '实验组分数显著劣于对照组';
|
|
76
64
|
case 'CAUTIOUS': return '实验组略优于对照组,但差距小或某层未达 gate';
|
|
77
65
|
case 'NOISE': return '两组分数差距置信区间跨过 0,统计上分辨不出效果';
|
|
78
|
-
case 'UNDERPOWERED': return '
|
|
66
|
+
case 'UNDERPOWERED': return '评测用例数太少,需要多加几条再看';
|
|
79
67
|
case 'SOLO': return '只跑了一组,没做对比';
|
|
80
68
|
}
|
|
81
69
|
}
|
|
@@ -95,7 +83,7 @@ export function levelTooltip(level, lang) {
|
|
|
95
83
|
// 去掉旧版 headline 和 significance 的内容重复 (perPair[0].headline 是干净的
|
|
96
84
|
// Δ+CI 核心, headline 拼装版只在 SOLO mode 用).
|
|
97
85
|
//
|
|
98
|
-
// computeVerdict
|
|
86
|
+
// computeVerdict 在历史混合批量 report 上有 NPE 风险 (顶层 summary
|
|
99
87
|
// 缺 variant 数据时 evaluateLayerGates 访问 .avgFactScore 炸). 加 try/catch
|
|
100
88
|
// 让 renderer 不 crash, 改为静默 skip pill — 这是 v0.21 B.4 的 scope 范围,
|
|
101
89
|
// verdict.ts/layer-gates.ts 的 defensive 修复留作单独 task.
|
|
@@ -318,11 +306,11 @@ export function renderSaturationCurve(saturation, variants, lang) {
|
|
|
318
306
|
: `<p style="font-size:13px;color:var(--text-muted);margin:8px 0 0">${lang === 'zh' ? '提示:repeat ≥ 5 时才会输出饱和判定。当前数据只够画曲线,不足以下结论。' : 'Note: saturation verdict needs repeat ≥ 5. Current data plots the curve only.'}</p>`;
|
|
319
307
|
return `
|
|
320
308
|
<h2 style="margin-top:24px">${lang === 'zh' ? '饱和曲线 (Saturation curve)' : 'Saturation curve'}</h2>
|
|
321
|
-
<p style="font-size:13px;color:var(--text-secondary);margin:4px 0 12px">${lang === 'zh' ? '
|
|
309
|
+
<p style="font-size:13px;color:var(--text-secondary);margin:4px 0 12px">${lang === 'zh' ? '随累积评测用例数 N 增长的均值与 95% CI。CI 宽度衰减放缓即饱和——再多评测用例对结论无实质收益。' : 'Mean and 95% CI as cumulative N grows. When CI shrink rate flattens, the evidence has saturated — more samples buy little.'}</p>
|
|
322
310
|
<svg viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${width}px;height:auto;display:block">
|
|
323
311
|
${yTicks}
|
|
324
312
|
<text x="${padL - 36}" y="${padT + plotH / 2}" font-size="11" text-anchor="middle" fill="var(--text-muted)" transform="rotate(-90 ${padL - 36} ${padT + plotH / 2})">${lang === 'zh' ? '均值' : 'mean'}</text>
|
|
325
|
-
<text x="${padL + plotW / 2}" y="${height - 4}" font-size="11" text-anchor="middle" fill="var(--text-muted)">${lang === 'zh' ? '
|
|
313
|
+
<text x="${padL + plotW / 2}" y="${height - 4}" font-size="11" text-anchor="middle" fill="var(--text-muted)">${lang === 'zh' ? '累积评测用例数 N' : 'cumulative N'}</text>
|
|
326
314
|
${xTicks}
|
|
327
315
|
${seriesParts.join('\n')}
|
|
328
316
|
</svg>
|
|
@@ -374,10 +362,18 @@ export function renderSummaryCards(variants, summary, lang, variance) {
|
|
|
374
362
|
// LLM 评价层 cell
|
|
375
363
|
const judgeCell = renderLayerCell(vd?.byLayer?.judge?.mean, s.avgJudgeScore);
|
|
376
364
|
// Cost — only show execution cost (judge cost is tool overhead, not skill cost)
|
|
365
|
+
// execCostReported === false 时(如 codex executor)显示「—」并 tooltip 解释,
|
|
366
|
+
// 跟"真的花了 $0(全 cached / 短 prompt)"区分开。
|
|
377
367
|
const execCost = s.totalExecCostUSD || 0;
|
|
368
|
+
const costReported = s.execCostReported !== false;
|
|
378
369
|
const hasCost = execCost > 0 || (s.avgTotalTokens || 0) > 0;
|
|
370
|
+
const costUnreportedTooltip = lang === 'zh'
|
|
371
|
+
? 'executor 不报 USD 成本(如 codex CLI),无法估算'
|
|
372
|
+
: 'executor does not report USD cost (e.g. codex CLI); not measurable';
|
|
379
373
|
const costCell = hasCost
|
|
380
|
-
?
|
|
374
|
+
? (costReported
|
|
375
|
+
? `<td class="summary-cell"><div class="summary-value">${fmtCost(execCost)}</div><div class="summary-detail">${fmtNum(s.avgTotalTokens)} tokens/${t('tokPerReq', lang).replace('tokens/', '')}</div></td>`
|
|
376
|
+
: `<td class="summary-cell" title="${e(costUnreportedTooltip)}"><div class="summary-value" style="color:var(--text-muted)">${fmtCost(0, false)}</div><div class="summary-detail">${fmtNum(s.avgTotalTokens)} tokens/${t('tokPerReq', lang).replace('tokens/', '')}</div></td>`)
|
|
381
377
|
: `<td class="summary-cell"><span style="color:var(--text-muted)">N/A</span></td>`;
|
|
382
378
|
// Efficiency
|
|
383
379
|
const effDetails = [];
|
|
@@ -456,10 +452,10 @@ export function renderSummaryCards(variants, summary, lang, variance) {
|
|
|
456
452
|
return `<tr><td style="border-left:3px solid ${color};padding-left:12px"><strong>${e(v)}</strong></td>${factCell}${behaviorCell}${judgeCell}${costCell}${effCell}${stabCell}</tr>`;
|
|
457
453
|
}).join('');
|
|
458
454
|
const guideModalId = 'guide-six-dims';
|
|
459
|
-
const guideTitle = lang === 'zh' ? '如何阅读六维对比?' : 'How to read this
|
|
455
|
+
const guideTitle = lang === 'zh' ? '如何阅读六维对比?' : 'How to read this six-dimension comparison?';
|
|
460
456
|
const guideIntro = lang === 'zh'
|
|
461
457
|
? '每行是一个实验分组(Variant),六列分别衡量不同维度:'
|
|
462
|
-
: 'Each row is
|
|
458
|
+
: 'Each row is an experiment variant. Six columns measure independent dimensions:';
|
|
463
459
|
const icon = (emoji) => `<span aria-hidden="true">${emoji}</span>`;
|
|
464
460
|
// 维度分隔加粗(border-top 2px),让六维的视觉边界更明显。sub 缩进从 28 收到 22。
|
|
465
461
|
const dim = 'style="padding:12px 0 4px;border-top:2px solid var(--border);color:var(--text-primary);font-weight:600"';
|
|
@@ -469,10 +465,10 @@ export function renderSummaryCards(variants, summary, lang, variance) {
|
|
|
469
465
|
const sub = 'style="padding:2px 0 2px 22px;font-size:12px;color:var(--text-secondary);font-weight:500"';
|
|
470
466
|
const subDesc = 'style="padding:2px 0;font-size:12px;color:var(--text-muted)"';
|
|
471
467
|
const guideRows = lang === 'zh' ? `
|
|
472
|
-
<tr><td ${dimFirst}>${icon('📋')} <strong>事实</strong></td><td ${dimFirstDesc}
|
|
473
|
-
<tr><td ${dim}>${icon('🛠️')} <strong>行为</strong></td><td ${dimDesc}
|
|
474
|
-
<tr><td ${dim}>${icon('💬')} <strong>LLM 评价</strong></td><td ${dimDesc}>请一个 LLM
|
|
475
|
-
<tr><td ${dim}>${icon('💰')} <strong
|
|
468
|
+
<tr><td ${dimFirst}>${icon('📋')} <strong>事实</strong></td><td ${dimFirstDesc}>任务执行模型的输出说得对不对(事实声明层面)。靠规则断言判:关键词是否出现、JSON 格式是否合法等,答错了直接不给分。</td></tr>
|
|
469
|
+
<tr><td ${dim}>${icon('🛠️')} <strong>行为</strong></td><td ${dimDesc}>任务执行模型做事的过程有没有走对路。靠规则断言判:该调的工具有没有调、有没有超过轮次/成本上限。</td></tr>
|
|
470
|
+
<tr><td ${dim}>${icon('💬')} <strong>LLM 评价</strong></td><td ${dimDesc}>请一个 LLM 当评委,让它读任务执行模型的输出内容,按预先写好的评分规则(英文叫 rubric)打个 1-5 分。主观但能抓到规则断言判不了的"整体好不好"——比如回答是否清晰、有没有答非所问。</td></tr>
|
|
471
|
+
<tr><td ${dim}>${icon('💰')} <strong>执行成本</strong></td><td ${dimDesc}>任务执行模型跑这次评测花了多少 API 调用费。评委模型成本单独作为评测开销记录,不算进 skill 自身成本。</td></tr>
|
|
476
472
|
<tr><td ${dim}>${icon('⚡')} <strong>效率</strong></td><td ${dimDesc}>一次评测平均跑多久;附带轮次数和工具调用次数。</td></tr>
|
|
477
473
|
<tr><td ${dim}>${icon('🛡️')} <strong>稳定性</strong></td><td ${dimDesc}>同一份测试跑很多次,分数抖不抖。抖得越少越稳定。<strong>跑一次看不出稳定性</strong>——至少要 <code>--repeat ≥ 2</code>,不然显示"—"。</td></tr>
|
|
478
474
|
<tr><td ${sub}>稳定 / 较稳 / 波动大</td><td ${subDesc}>分数波动比例 <5% = 稳定 · 5~15% = 一般 · >15% = 波动大</td></tr>
|
|
@@ -480,10 +476,10 @@ export function renderSummaryCards(variants, summary, lang, variance) {
|
|
|
480
476
|
<tr><td ${sub}>CV</td><td ${subDesc}>分数抖动幅度占平均分的比例(例:CV 2% = 分数波动大约是平均分的 2%)</td></tr>
|
|
481
477
|
<tr><td ${sub}>95% CI</td><td ${subDesc}>如果跑无数次求平均,真实平均分有 95% 概率落在这个范围里——范围越窄,这次测出的均值越可信</td></tr>
|
|
482
478
|
` : `
|
|
483
|
-
<tr><td ${dimFirst}>${icon('📋')} <strong>Fact</strong></td><td ${dimFirstDesc}>Whether the model's output is factually correct. Checked by rule-based assertions — keyword matches, JSON schema validity, etc. Wrong = zero.</td></tr>
|
|
484
|
-
<tr><td ${dim}>${icon('🛠️')} <strong>Behavior</strong></td><td ${dimDesc}>Whether the model followed the right process. Checked by rule-based assertions — did it call the expected tools, stay within turn/cost limits.</td></tr>
|
|
485
|
-
<tr><td ${dim}>${icon('💬')} <strong>LLM judge</strong></td><td ${dimDesc}>A separate LLM acts as judge: it reads the
|
|
486
|
-
<tr><td ${dim}>${icon('💰')} <strong>
|
|
479
|
+
<tr><td ${dimFirst}>${icon('📋')} <strong>Fact</strong></td><td ${dimFirstDesc}>Whether the task execution model's output is factually correct. Checked by rule-based assertions — keyword matches, JSON schema validity, etc. Wrong = zero.</td></tr>
|
|
480
|
+
<tr><td ${dim}>${icon('🛠️')} <strong>Behavior</strong></td><td ${dimDesc}>Whether the task execution model followed the right process. Checked by rule-based assertions — did it call the expected tools, stay within turn/cost limits.</td></tr>
|
|
481
|
+
<tr><td ${dim}>${icon('💬')} <strong>LLM judge</strong></td><td ${dimDesc}>A separate LLM acts as judge: it reads the task execution model's output and scores it 1-5 against a predefined rubric. Subjective, but catches "overall feel" that rule-based assertions miss — e.g., whether the answer is clear, whether it's on-topic.</td></tr>
|
|
482
|
+
<tr><td ${dim}>${icon('💰')} <strong>Exec cost</strong></td><td ${dimDesc}>API cost for the task execution model. Judge model cost is tracked as evaluation overhead, not skill cost.</td></tr>
|
|
487
483
|
<tr><td ${dim}>${icon('⚡')} <strong>Efficiency</strong></td><td ${dimDesc}>Average time per evaluation, plus turn counts and tool call stats.</td></tr>
|
|
488
484
|
<tr><td ${dim}>${icon('🛡️')} <strong>Stability</strong></td><td ${dimDesc}>How much the score swings when you repeat the same test. Less swing = more stable. <strong>You can't measure stability from a single run</strong> — need <code>--repeat ≥ 2</code>, otherwise shows "—".</td></tr>
|
|
489
485
|
<tr><td ${sub}>Stable / Moderate / Variable</td><td ${subDesc}>Score swing as % of mean: <5% = Stable · 5~15% = Moderate · >15% = Variable</td></tr>
|
|
@@ -492,7 +488,7 @@ export function renderSummaryCards(variants, summary, lang, variance) {
|
|
|
492
488
|
<tr><td ${sub}>95% CI</td><td ${subDesc}>If you ran infinitely many times, the true mean has a 95% chance of falling in this range — narrower = you can trust the measured mean more</td></tr>
|
|
493
489
|
`;
|
|
494
490
|
return `
|
|
495
|
-
<h2 style="display:flex;align-items:center;gap:4px">${lang === 'zh' ? '六维对比' : '
|
|
491
|
+
<h2 style="display:flex;align-items:center;gap:4px">${lang === 'zh' ? '六维对比' : 'Six-Dimension Comparison'} <button type="button" class="hint-btn" onclick="openModal('${guideModalId}')" aria-label="${e(guideTitle)}" aria-haspopup="dialog">?</button></h2>
|
|
496
492
|
<div id="${guideModalId}" class="modal-overlay" role="dialog" aria-modal="true" aria-labelledby="${guideModalId}-title" onclick="if(event.target===this)closeModal('${guideModalId}')">
|
|
497
493
|
<div class="modal-content">
|
|
498
494
|
<div class="modal-header">
|
|
@@ -548,7 +544,7 @@ function renderJudgeAgreementBlock(variants, summary, lang) {
|
|
|
548
544
|
<th>${t('judgeModelsLabel', lang)}</th>
|
|
549
545
|
<th title="${t('pearsonDesc', lang)}">${t('pearsonLabel', lang)}</th>
|
|
550
546
|
<th title="${t('madDesc', lang)}">${t('madLabel', lang)}</th>
|
|
551
|
-
<th>${lang === 'zh' ? '
|
|
547
|
+
<th>${lang === 'zh' ? '评测用例数' : 'Samples'}</th>
|
|
552
548
|
<th>${lang === 'zh' ? 'Judge 对数' : 'Pairs'}</th>
|
|
553
549
|
</tr></thead>
|
|
554
550
|
<tbody>${rows}</tbody>
|
|
@@ -682,9 +678,12 @@ function getVariantMetricMean(variance, variant, key) {
|
|
|
682
678
|
return v.mean;
|
|
683
679
|
return v.byMetric?.[key]?.mean ?? null;
|
|
684
680
|
}
|
|
685
|
-
export function renderVarianceComparisons(variance, lang, layeredStatsOpen = false) {
|
|
681
|
+
export function renderVarianceComparisons(variance, lang, layeredStatsOpen = false, summary) {
|
|
686
682
|
if (!variance || !variance.comparisons || variance.comparisons.length === 0)
|
|
687
683
|
return '';
|
|
684
|
+
// 任一 variant 的 exec 或 judge cost 未报告 → cost 行跳过(显示「—」会跟"持平"难区分,
|
|
685
|
+
// 索性直接不渲染该指标行)。判 cost 列前看 summary,缺 summary 当全 reported 走旧路径。
|
|
686
|
+
const allCostReported = !summary || Object.values(summary).every((v) => v.execCostReported !== false && v.judgeCostReported !== false);
|
|
688
687
|
const modalId = 'guide-variance-comparisons';
|
|
689
688
|
const title = lang === 'zh' ? '方差与显著性' : 'Variance & Significance';
|
|
690
689
|
const guideTitle = lang === 'zh' ? '如何阅读这张表?' : 'How to read this table?';
|
|
@@ -830,6 +829,9 @@ export function renderVarianceComparisons(variance, lang, layeredStatsOpen = fal
|
|
|
830
829
|
// Collect available metric rows for this comparison
|
|
831
830
|
const availableMetrics = [];
|
|
832
831
|
for (const cfg of METRIC_CONFIGS) {
|
|
832
|
+
// cost 行:任一 variant 不报 cost 时跳过(数据是占位 0,显示"持平"误导)
|
|
833
|
+
if (cfg.key === 'cost' && !allCostReported)
|
|
834
|
+
continue;
|
|
833
835
|
const m = pickMetricFromComparison(comp, cfg.key);
|
|
834
836
|
if (m)
|
|
835
837
|
availableMetrics.push({ cfg, metric: m });
|
|
@@ -864,7 +866,7 @@ export function renderVarianceComparisons(variance, lang, layeredStatsOpen = fal
|
|
|
864
866
|
{ label: '显著性', desc: 't 检验结论,基于 p<0.05 阈值。回答"差异真不真",和效应量"差多大"互补' },
|
|
865
867
|
{ label: 'p 值', desc: '假设真的没差异时,观察到当前差距的概率。越小越可信。0.05 只是约定阈值', sub: true },
|
|
866
868
|
{ label: 't 值', desc: '均值差 ÷ 估计误差,需配合 df 和效应量解读,不能单独看', sub: true },
|
|
867
|
-
{ label: 'df 自由度', desc: '≈"
|
|
869
|
+
{ label: 'df 自由度', desc: '≈"有效评测用例数"。--repeat 3 时通常 2~4;想达到 20+ 需 --repeat 10+', sub: true },
|
|
868
870
|
];
|
|
869
871
|
const glossaryEn = [
|
|
870
872
|
{ label: 'Gap', desc: 'Cross-run mean winner + absolute difference (raw units)' },
|
|
@@ -947,7 +949,7 @@ function severityDot(severity) {
|
|
|
947
949
|
};
|
|
948
950
|
return `<span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:${color[severity] || 'var(--text-muted)'};margin-right:8px;flex-shrink:0;margin-top:6px"></span>`;
|
|
949
951
|
}
|
|
950
|
-
function renderSummaryStructured(summary) {
|
|
952
|
+
function renderSummaryStructured(summary, lang) {
|
|
951
953
|
const markerRegex = /【([^】]+)】/g;
|
|
952
954
|
const markers = [];
|
|
953
955
|
let match;
|
|
@@ -962,9 +964,17 @@ function renderSummaryStructured(summary) {
|
|
|
962
964
|
if (sections.length === 0) {
|
|
963
965
|
return `<div style="padding:14px 18px;font-size:13px;line-height:1.8;color:var(--text-secondary);background:var(--bg-surface);border-radius:var(--radius);border:1px solid var(--border)">${e(summary)}</div>`;
|
|
964
966
|
}
|
|
967
|
+
const labelMap = {
|
|
968
|
+
结论: { zh: '结论', en: 'Conclusion' },
|
|
969
|
+
Conclusion: { zh: '结论', en: 'Conclusion' },
|
|
970
|
+
'关键差异': { zh: '关键差异', en: 'Key differences' },
|
|
971
|
+
'Key differences': { zh: '关键差异', en: 'Key differences' },
|
|
972
|
+
综合洞察: { zh: '综合洞察', en: 'Synthesis' },
|
|
973
|
+
Synthesis: { zh: '综合洞察', en: 'Synthesis' },
|
|
974
|
+
};
|
|
965
975
|
const sectionHtml = sections.map((section) => `
|
|
966
976
|
<div style="display:flex;gap:12px;align-items:baseline">
|
|
967
|
-
<span style="flex-shrink:0;font-size:11px;font-weight:600;color:var(--text-muted);letter-spacing:0.03em;min-width:56px">${e(section.label)}</span>
|
|
977
|
+
<span style="flex-shrink:0;font-size:11px;font-weight:600;color:var(--text-muted);letter-spacing:0.03em;min-width:56px">${e(labelMap[section.label]?.[lang] || section.label)}</span>
|
|
968
978
|
<span style="color:var(--text-secondary);font-size:13px;line-height:1.7">${e(section.content)}</span>
|
|
969
979
|
</div>`).join('');
|
|
970
980
|
return `
|
|
@@ -972,24 +982,188 @@ function renderSummaryStructured(summary) {
|
|
|
972
982
|
${sectionHtml}
|
|
973
983
|
</div>`;
|
|
974
984
|
}
|
|
975
|
-
|
|
985
|
+
function asRecord(value) {
|
|
986
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
987
|
+
}
|
|
988
|
+
function asArray(value) {
|
|
989
|
+
return Array.isArray(value) ? value : [];
|
|
990
|
+
}
|
|
991
|
+
function num(value) {
|
|
992
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
993
|
+
}
|
|
994
|
+
function localizedInsightMessage(insight, report, lang) {
|
|
995
|
+
const details = asRecord(insight.details);
|
|
996
|
+
const detailItems = asArray(insight.details);
|
|
997
|
+
const totalSamples = report?.results?.length || detailItems.length || num(details.total) || 0;
|
|
998
|
+
const type = insight.type;
|
|
999
|
+
switch (type) {
|
|
1000
|
+
case 'low_discrimination_all_passed': {
|
|
1001
|
+
const count = detailItems.length;
|
|
1002
|
+
return lang === 'zh'
|
|
1003
|
+
? `${count} 个断言所有变体均通过,区分度低`
|
|
1004
|
+
: `${count} assertions passed for every variant, so they have low discrimination power`;
|
|
1005
|
+
}
|
|
1006
|
+
case 'low_discrimination_all_failed': {
|
|
1007
|
+
const count = detailItems.length;
|
|
1008
|
+
return lang === 'zh'
|
|
1009
|
+
? `${count} 个断言所有变体均失败,断言可能过严或配置有误`
|
|
1010
|
+
: `${count} assertions failed for every variant; they may be too strict or misconfigured`;
|
|
1011
|
+
}
|
|
1012
|
+
case 'uniform_scores': {
|
|
1013
|
+
const count = detailItems.length;
|
|
1014
|
+
return lang === 'zh'
|
|
1015
|
+
? `${count}/${totalSamples} 个评测用例在变体间分差 < 0.5,区分度较低`
|
|
1016
|
+
: `${count}/${totalSamples} samples differ by less than 0.5 across variants, so they have low discrimination power`;
|
|
1017
|
+
}
|
|
1018
|
+
case 'all_pass':
|
|
1019
|
+
return lang === 'zh'
|
|
1020
|
+
? '所有断言在所有变体上全部通过,断言可能过于宽松'
|
|
1021
|
+
: 'All assertions passed for all variants; the assertions may be too loose';
|
|
1022
|
+
case 'all_fail':
|
|
1023
|
+
return lang === 'zh'
|
|
1024
|
+
? '所有断言在所有变体上全部失败,请检查断言配置'
|
|
1025
|
+
: 'All assertions failed for all variants; check the assertion configuration';
|
|
1026
|
+
case 'suggest_repeat': {
|
|
1027
|
+
const variant = String(details.variant || 'variant');
|
|
1028
|
+
const min = num(details.min);
|
|
1029
|
+
const max = num(details.max);
|
|
1030
|
+
const range = min != null && max != null ? `${min}~${max}` : '';
|
|
1031
|
+
return lang === 'zh'
|
|
1032
|
+
? `${variant} 的分数跨度较大${range ? `(${range})` : ''},建议使用 --repeat 多轮评测`
|
|
1033
|
+
: `${variant} has a wide score range${range ? ` (${range})` : ''}; run with --repeat to measure variance`;
|
|
1034
|
+
}
|
|
1035
|
+
case 'low_tool_success_rate': {
|
|
1036
|
+
const variant = String(details.variant || 'variant');
|
|
1037
|
+
const rate = num(details.toolSuccessRate);
|
|
1038
|
+
const pct = rate != null ? `${(rate * 100).toFixed(0)}%` : 'low';
|
|
1039
|
+
return lang === 'zh'
|
|
1040
|
+
? `${variant} 的工具调用成功率仅 ${pct},可能存在工具选择或参数问题`
|
|
1041
|
+
: `${variant} has only ${pct} tool-call success, which may indicate tool-selection or parameter issues`;
|
|
1042
|
+
}
|
|
1043
|
+
case 'tool_permission_error': {
|
|
1044
|
+
const count = detailItems.length;
|
|
1045
|
+
return lang === 'zh'
|
|
1046
|
+
? `检测到 ${count} 次工具权限错误,实验结论可能被环境问题污染`
|
|
1047
|
+
: `${count} tool permission errors were detected; the conclusion may be contaminated by environment issues`;
|
|
1048
|
+
}
|
|
1049
|
+
case 'trace_integrity_gap': {
|
|
1050
|
+
const count = detailItems.length;
|
|
1051
|
+
return lang === 'zh'
|
|
1052
|
+
? `${count} 个 variant 的 trace 覆盖率低于 75%,报告可能不足以解释 agent 行为差异`
|
|
1053
|
+
: `${count} variants have trace coverage below 75%, so the report may not fully explain agent behavior differences`;
|
|
1054
|
+
}
|
|
1055
|
+
case 'agent_assertion_discrimination_low': {
|
|
1056
|
+
const total = num(details.total) || 0;
|
|
1057
|
+
const discriminative = num(details.discriminative) || 0;
|
|
1058
|
+
const pct = total > 0 ? Math.round((discriminative / total) * 100) : 0;
|
|
1059
|
+
return lang === 'zh'
|
|
1060
|
+
? `agent 断言区分度偏低,只有 ${pct}% 的断言真正拉开了变体差异`
|
|
1061
|
+
: `Agent assertion discrimination is low; only ${pct}% of assertions separate variants`;
|
|
1062
|
+
}
|
|
1063
|
+
case 'agent_assertion_discrimination_ok': {
|
|
1064
|
+
const total = num(details.total) || 0;
|
|
1065
|
+
const discriminative = num(details.discriminative) || 0;
|
|
1066
|
+
const pct = total > 0 ? Math.round((discriminative / total) * 100) : 0;
|
|
1067
|
+
return lang === 'zh'
|
|
1068
|
+
? `agent 断言区分度达标,${pct}% 的断言能区分变体差异`
|
|
1069
|
+
: `Agent assertion discrimination is healthy; ${pct}% of assertions separate variants`;
|
|
1070
|
+
}
|
|
1071
|
+
case 'efficiency_gap': {
|
|
1072
|
+
const variant = String(details.variant || 'variant');
|
|
1073
|
+
const baseline = String(details.baseline || 'baseline');
|
|
1074
|
+
return lang === 'zh'
|
|
1075
|
+
? `${variant} 与 ${baseline} 在效率维度存在明显差异`
|
|
1076
|
+
: `${variant} differs materially from ${baseline} on efficiency`;
|
|
1077
|
+
}
|
|
1078
|
+
case 'tool_count_gap': {
|
|
1079
|
+
const variant = String(details.variant || 'variant');
|
|
1080
|
+
const baseline = String(details.baseline || 'baseline');
|
|
1081
|
+
const baseTools = num(details.baseTools);
|
|
1082
|
+
const otherTools = num(details.otherTools);
|
|
1083
|
+
const delta = baseTools != null && otherTools != null ? Math.abs(otherTools - baseTools).toFixed(1) : '';
|
|
1084
|
+
return lang === 'zh'
|
|
1085
|
+
? `${variant} 与 ${baseline} 的工具调用次数差异明显${delta ? `(差 ${delta} 次)` : ''}`
|
|
1086
|
+
: `${variant} differs materially from ${baseline} in tool-call count${delta ? ` (${delta} calls apart)` : ''}`;
|
|
1087
|
+
}
|
|
1088
|
+
case 'high_cost_sample': {
|
|
1089
|
+
const count = detailItems.length;
|
|
1090
|
+
return lang === 'zh'
|
|
1091
|
+
? `${count} 个评测用例成本显著高于平均值`
|
|
1092
|
+
: `${count} samples cost materially more than average`;
|
|
1093
|
+
}
|
|
1094
|
+
default:
|
|
1095
|
+
return lang === 'zh'
|
|
1096
|
+
? `结构化诊断:${type}`
|
|
1097
|
+
: `Structured diagnostic: ${type}`;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
function localizedSuggestion(insight, lang) {
|
|
1101
|
+
switch (insight.type) {
|
|
1102
|
+
case 'low_discrimination_all_passed':
|
|
1103
|
+
return lang === 'zh'
|
|
1104
|
+
? '把全通过断言替换为能检测 skill 独有细节的断言,例如特定参数名、配置值或流程要求'
|
|
1105
|
+
: 'Replace always-passing assertions with checks for artifact-specific details, such as parameter names, config values, or workflow requirements';
|
|
1106
|
+
case 'low_discrimination_all_failed':
|
|
1107
|
+
return lang === 'zh'
|
|
1108
|
+
? '检查断言条件是否正确,或降低匹配要求,避免 broken 用例污染结论'
|
|
1109
|
+
: 'Check whether the assertion condition is correct, or relax the matcher to avoid broken samples contaminating the conclusion';
|
|
1110
|
+
case 'uniform_scores':
|
|
1111
|
+
return lang === 'zh'
|
|
1112
|
+
? '增加更有挑战性的评测用例,或把 rubric 写得更能区分优劣'
|
|
1113
|
+
: 'Add more challenging samples, or make the rubric more discriminative';
|
|
1114
|
+
case 'all_pass':
|
|
1115
|
+
return lang === 'zh'
|
|
1116
|
+
? '增加更严格的断言来区分不同变体的质量'
|
|
1117
|
+
: 'Add stricter assertions that can distinguish variant quality';
|
|
1118
|
+
case 'all_fail':
|
|
1119
|
+
return lang === 'zh'
|
|
1120
|
+
? '优先检查评测配置和断言目标,确认用例不是整体不可达'
|
|
1121
|
+
: 'Check the evaluation config and assertion target first; make sure the sample is reachable';
|
|
1122
|
+
case 'suggest_repeat':
|
|
1123
|
+
return lang === 'zh'
|
|
1124
|
+
? '使用 --repeat 3 或更多轮次获取方差、置信区间和显著性检验'
|
|
1125
|
+
: 'Run with --repeat 3 or more to obtain variance, confidence intervals, and significance tests';
|
|
1126
|
+
case 'low_tool_success_rate':
|
|
1127
|
+
return lang === 'zh'
|
|
1128
|
+
? '检查失败工具调用,必要时在 skill 中补充工具选择和参数约束'
|
|
1129
|
+
: 'Inspect failed tool calls and, if needed, add tool-selection and parameter guidance to the artifact';
|
|
1130
|
+
case 'tool_permission_error':
|
|
1131
|
+
return lang === 'zh'
|
|
1132
|
+
? '先解决工具权限或工作目录问题,再解读分数差异'
|
|
1133
|
+
: 'Fix tool permission or working-directory issues before interpreting score differences';
|
|
1134
|
+
case 'trace_integrity_gap':
|
|
1135
|
+
return lang === 'zh'
|
|
1136
|
+
? '补齐 turns、toolCalls、timing 和完整输出采集,确保报告能解释行为差异'
|
|
1137
|
+
: 'Capture turns, tool calls, timing, and full output so the report can explain behavior differences';
|
|
1138
|
+
case 'agent_assertion_discrimination_low':
|
|
1139
|
+
return lang === 'zh'
|
|
1140
|
+
? '重写 agent 断言时优先约束工具路径、关键文件读取和 turns 上限'
|
|
1141
|
+
: 'When rewriting agent assertions, prioritize tool path, key file reads, and turn-limit constraints';
|
|
1142
|
+
default:
|
|
1143
|
+
return lang === 'zh'
|
|
1144
|
+
? '查看结构化 details 字段定位原因'
|
|
1145
|
+
: 'Inspect the structured details field for the underlying evidence';
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
export function renderAnalysis(report, lang) {
|
|
1149
|
+
const analysis = report?.analysis;
|
|
976
1150
|
if (!analysis)
|
|
977
1151
|
return '';
|
|
978
|
-
const { insights
|
|
979
|
-
if ((!insights || insights.length === 0) &&
|
|
1152
|
+
const { insights } = analysis;
|
|
1153
|
+
if ((!insights || insights.length === 0) && !report)
|
|
980
1154
|
return '';
|
|
981
1155
|
const issues = (insights || []).filter((insight) => !isConclusion(insight));
|
|
982
1156
|
const issueLabel = lang === 'zh' ? '问题与建议' : 'Issues & Suggestions';
|
|
983
|
-
const safeSuggestions =
|
|
1157
|
+
const safeSuggestions = issues.map((issue) => localizedSuggestion(issue, lang));
|
|
984
1158
|
let issuesHtml = '';
|
|
985
|
-
if (issues.length > 0
|
|
986
|
-
const maxRows =
|
|
1159
|
+
if (issues.length > 0) {
|
|
1160
|
+
const maxRows = issues.length;
|
|
987
1161
|
const rows = [];
|
|
988
1162
|
for (let i = 0; i < maxRows; i++) {
|
|
989
1163
|
const issue = issues[i];
|
|
990
1164
|
const suggestion = safeSuggestions[i];
|
|
991
1165
|
const issueContent = issue
|
|
992
|
-
? `${severityDot(issue.severity)}<span>${e(issue
|
|
1166
|
+
? `${severityDot(issue.severity)}<span>${e(localizedInsightMessage(issue, report, lang))}</span>`
|
|
993
1167
|
: '';
|
|
994
1168
|
const suggestionContent = suggestion
|
|
995
1169
|
? e(suggestion)
|
|
@@ -1013,9 +1187,12 @@ export function renderAnalysis(analysis, lang) {
|
|
|
1013
1187
|
</div>
|
|
1014
1188
|
`;
|
|
1015
1189
|
}
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1190
|
+
const generatedSummary = report ? generateAnalysisSummary(report, lang) : undefined;
|
|
1191
|
+
const summaryHtml = generatedSummary
|
|
1192
|
+
? renderSummaryStructured(generatedSummary, lang)
|
|
1018
1193
|
: '';
|
|
1194
|
+
if (!summaryHtml && !issuesHtml)
|
|
1195
|
+
return '';
|
|
1019
1196
|
return `
|
|
1020
1197
|
<h2 data-i18n="autoAnalysis">${t('autoAnalysis', lang)}</h2>
|
|
1021
1198
|
${summaryHtml}
|
|
@@ -1168,8 +1345,8 @@ export function renderKnowledgeInteractionSection(coverage, gapReports, lang) {
|
|
|
1168
1345
|
return '';
|
|
1169
1346
|
const title = lang === 'zh' ? '本次测评:测试用例 × 知识库' : 'This Evaluation: Test Set × Knowledge Base';
|
|
1170
1347
|
const desc = lang === 'zh'
|
|
1171
|
-
? '展示本次测评用例和知识库的交互画像——用到哪些知识(使用情况)·
|
|
1172
|
-
: 'How this test set interacts with the KB — which knowledge was exercised (usage) · which
|
|
1348
|
+
? '展示本次测评用例和知识库的交互画像——用到哪些知识(使用情况)· 哪些知识想找但没找到或任务执行模型表达不确定(盲区)。'
|
|
1349
|
+
: 'How this test set interacts with the KB — which knowledge was exercised (usage) · which knowledge the task execution model missed or flagged as uncertain (gaps).';
|
|
1173
1350
|
const readHint = lang === 'zh'
|
|
1174
1351
|
? '💡 读表:两者同时高 → 知识库内容有问题(有文件但答不出)· 同时低 → 测评用例太浅(没触到复杂场景)· 使用高 + 盲区低 → 理想但警惕用例驯化'
|
|
1175
1352
|
: '💡 Read together: both high → KB content issues (files exist but can\'t answer) · both low → test set too shallow · high use + low gap → ideal, but beware sample-set overfitting';
|
|
@@ -1180,7 +1357,7 @@ export function renderKnowledgeInteractionSection(coverage, gapReports, lang) {
|
|
|
1180
1357
|
]));
|
|
1181
1358
|
const signalTypeLabels = {
|
|
1182
1359
|
failed_search: { zh: '搜索未命中', en: 'Search miss' },
|
|
1183
|
-
explicit_marker: { zh: '
|
|
1360
|
+
explicit_marker: { zh: '任务执行模型标记缺口', en: 'Execution model flag' },
|
|
1184
1361
|
hedging: { zh: '表达不确定', en: 'Hedging' },
|
|
1185
1362
|
repeated_failure: { zh: '反复未命中', en: 'Repeated miss' },
|
|
1186
1363
|
};
|
|
@@ -1274,7 +1451,7 @@ export function renderKnowledgeInteractionSection(coverage, gapReports, lang) {
|
|
|
1274
1451
|
const softShare = pct - weightedPct;
|
|
1275
1452
|
const weightedHint = lang === 'zh'
|
|
1276
1453
|
? (softShare >= 10
|
|
1277
|
-
? `<strong>实际盲区 ${weightedPct}%</strong> · 另 ${softShare}%
|
|
1454
|
+
? `<strong>实际盲区 ${weightedPct}%</strong> · 另 ${softShare}% 为任务执行模型表达不确定(软信号,建议对照清单复核)`
|
|
1278
1455
|
: `<strong>实际盲区 ${weightedPct}%</strong> · 主要来自确定的搜索未命中`)
|
|
1279
1456
|
: (softShare >= 10
|
|
1280
1457
|
? `<strong>real gaps ${weightedPct}%</strong> · another ${softShare}% is hedging (review list below)`
|
|
@@ -1297,7 +1474,7 @@ export function renderKnowledgeInteractionSection(coverage, gapReports, lang) {
|
|
|
1297
1474
|
? `<div style="font-size:var(--fs-micro);color:var(--text-muted);margin-top:6px">${lang === 'zh' ? `另 ${gap.signals.length - INVENTORY_CAP} 条未展示` : `+${gap.signals.length - INVENTORY_CAP} more not shown`}</div>`
|
|
1298
1475
|
: '';
|
|
1299
1476
|
const detailsLabel = lang === 'zh'
|
|
1300
|
-
? `展开 ${gap.signals.length} 条证据(按严重度上色: 红=确定 /
|
|
1477
|
+
? `展开 ${gap.signals.length} 条证据(按严重度上色: 红=确定 / 黄=执行模型自述 / 灰=犹豫)`
|
|
1301
1478
|
: `Show all ${gap.signals.length} evidence items (red=confirmed · yellow=self-flagged · gray=hedging)`;
|
|
1302
1479
|
gapInner = `
|
|
1303
1480
|
<div class="ki-col-header">
|
|
@@ -1307,7 +1484,7 @@ export function renderKnowledgeInteractionSection(coverage, gapReports, lang) {
|
|
|
1307
1484
|
<div class="ki-bar" role="progressbar" aria-valuenow="${pct}" aria-valuemin="0" aria-valuemax="100" aria-label="${e(barLabel)}">
|
|
1308
1485
|
<div class="ki-bar-fill" style="width:${barW}%;background:${pctColor}"></div>
|
|
1309
1486
|
</div>
|
|
1310
|
-
<div style="font-size:11px;color:var(--text-muted);margin-bottom:4px">${gap.samplesWithGap}/${gap.sampleCount} ${lang === 'zh' ? '
|
|
1487
|
+
<div style="font-size:11px;color:var(--text-muted);margin-bottom:4px">${gap.samplesWithGap}/${gap.sampleCount} ${lang === 'zh' ? '个评测用例出现搜索未命中或表达不确定' : 'samples with search miss / hedging'}</div>
|
|
1311
1488
|
<div style="font-size:var(--fs-detail);color:var(--text-secondary);margin-bottom:8px">${weightedHint}</div>
|
|
1312
1489
|
${typeBadges ? `<div>${typeBadges}</div>` : ''}
|
|
1313
1490
|
${inventory ? `<details class="ki-details"><summary>${detailsLabel}</summary>
|
|
@@ -1356,11 +1533,11 @@ export function renderGapSection(gapReports, lang) {
|
|
|
1356
1533
|
return '';
|
|
1357
1534
|
const title = lang === 'zh' ? '本次测评的知识盲区' : 'Knowledge gaps in this evaluation';
|
|
1358
1535
|
const desc = lang === 'zh'
|
|
1359
|
-
? '
|
|
1360
|
-
: 'Which knowledge the model tried to find but missed, or expressed uncertainty about. High numbers do not necessarily mean the KB is incomplete — the test set may be asking about areas the KB never covered.';
|
|
1536
|
+
? '本次测评中,哪些知识想找但没找到、或任务执行模型表达不确定。数字高不一定代表知识库不全——也可能是测试用例问的领域知识库未覆盖。'
|
|
1537
|
+
: 'Which knowledge the task execution model tried to find but missed, or expressed uncertainty about. High numbers do not necessarily mean the KB is incomplete — the test set may be asking about areas the KB never covered.';
|
|
1361
1538
|
const signalTypeLabels = {
|
|
1362
1539
|
failed_search: { zh: '搜索未命中', en: 'Search miss' },
|
|
1363
|
-
explicit_marker: { zh: '
|
|
1540
|
+
explicit_marker: { zh: '任务执行模型标记缺口', en: 'Execution model flag' },
|
|
1364
1541
|
hedging: { zh: '表达不确定', en: 'Hedging' },
|
|
1365
1542
|
repeated_failure: { zh: '反复未命中', en: 'Repeated miss' },
|
|
1366
1543
|
};
|
|
@@ -1377,7 +1554,7 @@ export function renderGapSection(gapReports, lang) {
|
|
|
1377
1554
|
const softSignalShare = pct - weightedPct;
|
|
1378
1555
|
const weightedHint = lang === 'zh'
|
|
1379
1556
|
? (softSignalShare >= 10
|
|
1380
|
-
? `<strong>实际盲区 ${weightedPct}%</strong> · 另外 ${softSignalShare}%
|
|
1557
|
+
? `<strong>实际盲区 ${weightedPct}%</strong> · 另外 ${softSignalShare}% 为任务执行模型表达不确定(软信号,建议对照右侧清单复核)`
|
|
1381
1558
|
: `<strong>实际盲区 ${weightedPct}%</strong> · 主要来自确定的搜索未命中`)
|
|
1382
1559
|
: (softSignalShare >= 10
|
|
1383
1560
|
? `<strong>real gaps ${weightedPct}%</strong> · another ${softSignalShare}% is hedging (soft signals — review the list on the right)`
|
|
@@ -1423,7 +1600,7 @@ export function renderGapSection(gapReports, lang) {
|
|
|
1423
1600
|
<div style="width:${barW}%;height:100%;background:${pctColor};border-radius:4px"></div>
|
|
1424
1601
|
</div>
|
|
1425
1602
|
<div style="font-size:var(--fs-detail);color:var(--text-muted);margin-bottom:4px">
|
|
1426
|
-
${report.samplesWithGap} / ${report.sampleCount} ${lang === 'zh' ? '
|
|
1603
|
+
${report.samplesWithGap} / ${report.sampleCount} ${lang === 'zh' ? '个评测用例出现搜索未命中或表达不确定' : 'samples with search miss or hedging'}
|
|
1427
1604
|
</div>
|
|
1428
1605
|
<div style="font-size:var(--fs-detail);color:var(--text-secondary);margin-bottom:10px">${weightedHint}</div>
|
|
1429
1606
|
${typeBadges ? `<div style="margin-bottom:10px">${typeBadges}</div>` : ''}
|