| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 3 个月前 |
@opentiny/genui-sdk-benchmarks
基于 @opentiny/genui-sdk-core 的大模型 schemaJson 生成 基准:在线拉流生成样本(Vercel AI SDK + playground 的 Provider 映射),再离线校验、统计并输出 JSON / HTML / Excel 报告。
关注指标
- schemaJson:代码块是否存在、JSON 是否可解析、
genRootSchema()协议是否通过 - TTFT:首 Token 或首段 reasoning-delta 的延迟(以流中首次计入为准)
- 总耗时:端到端(
totalMs) - TPOT:首 Token 之后平均每输出 Token 耗时(见下文公式)
- Token:
promptTokens/completionTokens/totalTokens - LLM-as-a-Judge(可选):对输出质量打分 1~10,并给出简要原因
目录结构
main.ts # 入口:串行 generateSamples → runReport(.env 在包根目录)
package.json # 脚本名:benchmarks
src/
├── benchmark.config.ts # 默认运行项;可被环境变量 BENCH_* 覆盖
├── generate-samples.ts # 在线生成样本并写入本次 run 目录
├── run-report.ts # 读取样本、可选 Judge、汇总并写 report.json / report.html
├── framework/
│ ├── types.ts # LlmBenchmarkRunOptions、样本与结果类型
│ ├── runner.ts # 报告落盘、HTML、comparisonByScenario 聚合
│ ├── reporter.ts # 控制台表格与 Summary
│ └── index.ts
├── samples/
│ ├── index.ts # coreLlmBenchmarkSampleCases(注册内置场景)
│ ├── basic.ts
│ ├── complex.ts
│ ├── edge.ts
│ ├── constraints.ts
│ └── contextual.ts
└── utils/
├── index.ts
├── env.ts # BENCH_* 解析(含 envStreamTimeoutMs)
├── fs-paths.ts # reports 根目录、run 目录名、样本文件路径
├── tpot.ts # TPOT 计算
├── extract-schema-json.ts
├── judge.ts
├── resolve-models.ts
├── resolve-ai-sdk-model.ts # 按 BENCH_MAAS_MODELS_PATH 读清单,构造 AI SDK model
├── stream-text-usage.ts # resolveStreamTextUsage、benchStreamTextAbortSignal(streamText 超时)
├── first-observable-component.ts
├── excel-detail-rows.ts # Excel「明细」行
├── comparison-scenario-label.ts
├── stats.ts
├── maas-manifest-models.ts # resolveMaasModelsJsonPath、listMaasManifestModelNames(BENCH_MAAS_MODELS_PATH)
└── number.ts
系统提示词由 genPrompt(render-config, tgCustomConfig) + specificPrompt + userAppendPrompt 拼出,与 playground chat-genui 思路一致;无单独的 llm.config.ts。
maas-models.json 路径(BENCH_MAAS_MODELS_PATH)
| 用途 | 实现 | 说明 |
|---|---|---|
| 解析模型实例(实际请求) | resolve-ai-sdk-model.ts |
通过 resolveMaasModelsJsonPath()(与下表同源)读取 BENCH_MAAS_MODELS_PATH 指向的清单,构建 ProviderModelMapper 与 AI SDK model。 |
| 枚举多模型名称列表 | maas-manifest-models.ts |
listMaasManifestModelNames() 同样使用 resolveMaasModelsJsonPath()。 |
须在 packages/benchmarks/.env 中设置 BENCH_MAAS_MODELS_PATH(相对 benchmarks 包根或绝对路径);未设置或仅空白时,拉模型列表与实际请求解析都会抛错。
环境与 API Key
在 本包根目录(与 main.ts 同级)放置 .env。可参考 .env.example。
- API Key / Base URL 的环境变量名由
maas-models.json(及你配置的BENCH_MAAS_MODELS_PATH)里各 provider 的apiKeyEnvName、baseUrlEnvName决定;仓库自带清单里常见为DEEPSEEK_API_KEY,可选DEEPSEEK_BASE_URL覆盖默认baseUrl。 - 须在
.env中设置BENCH_MAAS_MODELS_PATH指向maas-models.json(见上文「maas-models.json路径」);未设置或仅空白会在枚举模型名或解析模型实例时抛错。
布尔型环境变量:未设置、空字符串或仅空白表示「用 benchmark.config.ts 默认值」;若去掉首尾空白后非空,则 1、true、yes(后两者大小写不敏感)为真,其它非空值(如 false、0)为假。
配置项与环境变量(BENCH_*)
| 变量 | 作用 |
|---|---|
BENCH_MODEL |
单模型 id;与 BENCH_MODELS / 配置里的 models 至少其一非空即可;仅多模型时可不设此项 |
BENCH_MODELS |
逗号分隔多模型;非空时只跑列表内模型,报告也只统计这些模型 |
BENCH_FRAMEWORK |
Vue 或 Angular |
BENCH_SCENARIO |
单场景 id 过滤 |
BENCH_SCENARIOS |
逗号分隔多场景;优先级高于 BENCH_SCENARIO |
BENCH_REPEAT |
每个「模型 × 场景」重复次数(正整数,默认取自 config) |
BENCH_CONCURRENCY |
生成阶段并发数(正整数,默认取自 config) |
BENCH_STREAM_TIMEOUT_MS |
单次 streamText 超时(毫秒);默认 600000(10 分钟);0 表示不启用超时(生成与 Judge 均适用) |
BENCH_LLM_JUDGE |
是否启用 Judge(覆盖 benchmark.config 中 llmJudge.enabled) |
BENCH_LLM_JUDGE_MODEL |
Judge 使用的模型 id(空则复用主模型:显式 model,否则为 models 首项) |
BENCH_JSON |
true 时控制台输出 JSON;否则表格 + Summary |
BENCH_WRITE_EXCEL |
是否生成 report_<runDir>.xlsx(runDir 为本次样本/报告所在子目录名;默认 true) |
BENCH_MODELS_FROM_MAAS |
为真且 models 在 config 中为空 时,用 BENCH_MAAS_MODELS_PATH 清单中的模型名作为多模型列表(config 里 modelsFromMaasManifest: true 时不必再设此项) |
BENCH_MAAS_MODELS_PATH |
maas-models.json:绝对路径,或相对 benchmarks 包根目录(与 main.ts、.env 同级)。枚举模型名与 resolveAiSdkModelForBench 解析实例共用此路径;未设置或仅空白会报错(见 .env.example) |
BENCH_COMPARE_EMPTY_SYSTEM |
在非「仅 plain」模式下,是否额外生成空 system 对照样本(*_plain.json) |
BENCH_PLAIN_ONLY |
仅生成 plain、不生成 full(常与 TARGET 配合向已有 run 补文件) |
BENCH_TARGET_SAMPLE_RUN_DIR |
样本与报告写入已有子目录(相对样本根目录或绝对路径),不再新建北京时间戳目录 |
BENCH_SKIP_EXISTING_SAMPLES |
目标样本 .json 已存在则跳过 API。未设置时:指定了 TARGET 则默认 true(便于续跑),否则 false |
BENCH_SAMPLES_DIR |
样本根目录(默认:packages/benchmarks/reports,见 resolveSamplesDir) |
BENCH_OUTPUT_DIR |
报告输出目录(默认与本次 run 目录一致) |
src/benchmark.config.ts 中对各配置项的默认值有更细的说明(含 promptConfig、llmJudge、streamTimeoutMs、modelsFromMaasManifest、compareEmptySystem / compareEmptySystemPlainOnly 等)。
默认「样本变体」行为(benchmark.config.ts)
生成逻辑见 generate-samples.ts:
compareEmptySystemPlainOnly === true(仅 plain):每个任务只写 空 system 的*_plain.json,不写 full。compareEmptySystem === true且 plainOnly 为 false:每个「模型 × 场景 × run」写 full + plain 各一份。- 二者均为 false:只写 full。
当前仓库默认配置里 compareEmptySystemPlainOnly 为 true,即默认只生成 plain 样本。若要默认跑完整 system 的 schema 基准,请在 config 或环境中关闭「仅 plain」(例如 .env 中 BENCH_PLAIN_ONLY=false,并按需设置 BENCH_COMPARE_EMPTY_SYSTEM)。
中断后继续
生成阶段进程被中断或手动停止后,可在相同模型 / 场景 / repeat 配置下接着补全,无需对已落盘的样本重复请求 API:
- 设置
BENCH_TARGET_SAMPLE_RUN_DIR为已有样本所在子目录(相对默认样本根目录reports/下的目录名,或绝对路径),本次不再新建北京时间戳目录。 BENCH_SKIP_EXISTING_SAMPLES:未设置时,只要指定了TARGET,默认为true——目标路径上已存在的*.json会跳过生成(日志含skip existing),只补缺失任务。- 若要整目录覆盖重跑,设
BENCH_SKIP_EXISTING_SAMPLES=false。 - 入口仍是
generateSamples→runReport串行:只有本次命令完整跑完生成并进入报告阶段,才会写出/更新report.json、report.html、report_<runDir>.xlsx。若上次在报告前中断,续跑命令结束后会一并补报告。
示例(将目录名换成你的 run):
BENCH_TARGET_SAMPLE_RUN_DIR=2026-05-09_09-52-03 pnpm --filter @opentiny/genui-sdk-benchmarks benchmarks
内置场景
场景 id 与文案在 src/samples/*.ts 中维护,汇总为 coreLlmBenchmarkSampleCases,当前包含:
- basic、complex、edge、constraints、contextual(见
src/samples/index.ts的展开顺序)。
多模型与报告过滤
- 配置
models/BENCH_MODELS:只生成并只汇总这些模型的样本。 - 仅配置单个
model(且未限定models):报告若未限定models,会读取目录下全部.json样本(便于对比历史 run)。 - 默认每次在样本根目录下新建
yyyy-MM-dd_hh-mm-ss(北京时间) 子目录;若设置BENCH_TARGET_SAMPLE_RUN_DIR则写入该目录、不新建时间戳。 - 样本文件名:
${modelSlug}_${scenario}_${runIndex}.json(plain 为_${runIndex}_plain.json后缀形式,即..._${runIndex}_plain.json;modelSlug为「文件安全可读前缀 + 下划线 + 模型 id 的 SHA256 十二位十六进制」,避免不同 id 经截断后撞名覆盖)。 - 中断后继续:见上文「中断后继续」。
运行
在 仓库根目录:
pnpm benchmarks
流程:generateSamples 写入本次 runDir → runReport 将 samplesDir 设为该 runDir,只统计本次生成的样本。
报告产物
写入选定的输出目录(默认同本次样本目录):
report.json:model、models、repeat、benchmarkTotalMs(自入口main起至写出报告的总耗时 ms,未计时时可能缺省)、llmJudge、comparisonByScenario(按场景 × 模型:avgTtftMs、avgTotalMs、avgTpotMs?、avgTotalTokens、schemaPassRate等)、generatedAt、逐条resultsreport.html:按场景对比柱状图(含 TTFT、Total、TPOT、Token、Schema 通过率等)与单次运行明细图、明细表report_<runDir>.xlsx(未关BENCH_WRITE_EXCEL时):runDir为输出目录文件夹名。含明细:model、scenario、runIndex、totalMs、tpsMs(列名如此,数值为 TPOT,单位 ms/token)、promptTokens、completionTokens、totalTokens、llmJudgeScore、llmJudgeReason、llmJudgeError、llmJudgeInputTokens、llmJudgeOutputTokens、errorMessage、promptVariant、generatedAt;另含按场景对比。「明细」仅指标与短文本列,不含模型原始输出 / schemaJson(完整内容见同目录report.json与样本*.json)。开启BENCH_LLM_JUDGE且提供商在响应中返回 usage 时,llmJudgeInputTokens/llmJudgeOutputTokens才有值;report.json的results中对应字段为llmJudgePromptTokens/llmJudgeCompletionTokens/llmJudgeTotalTokens与benchTotalTokens等(与 Excel 列名以 JSON 为准)。
控制台:json: false 时打印明细表与 Benchmark Summary(含平均 Judge 分、平均 TPOT 等)。
results 逐条字段说明
| 字段 | 含义 |
|---|---|
scenario / runIndex / model |
场景、重复序号、模型 |
promptVariant |
full 或 plain(空 system 对照) |
ttftMs |
请求到首个 text-delta 或 reasoning-delta 的耗时 |
totalMs |
请求到流结束的耗时 |
firstObservableComponentMs |
输出中首次出现 TinyCard 的耗时(未出现则缺省) |
tpotMs |
TPOT(ms/token):(totalMs - ttftMs) / (completionTokens - 1);completionTokens ≤ 1 时省略 |
isSchemaJsonBlockFound |
是否解析到 schemaJson 代码块 |
isSchemaJsonValidJson |
块内是否为合法 JSON |
isSchemaJsonValidAgainstProtocol |
是否通过 genRootSchema() |
schemaValidationError |
校验失败时的说明 |
promptTokens / completionTokens / totalTokens |
模型 usage(报告不含缓存分项) |
benchTotalTokens |
生成 + Judge 合计 token(未开 Judge 或未返回 usage 时等于 totalTokens) |
rawOutputChars |
原始文本输出字符数 |
llmJudgeScore |
Judge 分数 1~10(启用且解析成功时) |
llmJudgeReason / llmJudgeError |
Judge 原因或错误信息 |
llmJudgePromptTokens / llmJudgeCompletionTokens / llmJudgeTotalTokens |
Judge 调用的 usage(启用报告阶段 Judge 且 API 返回时有效) |
errorMessage |
生成阶段流错误信息(若有) |