尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

LLM 测试的 testing LLMs:模型本身的评估(eval harness + golden set + drift)

LLM 测试的 testing LLMs:模型本身的评估(eval harness + golden set + drift) 系列专栏:测试工程师每日一博 · Day 26(2026-08-10,周一,8 月第二周)上一篇:[Day 25 · 性能压测的容量规划:把找拐点上升为找容量曲线方程]这是系列的翻面时刻 —— 前 25 篇都在讲如何用 LLM 帮测试工程师(Day 13/22/24/25),Day 26 第一次回答如何测试 LLM 自身。也就是说,被测对象不再是 Java 代码、不再是 HTTP 接口,而是模型本身。目标:给一份 eval harness golden set drift 三件套的工程化清单,读完能直接照搬落地。这是测试工程师迎接 LLM 时代的核心素养。一、为什么 Day 26 是翻面时刻工业里把 LLM 接进自家产品的团队一夜变多——客服 / 智能搜索 / 代码助手 / 内容生成。他们的核心交付物就是 LLM 输出。所以测试工程师必须翻面,被测对象从代码翻到模型。先回看过去 25 篇 LLM 出现的场景:DayLLM 的角色Day 13LLM 生成测试用例 / selector 自愈 / flaky 根因Day 16LLM 故障复盘自动归类Day 17LLM 候选风险点提 PR reviewDay 22LLM 视觉自愈 selectorDay 24LLM 安全报告解读Day 25LLM 容量曲线翻译也就是说,Day 26 之前 LLM 都是工具,被测对象是产品代码。Day 26 翻面 —LLM 自身是被测对象。这一翻面工业意义重大。今天把 AI 接进自家产品的团队越来越多(RAG 客服、智能搜索、代码助手…),这些团队的核心交付物本身就是 LLM 输出。如果你的测试工程师对 LLM 自身毫不了解,等于对一个全新测试维度视而不见。二、测试 LLM 跟测试代码的本质区别正常的 Java 代码:输入确定 内部状态确定 → 输出确定。assertThat(actual).isEqualTo(expected)能精确断言。LLM 完全反着:维度传统代码LLM确定性强(同输入同输出)弱(temperature / 采样随机)输出形式强类型对象自由文本错误定义异常 / 错误值主观判断答得对不对覆盖率行 / 分支 / 字节码没有公认的覆盖率概念flaky罕见(多为并发 / 时钟)常态(每次 inference 都可能不同)回归测试单测断言N-shot 标注 评分矩阵工具链JUnit / pytest / coverage.pypromptfoo / LangSmith / DeepEval注意覆盖率那一栏——Day 26 不能拿 JaCoCo 那套来回答LLM 测了多少。LLM 测试的覆盖不是一个百分比,是一组维度(准确率 / 召回 / 安全 / 偏见 / 多语言 / 长文 / 上下文…),每个维度都有它自己的 golden set。三、eval harness:LLM 测试的工具集LLM 测试最核心的工具是eval harness——它给一段 LLM 输出自动打分,产生数据化的对错判断。┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ golden set │───→│ LLM under │───→│ scoring │───┬→ 分数 报告 │ (N 条样本) │ │ test │ │ function │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ ┌─ scorer 分类 ─────────────────────────┤ │ │ exact match │ semantic match(LLM-as-judge) │ regex / structured-validation │ human eval spot check │四个常见 scoring 方法:3.1 exact match(精确匹配)只适合结构稳定输出,如分类标签:defexact_match_score(llm_output:str,expected:str)-float:return1.0ifllm_output.strip().lower()expected.lower()else0.0优点:可复现、零歧义;缺点:对自由文本输出几乎不能用作主指标。3.2 semantic match(LLM-as-judge)让另一个 LLM 当裁判:defllm_judge_score(question:str,reference:str,candidate:str)-float: 用 GPT-4 之类强模型当裁判,在很多工业里是 SOTA 做法 promptf 给定问题:{question}标准答案:{reference}候选答案:{candidate}用 1-5 给候选答案打分,只输出数字。 scorecall_judge_llm(prompt)returnfloat(score)/5.0# 归一化到 0-1优点:能判断语义对错;缺点:judge LLM 也有 bias,且 evaluate 自身的成本不低。3.3 regex / structured-validation对期望 JSON / 表格 / 代码的输出:importjson,redefschema_score(output:str)-float:输出必须是合法 JSON 且包含必填字段try:datajson.loads(output)except:return0.0required{test_name,assertions,expected}return1.0ifrequired.issubset(data.keys())else0.5优点:严格,可复现;缺点:只校验形状,不校验内容质量。3.4 human eval spot check定期抽 N 条样本给人 review,这是最后一道质量门。这是工业里**「绝对必要」**的一步(再强的自动评估也代替不了人评)。3.5 promptfoo / DeepEval 的角色它们都是开源 eval harness 框架,把上面 §3.1-3.4 全部封装为 YAML 配置:# promptfooconfig.yaml(已有用例就一份 yaml)prompts:-给客户问题「{{question}}」{describe:测试:「订单查询」场景下,模型能正确给出订单状态}/{测试:{question西班牙语 / 问无意义问题 /...}}providers:-openai:gpt-4o-openai:gpt-4o-mini-local:my-inhouse-model:v2tests:-vars:{question:我的订单 ABC123 状态?}assert:-type:containsvalue:已发货-type:llm-rubricvalue:答案应该说明预计送达时间-assert:-type:javascriptvalue:output.length 200跑一条promptfoo eval,对每个 provider × 每个 test 跑一套评分,输出对比表。这就是 LLM 测试的最佳实践骨架。3.6 一个综合 scorer:加权融合实际工业里没有单一 scorer 能解决一切。成熟的 eval harness 会把上面 4 类 scorer 加权融合,权重跟业务场景对齐:defcomposite_score(llm_output,expected,**ctx):weightsctx.get(weights,{exact:0.2,# 结构化输出底线semantic:0.5,# 语义对错(主指标)schema:0.2,# 形状合规safety:0.1,# 不输出危险内容})scores{exact:exact_match_score(llm_output,expected),semantic:llm_judge_score(ctx[question],expected,llm_output),schema:schema_score(llm_output),safety:safety_score(llm_output),}# 任一维度 0 分 → 复合分直接 0(强约束,避免平均掩盖)ifany(s0forsinscores.values()):return0.0returnsum(scores[k]*weights[k]forkinweights)关键设计是任一维度 0 分 → 复合分直接 0。这条强约束避免了「语义优秀但安全维度挂了,总分 90% 假象通过」的常见坑——这种坑放出去就是给客服 LLM 留 PII 输出的后门。四、golden set:LLM 的回归测试基线跟 Day 16 §7生产故障转红灯类似,LLM 测试也需要golden set—— 一组精心挑选的样本,代表系统应该答对的所有维度。4.1 golden set 不是随便 N 条样本工业里很容易踩一个坑:随机采 1000 条 prompt 作为 golden set。结果是:复杂样本占比太少,跑出来分数看着高,实际上系统在边角案例上挂成狗。golden set必须按维度分桶:# golden-set.yamldimensions:-name:basic_qa# 基础问答samples:50# 占比 30%sample_proportion:0.3-name:multi_turn# 多轮对话samples:30sample_proportion:0.18-name:long_context# 长上下文( 4K tokens)samples:15sample_proportion:0.09-name:multilingual# 多语言samples:20sample_proportion:0.12-name:edge_cases# 边角:错别字 / 错引上下文 / 矛盾输入samples:25sample_proportion:0.15-name:safety# 安全:不能输出 PII / 歧视 / 危险信息samples:25sample_proportion:0.15total:165关键设计:每个维度独立计分;报告里看,单维度分数 阈值就是红灯(不要看总分);维度配比跟业务场景相关(客服系统 safety 占比要更高,搜索系统应召回优先)。4.2 golden set 何时升级工业真实经验:每月新增 10 条:从生产日志里挑模型答错了人补回的,或用户投诉案例;季度大 review:重审维度配置,配比改了就重跑全集(旧数据失效);大模型版本切换前:必跑全套,且保留历史作为对比 baseline。4.3 golden set 进 git跟 Day 14 §6.2 fixture 户口同源 — golden set必须进 git,带 .meta 户口:# golden-set/safety-001.yaml.metaid:safety-001description:模型应拒绝提供信用卡盗刷建议created_by:qa_engineercreated_at:2026-07-15tags:[safety,p0,content_mod]last_passed_at:2026-08-09fail_rate_30d:0owner:security_team任一条 case 30 天失败率 0,触发 review。4.4 跟 Day 16 红灯回扣的具体衔接Day 16 §7 把生产故障转成「Tag(prod_incident) 红灯 case」,LLM 时代也有完全对位的动作 ——把线上 LLM 答错的 case转成 golden set 新条目:# tools/incident_to_golden.pydefincident_to_golden_sample(incident_log:dict)-dict: 输入:线上记录的「用户问题 模型答错 真实正确答案」 输出:符合 §4.1 维度结构的 golden set 新条目 return{id:fprod_incident_{incident_log[id]},dimension:classify_dimension(incident_log),# 自动归类到 6 维question:incident_log[question],expected:incident_log[corrected_answer],tags:[prod_incident,incident_log[severity]],source:production,created_at:now(),}这条流程就是 Day 16 §7 在 LLM 测试体系的镜像:生产红灯反向灌入 golden set,循环改善。工业实践里,一条 P1 投诉的 LLM 答错对应一条 golden 新样本,golden set 每周 10-30 条新样本,其中 60% 来源于生产反思(Day 16 镜像),另 40% 来源于探索性测试准备(回扣 Day 11 左移)。五、模型 drift:LLM 的 flaky 等价物LLM 测试最大的流动性问题:同样的 prompt、同样的 golden set,模型版本一变,行为就漂移。这是 Day 10 flaky 在 LLM 时代的等价物。5.1 drift 类型分类defdetect_drift(history:list[dict],window_days:int30)-dict: history: [{ts, score, dimension}] 返回各维度近 N 天的漂移 todaynow()recent[hforhinhistoryifh[ts]today-window_days]baseline[hforhinhistoryiftoday-2*window_daysh[ts]today-window_days]drift{}fordimindimensions:recent_scoreavg([r[score]forrinrecentifr[dimension]dim])baseline_scoreavg([b[score]forbinbaselineifb[dimension]dim])drift[dim]{recent_score:recent_score,baseline_score:baseline_score,drift_pct:(baseline_score-recent_score)/baseline_score*100ifbaseline_scoreelse0,}returndriftdrift 阈值:各维度 drift 5% → 黄灯警告;drift 15% → 红灯,立刻停止新版本发版,排查原因。5.2 drift 的常见 3 种根因1. 模型版本切换(gpt-4o-2026-05 → gpt-4o-2026-08) ─ 即使是新版本更好,它输出更啰嗦 / 更严格 / 更短也可能让你的 golden set 短期失败 2. 数据 drift(RAG 系统的索引更新) ─ 知识库内容变了,旧答案不再最新 ─ 解法:把时效敏感和时效不敏感的 case 分桶评估 3. prompt drift ─ 业务方调整了 prompt(把简洁改成详细),所有 case 输出量级变 ─ 解法:prompt 进 git(回扣 Day 13 §8.3 prompts/ YAML)每类 drift 的解法不同,不能看到红灯就重测——必须先分类根因再决定怎么改。六、LLM 测试的金字塔回到 Day 1 测试金字塔的精神,LLM 测试也能套用三角形:┌─────────────┐ │ human eval │ ← 1%(每周抽 10 条人评) ├─────────────┤ │ 大规模样本 │ ← 9%(几百条 random sample 评估 recall/precision) ├─────────────┤ │ golden set │ ← 30%(每版本跑,N165 标注样本) ├─────────────┤ │ invariants │ ← 60%(schema / 安全 / 不输出 PII 等结构化断言) └─────────────┘4 层由下到上:invariants(60%):自动化的 schema / 安全断言,跑得最快(CI 每次);golden set(30%):每次模型版本切换跑;大规模样本(9%):月度评估,用 LLM-as-judge;human eval(1%):每周抽 10 条人评,最重要但不频繁。每层的代价跟价值成反比:invariants 跑得快但价值低;human eval 跑得慢但价值最高。比例60/30/9/1就是这种反比的最佳折中。6.1 跟 Day 1 测试金字塔的根本差异Day 1 经典金字塔 70/20/10,「单测越多越好」;Day 26 LLM 金字塔 60/30/9/1,自动 invariants 占 60%,人评只占 1%。这两个比例不可类比 ——传统单测是「严格断言」,LLM invariants 也是严格断言;传统集成测是「多组件协作」,LLM golden set 是「多维样本评估」;传统 E2E 是「真实用户路径」,LLM random sample 是「线上随机采样」。金字塔是精神同源,具体执行完全异类。这次回到 §2 那张表的核心意义:不能用 JaCoCo 覆盖率思路测 LLM,但能借测试金字塔的精神。七、把 LLM 测试接进 CI# .github/workflows/llm-eval.ymlname:LLM Evalon:pull_request:paths:[prompts/**,golden-set/**,model-config/**]schedule:[{cron:0 4 * * 1}]# 每周一.depth evaljobs:eval:runs-on:llm-runnersteps:-uses:actions/checkoutv4-name:Run invariants(CI 每次)run:promptfoo eval tests/invariants/--threshold 0.99-name:Run golden set(PR 每周)if:github.event_name schedulerun:promptfoo eval golden-set/--threshold 0.92-name:Drift detection(每周)if:github.event_name schedulerun:python tools/drift_detect.py--window 30d-name:Notify on regressionif:failure()run:|gh issue create --title [LLM Eval regression] ${{ github.run_id }} \ --body qa-leads,本周 LLM eval 退步,请参 §5.2 三种根因分类排查这条 pipeline三次红线:- invariants 99% → PR 红(CI 拦下),prompt / golden 改动 PR 红灯;golden set 92% → 拦新版上线(Day 23 卡发布决策树 §4 Q5 中的应用);drift 红灯 → 自动 issue,人分类根因。八、回扣系列Day在 Day 26 它接到的线Day 1 测试金字塔§6 LLM 测试金字塔(60/30/9/1)Day 3 覆盖率§2 LLM 无 JaCoCo 概念,用多维度替代Day 8 TDD§7 invariants 在 PR 同 TDD 红绿一致Day 10 flaky 治理§5 drift 是 LLM 时代的 flakyDay 13 prompt 工程就是新单元测试§3 eval harness 是它的扩展,全篇是 Day 13 §8 的延伸Day 14 fixture§4.3 golden set 进 git .meta 户口Day 16 红灯回扣§4 golden set 来源是生产发现错答Day 17 代码评审§7 prompt golden set 改动 PR reviewDay 19 三方协作§7 LLM 测试需要 QA MLE DevOps 三方Day 20 OKR 度量§5 drift_pct 进度量体系Day 23 微服务测试矩阵LLM 作为后端服务时,它该进 Q5(外部表现型)Day 24 安全测试golden safety 维度12 条回扣。Day 26 是系列第二次翻面时刻—— 第一次是 Day 11 左移、Day 12 右移把时间轴展开;Day 26 把被测对象从代码翻到模型。九、给测试工程师的实操入门路径如果你团队刚把 LLM 接上,不知道从哪儿下手:第一周:写 20 条最关键的 case(覆盖核心业务路径美),手跑,不接 CI;第二周:把 20 条用 §3.1 exact match / §3.3 schema validation 接到 promptfoo,写跑 invariants;第三周:把第 1 周的 20 条扩到 100 条,按 §4.1 维度分桶,接 CI;第 4-8 周:加 drift 监控 LLM-as-judge 月度大 eval;第 9 周:开始研究 RAG / agentic 评估(下一个高度)。关键:不要追求一上来就 200 条 case LLM-as-judge——前 4 周先把 invariants 和 golden set 落地,让团队建立LLM 也能测的工程感;然后再加深度。十、反模式清单反模式表现干掉的办法golden set 随机采样复杂场景占比太少,分数虚高§4.1 按维度分桶只看总分单维度挂但被总分掩盖报告看维度,不看总分不接 CI提交 prompt / model 升级就跑不了§7 三次红线接进 CI没有 human evalLLM-judge 也错,人评缺失每周抽 10 条,1% 的工作量drift 红灯重测吧没分类根因直接重跑,根本问题没解§5.2 三种根因分类golden set 半年不更新边角案例永远没补§4.2 月增 10 条案例用 JaCoCo 思路算覆盖率LLM 无对应概念§2 维度替代模型版本升级不跑 eval上线后 unknown regression§7 schedule 跑全套十一、原则三句话LLM 测试不是断言,是评分矩阵——exact / semantic / schema / human 四档各有适用场景;golden set 按维度分桶,不看总分看单维度——5% drift 就告警,15% drift 就拦发版;invariants golden set random sample human eval 60/30/9/1—— LLM 测试金字塔。十二、思考题留给今晚:你团队目前在用 LLM 吗?如果有,测试 LLM 自身做过吗?用什么方法?团队上次升级 prompt / 模型版本有没有跑 eval?如果没跑,要不要在下次升级前补上?你的 LLM 系统每条样本都生成 PII 风险分析吗?如果没,§7 invariants 加一条;drift 红灯亮了第一个动作是什么?不要立刻重测,先用 §5.2 三种根因分类;eval harness 进 CI 后,谁在维护 golden set?12.1 一句口诀(贴墙上)读过本篇后,团队做 LLM 上线决策时可套用 ——「invariant 拦断、golden 分维、random 抽样、human 把关」:CI 自动 invariants 拦 P0 红线(60%);golden set 按维度分桶看分数不看总分(30%);每周大规模 random sample 跑 recall/precision(9%);每周 10 条人工人评补盲点(1%)。三层自动 1% 人工,LLM 测试金字塔就此落地。十三、TL;DRDay 26 是系列翻面时刻:前 25 篇 LLM 是工具,Day 26 LLM 是被测对象;eval harness golden set scoring function;4 种 scoring:exact match / semantic(LLM-as-judge)/ schema-validate / human eval;golden set 按维度分桶,6 维(基础 / 多轮 / 长文 / 多语 / 边角 / 安全)推荐配比;drift 是 LLM 的 flaky:5% 黄灯,15% 红灯拦发版;LLM 测试金字塔 60/30/9/1(invariants / golden / random sample / human);12 条对位前文,Day 13 §8(“prompt 当单元测试”)→ Day 26(“prompt golden set 升级版”)。下一篇:Day 27 ·测试工程师的开源参与:从提 issue 到核心贡献者的实操路径Day 6 LLM 测试是个深度话题,Day 27 转向工程师外延 — 把测试工程师的影响力延伸到公司之外的 OSS圈。拆 issue → PR → reviewer → maintainer 四阶段,以及如何让公司支持这种社区投入。下篇见
返回列表