From bf89269c11013896698e363ea535bd5fae150945 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Wed, 21 Oct 2026 19:32:38 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=84=E6=B5=8B=E5=89=8D=E7=AB=AF=EF=BC=9A?= =?UTF-8?q?=E5=8F=98=E4=BD=93=E9=87=8C=E8=83=BD=E9=80=89=E3=80=8C=E5=88=86?= =?UTF-8?q?=E6=9E=90=E5=B7=A5=E5=85=B7=E3=80=8D=E5=BC=80=20/=20=E5=85=B3?= =?UTF-8?q?=EF=BC=8C=E5=8F=91=E8=B5=B7=E8=AF=84=E6=B5=8B=E5=A4=9A=E4=B8=80?= =?UTF-8?q?=E7=A7=8D=E3=80=8C=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E5=AF=B9=E7=85=A7=E3=80=8D=E3=80=82typesEval=20?= =?UTF-8?q?=E5=8A=A0=20EvalAnalysisTools=E3=80=81EvalPreset=EF=BC=8CEvalVa?= =?UTF-8?q?riant=20=E5=A4=9A=20analysis=EF=BC=9BtermsEval=20=E5=8A=A0?= =?UTF-8?q?=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E7=9A=84=E5=8F=AB=E6=B3=95?= =?UTF-8?q?=E3=80=81=E6=8F=90=E7=A4=BA=E5=92=8C=E8=BF=99=E7=A7=8D=E5=AF=B9?= =?UTF-8?q?=E7=85=A7=E7=9A=84=E8=AF=B4=E6=98=8E=EF=BC=8C=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E3=80=8C=E9=83=BD=E6=B2=A1=E5=8F=98=E3=80=8D=E9=82=A3=E5=8F=A5?= =?UTF-8?q?=E5=B8=A6=E4=B8=8A=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E3=80=82?= =?UTF-8?q?StartDialog=EF=BC=9AArmFields=20=E5=A4=9A=E4=B8=80=E6=A0=BC?= =?UTF-8?q?=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=EF=BC=88=E9=A2=98=E9=9B=86?= =?UTF-8?q?=E7=9A=84=E9=BB=98=E8=AE=A4=E5=8F=98=E4=BD=93=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E5=BC=A0=E8=A1=A8=E5=8D=95=EF=BC=89=EF=BC=8C=E9=A2=84=E8=AE=BE?= =?UTF-8?q?=E5=AF=B9=E7=85=A7=E9=87=8C=E7=94=B1=E9=A2=84=E8=AE=BE=E5=AE=9A?= =?UTF-8?q?=E7=9A=84=E9=82=A3=E4=B8=80=E9=A1=B9=E4=B8=8D=E6=91=86=EF=BC=88?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E8=B4=A1=E7=8C=AE=E4=B8=8D=E6=91=86=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E3=80=81=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E4=B8=8D=E6=91=86=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=EF=BC=89=EF=BC=9B=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E5=AF=B9=E7=85=A7=E4=BA=A4=20{preset:=20analysis=5Fto?= =?UTF-8?q?ols,=20variant}=EF=BC=8C=E5=8F=98=E4=BD=93=E9=87=8C=E4=B8=8D?= =?UTF-8?q?=E5=B8=A6=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7=E5=92=8C=E5=90=8D?= =?UTF-8?q?=E5=AD=97=EF=BC=8C=E7=BC=BA=E7=9C=81=E6=AF=8F=E9=A2=98=203=20?= =?UTF-8?q?=E6=AC=A1=E3=80=82=E7=BB=93=E6=9E=9C=E9=A1=B5=E3=80=81=E5=AF=B9?= =?UTF-8?q?=E6=AF=94=E9=A1=B5=E3=80=81A/B=20=E7=85=A7=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E5=8F=98=E4=BD=93=E9=82=A3=E4=B8=80=E5=8F=A5?= =?UTF-8?q?=E5=92=8C=E6=8C=87=E7=BA=B9=E5=B7=AE=E5=BC=82=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E3=80=82check-evals=EF=BC=9A=E5=8F=91=E8=B5=B7=E6=97=B6?= =?UTF-8?q?=E8=AF=84=E4=B8=80=E6=AC=A1=E9=80=89=E3=80=8C=E5=85=B3=E3=80=8D?= =?UTF-8?q?=E3=80=81=E4=B8=A4=E7=A7=8D=E9=A2=84=E8=AE=BE=E7=9A=84=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E4=BD=93=E5=92=8C=E4=BC=B0=E7=AE=97=E7=9A=84=E4=B8=A4?= =?UTF-8?q?=E8=87=82=EF=BC=8C=E5=AF=B9=E6=AF=94=E5=86=99=E3=80=8C=E5=88=86?= =?UTF-8?q?=E6=9E=90=E5=B7=A5=E5=85=B7=EF=BC=9A=E5=BC=80=20=E2=86=92=20?= =?UTF-8?q?=E5=85=B3=E3=80=8D=EF=BC=8C=E5=88=86=E6=9E=90=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E5=AF=B9=E7=85=A7=E7=9A=84=E4=B8=A4=E8=87=82?= =?UTF-8?q?=E5=92=8C=E8=AF=A6=E6=83=85=E9=A1=B5=E5=A4=B4=EF=BC=9Btest=5Ffr?= =?UTF-8?q?ontend=5Feval=5Funions=20=E5=AF=B9=E4=B8=8A=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=9A=84=E5=8F=96=E5=80=BC=E3=80=81=E5=8F=AB?= =?UTF-8?q?=E6=B3=95=E5=92=8C=E9=A2=84=E8=AE=BE=E5=AF=B9=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/tests/test_frontend_eval_unions.py | 11 +++++ frontend/src/lib/termsEval.ts | 18 ++++--- frontend/src/pages/evals/StartDialog.tsx | 37 ++++++++++---- frontend/src/typesEval.ts | 13 +++-- scripts/check-evals.mjs | 56 +++++++++++++++++++--- 5 files changed, 109 insertions(+), 26 deletions(-) diff --git a/backend/tests/test_frontend_eval_unions.py b/backend/tests/test_frontend_eval_unions.py index 4c79c18c..4fc167a3 100644 --- a/backend/tests/test_frontend_eval_unions.py +++ b/backend/tests/test_frontend_eval_unions.py @@ -92,6 +92,17 @@ def test_scores_compare_and_catalog_modes(): assert _labels("start.catalogMode") == list(CATALOG_MODES) +def test_analysis_tools_and_presets_follow_the_server(): + """变体的分析工具开、关和预设对照(api/evals.PRESETS):前端的取值和服务端一一对上。叫法写「开」「关」,和服务端 + describe、对比里写的同一种说法。""" + from app.api.evals import PRESETS + from app.eval.variants import ANALYSIS_TOOLS, ANALYSIS_TOOLS_LABEL + + assert _union("EvalAnalysisTools") == list(ANALYSIS_TOOLS) + assert _pairs("start.analysisToolsMode") == list(ANALYSIS_TOOLS_LABEL.items()) + assert _union("EvalPreset") == list(PRESETS) + + def test_signal_bands_follow_the_server(): from app.api.evals import SIGNAL_CRITERIA diff --git a/frontend/src/lib/termsEval.ts b/frontend/src/lib/termsEval.ts index a3a5d615..24c7583f 100644 --- a/frontend/src/lib/termsEval.ts +++ b/frontend/src/lib/termsEval.ts @@ -5,9 +5,9 @@ * 统计、结论、能不能做都由服务端给,这里只有叫法和句式:数字一律是服务端算好交来的,这里只负责写成话。 */ import type { - EvalAnalysisMode, EvalAnalysisOp, EvalCatalogMode, EvalCause, EvalE1Band, EvalE3Band, EvalExpectationKind, EvalGoldKind, - EvalJudgement, EvalOutcome, EvalPath, EvalRate, EvalStatus, EvalTextOutcome, EvalTransition, EvalTrialStatus, EvalTrigger, - EvalUpgradePolicy, EvalVerdict, + EvalAnalysisMode, EvalAnalysisOp, EvalAnalysisTools, EvalCatalogMode, EvalCause, EvalE1Band, EvalE3Band, EvalExpectationKind, + EvalGoldKind, EvalJudgement, EvalOutcome, EvalPath, EvalRate, EvalStatus, EvalTextOutcome, EvalTransition, EvalTrialStatus, + EvalTrigger, EvalUpgradePolicy, EvalVerdict, } from '../typesEval' import { formatCost, formatNumber } from './format' @@ -380,12 +380,15 @@ export const EVAL_TEXT = { start: { title: '发起评测', mode: '评测方式', - modes: { single: '评一次', ab: 'A/B 对照', catalog: '目录贡献对照' } as Record<'single' | 'ab' | 'catalog', string>, + modes: { + single: '评一次', ab: 'A/B 对照', catalog: '目录贡献对照', analysis_tools: '分析工具贡献对照', + } as Record<'single' | 'ab' | 'catalog' | 'analysis_tools', string>, modeHint: { single: '按一组变体评一遍题集', ab: '两到三臂各自一组变体,共用同一份期望答案,同一题几臂同时作答', catalog: '预设的 A/B:当前目录 vs 关目录,可以再加一臂「只用已核实和已确认的项」,量出数据目录帮了多少', - } as Record<'single' | 'ab' | 'catalog', string>, + analysis_tools: '预设的 A/B:分析工具开 vs 关,量出分析工具(变化拆解、波动基线……)帮了多少', + } as Record<'single' | 'ab' | 'catalog' | 'analysis_tools', string>, arm: (name: string) => `${name} 臂`, addArm: '再加一臂', removeArm: '去掉这一臂', @@ -407,6 +410,9 @@ export const EVAL_TEXT = { catalogHint: '当前目录、只用已核实的项都在开评时拍一份快照按它读:评测期间目录被改也不影响可比性', snapshot: '选一份目录快照', snapshotNone: '还没有可用的目录快照', + analysisTools: '分析工具', + analysisToolsMode: { on: '开', off: '关' } as Record, + analysisToolsHint: '关掉时助手建图看不到分析工具和分析卡;工作流题按固定的版本运行,不受影响', repeats: '每题重复几次', repeatsHint: '模型有随机性:对照建议每题 3 次', reviewedArm: '再加一臂「只用已核实和已确认的项」', @@ -586,7 +592,7 @@ export const EVAL_TEXT = { baseText: (short: string, when: string) => `${short} · ${when}`, none: '没有可比的上一次:同一题集、同一变体里还没有比这次先发起、已经评完的评测', fingerprint: '两次之间变了什么', - fingerprintNone: '模型、目录、提示词、表结构、题目、评分规则、分析设置都没变', + fingerprintNone: '模型、目录、分析工具、提示词、表结构、题目、评分规则、分析设置都没变', changed: '变了', transitions: '逐题转移', transition: { regressed: '退步', improved: '进步', same: '不变', incomparable: '不可比' } as Record, diff --git a/frontend/src/pages/evals/StartDialog.tsx b/frontend/src/pages/evals/StartDialog.tsx index 19386493..75e3781b 100644 --- a/frontend/src/pages/evals/StartDialog.tsx +++ b/frontend/src/pages/evals/StartDialog.tsx @@ -6,13 +6,16 @@ import { Field, Modal, Notice, Spinner, toast, useRadioGroup } from '../../compo import { errorMessage } from '../../lib/errors' import { formatCost, formatDateTime, shortId } from '../../lib/format' import { EVAL_TEXT } from '../../lib/termsEval' -import type { EvalCatalogMode, EvalEstimate, EvalRun, EvalSnapshot, EvalStartBody, EvalSuite, EvalVariant } from '../../typesEval' +import type { + EvalAnalysisTools, EvalCatalogMode, EvalEstimate, EvalRun, EvalSnapshot, EvalStartBody, EvalSuite, EvalVariant, +} from '../../typesEval' import { ModelPick } from './parts' const T = EVAL_TEXT.start -const MODES = ['single', 'ab', 'catalog'] as const +const MODES = ['single', 'ab', 'catalog', 'analysis_tools'] as const type Mode = (typeof MODES)[number] const CATALOG_MODES: EvalCatalogMode[] = ['live', 'reviewed', 'off', 'snapshot'] +const ANALYSIS_TOOLS: EvalAnalysisTools[] = ['on', 'off'] /** 一臂的变体(表单里的样子):全部键都在,交上去之前不改形状 */ export function blankVariant(base?: Partial): EvalVariant { @@ -21,6 +24,7 @@ export function blankVariant(base?: Partial): EvalVariant { writer: { provider: base?.writer?.provider ?? null, model: base?.writer?.model ?? null }, judge: base?.judge ?? false, catalog: { mode: base?.catalog?.mode ?? 'live', snapshot: base?.catalog?.snapshot ?? null }, + analysis: { tools: base?.analysis?.tools ?? 'on' }, repeats: base?.repeats ?? 1, label: base?.label ?? null, } @@ -37,12 +41,13 @@ export function snapshotLabel(s: EvalSnapshot): string { } /** - * 一臂变体的表单:助手、写作模型(缺省按设置),结论裁判,数据目录(当前 / 只用已核实的 / 关 / 快照),重复次数,名字。 - * 题集设置里的「默认变体」也用它(定时评测按默认变体评) + * 一臂变体的表单:助手、写作模型(缺省按设置),结论裁判,数据目录(当前 / 只用已核实的 / 关 / 快照),分析工具(开 / 关), + * 重复次数,名字。题集设置里的「默认变体」也用它(定时评测按默认变体评)。预设对照里由预设定的那一项(目录、分析工具)不摆 */ -export function ArmFields({ idPrefix, value, onChange, snapshots, withLabel = false, labelIndex = 0, hideCatalog = false }: { +export function ArmFields({ idPrefix, value, onChange, snapshots, withLabel = false, labelIndex = 0, hideCatalog = false, + hideAnalysis = false }: { idPrefix: string; value: EvalVariant; onChange: (v: EvalVariant) => void; snapshots: EvalSnapshot[] - withLabel?: boolean; labelIndex?: number; hideCatalog?: boolean + withLabel?: boolean; labelIndex?: number; hideCatalog?: boolean; hideAnalysis?: boolean }) { const set = (patch: Partial) => onChange({ ...value, ...patch }) const usable = usableSnapshots(snapshots) @@ -82,6 +87,14 @@ export function ArmFields({ idPrefix, value, onChange, snapshots, withLabel = fa )} + {!hideAnalysis && ( + + + + )}