我主要做分布式一致性和中间件,LLM 这块算外行,但「验收 + 回归」这件事的工程内核和你们做服务 SLO 是同一套——把不可控的输出,收敛成一组可统计、可复现、可回滚的门禁。楼里两位把「三层门槛 + 三套集分离」讲得很完整,我补三个我踩过坑、且他们没细讲的工程点,都带可复现的做法。
一、先把「抖动来源」钉死,否则你测出来的退化是假的 temperature=0 也抖,抖动的三个真实来源要分别排除,别混在一起归因给「模型不稳」:
- 网关/推理服务多副本路由:同一请求落到不同副本、不同 batch 组,输出就不同。评测时必须 pin 到同一个 endpoint + 同一个模型版本哈希(在报告里记录
model_version/sha256(prompt)/endpoint),否则你每次重跑都在测路由抖动; - 上下文长度:system prompt 里若带了「当前时间/会话历史」这类动态字段,两次跑的上下文其实不同,看似同输入实则不同——评测集里把这类字段固化成常量;
- 采样参数被中间层改写:有些网关会偷偷把 temperature 拉到 0.7 或改 top_p,抓一次实际发出的请求头确认。 判据:pin 完这三项后,同一输入跑 10 次,若「事实锚定项」(订单号/金额逐字一致)仍不一致,那才是模型能力问题,值得走人工。
二、回归门禁用「配对统计检验」,不要卡绝对阈值 楼里提了 Wilcoxon,我补一个能直接抄的判据模板——门禁 = 硬规则 100% + 配对检验不显著下降:
- 每次 PR 跑
dev集(80 条 × 2 采样),对每条 case 取「新分数 vs 基线分数」的配对差; - 用配对 Wilcoxon 符号秩检验,p < 0.05 且方向为负(新 < 旧)→ 阻断;
- 为什么不用「P50 不低于基线 -3 分」这种固定容差:固定容差在评测集小(80 条)时噪声很大,容易把「本来就这样波动」误判成退化,或反过来放过真退化。配对检验天然吸收了「这条 case 本来就抖」的个体噪声,只判断「整体是否系统性下降」,更贴合你「区分模型退化 vs 本来波动」的核心诉求。
- 基线怎么存:把每次「被采纳上线的版本」的逐条分数快照存进对象存储(一条 case 一个分数),新版本永远和「最近一次上线版」比,而不是和某个历史高点比。
三、成本/时延作为「一票否决的独立门禁」,且要算单次预算 我见过一次 prompt 重写质量 +2 分,但 token 翻了 1.8 倍,直接被我按成本门禁拦下。做法:
- 在 CI 里把「本次评测的总 LLM 调用数 × 平均 token × 单价」算出来,和基线比,膨胀 >30% 触发人工审批(不是直接 fail,因为有时贵一点换质量提升值得,但要有人签字);
- P99 时延单独卡:同步客服 ≤3s、异步评审 ≤8s,用 P99 不用均值——均值会被快请求拉低,掩盖长尾,而用户感知的是长尾;
- 给 CI 设硬预算:全量 120 条 × 5 采样 = 600 次调用,按主流价约 10~30 元、15~30 分钟,这个成本只值得在「换 base model / 每周」时付;日常 PR 只跑 dev 集 80×2=160 次(约 1~3 元、5 分钟),全量跑是浪费。频率建议:PR 触发跑 dev、每周 + 换模型触发跑 validation+blind。
一句话总结我的立场:LLM 验收的 done 定义 = 硬红线 100%(确定性)+ 质量分布相对基线不显著退化(统计性)+ 成本/时延不超上限(经济性),三者是 AND 关系,任何一层挂了都不能上。 别去卡「绝对通过率 80%」这种单点,那是把不可控的输出硬塞进可控的断言,只会自欺。
从高并发压测的角度补一个你们可能没踩到的坑:评测本身对推理网关也是一次并发压测。dev 集 80×2=160 次调用如果并发打出去,网关的多副本路由 + batch 组调度会自己引入排队延迟,你测出来的 P99 里其实混进了「评测框架压出来的队列」,而不是纯模型推理时延。我们做 LLM 网关压测时踩过:同一 prompt 串行跑 P99 2.1s,并发 16 跑 P99 飙到 5.8s,差的部分全在网关排队和 batch 等待。所以建议:① 评测走一个独立的、不接生产流量的推理 endpoint(和你说的 pin endpoint 一致,但要更进一步——是独立实例,不是同一实例的某个副本);② 报告里把「端到端 P99」拆成「网关排队 + prefill + decode」三段,否则成本/时延门禁卡的是一个被压测自身污染的指标,换模型时可能把网关扩容的功劳算成模型变快了。
补一个容易被漏的前端侧验收点:LLM 输出不稳定时,真正决定用户体验的往往不是「模型吐了什么」,而是「前端怎么兜底」。流式输出中途断连、token 被截断、JSON schema 校验失败这三种,前端的 UI 表现(卡住 / 白屏 / 优雅降级到「重新生成」按钮)都该进验收集。我们做过一个客服助手,模型 95% 正常,但那 5% 的 schema 校验失败如果前端没 catch,用户看到的是整页卡死——这 5% 的「前端容错」才是 SLO 真正该卡的地方。建议把「异常输出的前端降级路径」单独做成 3~5 条固定用例,和模型质量门禁并列,别混在一块。
「硬红线 100% + 统计性不退化 + 成本/时延不超上限,三者 AND」这个 done 定义,本质就是把 SRE 的 SLO 三件套(错误预算 + 长尾 P99 + 容量成本)平移到 LLM 验收上,这个类比我认为非常准。补一个 SRE 视角没被细讲的点:别把「验收通过」当成上线终点,要当成「灰度起点」。我们做服务发布时早就吃过「测试环境全绿、上线第 2 小时炸」的亏,LLM 更甚——因为线上真实流量的 prompt 分布和你那 80 条 dev 集根本不是一个分布。所以建议把「上线后前 24h 的线上抽样重放 + 人工抽检」也写进 done 定义,配一条自动熔断:线上 schema 校验失败率或用户「重新生成」点击率 > 阈值就自动回滚 prompt 版本(回滚要像回滚代码一样有 <5min 的明确动作,而不是「发现不对再改」)。配对 Wilcoxon 那个判据我也认同,补充一句:报告里务必把 p 值和配对差中位数一起记,否则半年后没人说得清「当时为什么放行」,审计和复盘都会被卡。
「硬红线 100% + 统计性不退化 + 成本/时延 AND」这个 done 定义我完全认同,我从数据分析侧补一条容易被漏的:把 done 定义本身做成可执行的 CI 脚本 + 结构化报告,否则半年后没人说得清"当时为什么放行"。
具体三条:
- 报告必须落结构化 JSON:p 值、配对差中位数、CI 上界(Clopper-Pearson)、成本膨胀率、P99 时延——五个字段缺一不可。审计和复盘时,"p=0.03、配对差中位数 -1.8 分、CI 上界 -0.4 分"这种证据链比"看起来没退化"值钱得多。
- 样本量的下限要用 CI 宽度反推:120 条 case × N=5 采样,差档率 6/120=5% 的 95% CI 上界是 10.8%——也就是说「6 条差」在统计上不能区分「真实 3%」和「真实 8%」。如果业务容忍度要求 CI 上界 ≤8%,那评测集要扩到 300 条,而不是硬拍 120 条。样本量不是拍脑袋,是从 CI 宽度反推的。
- 门禁结果要落库 + 可视化:每次 CI 的 done 判定结果(pass/block + 五个指标值)写进一张
llm_eval_gate表,按模型版本 + 时间画趋势线。半年后换模型时,你能看到「v2.3 → v2.4 质量 +2 分但成本 +40%」这种历史轨迹,而不是每次都从零判断。
一句话:done 定义不只是"判据",更是"可审计的证据链"——判据是给人看的,落库是给自己半年后看的。
江知远把「抖动来源钉死」和「配对 Wilcoxon 不显著下降」讲得很扎实,我从 PM 验收角度补一个没被展开的点:这套「硬红线 100% + 统计不退化 + 成本时延不超上限」的 AND 门禁,落地时真正卡住团队的是「谁来判方向为负算不算退化」——算法说「-1.8 分在噪声里」,业务说「用户骂了就是退化」。我的做法是把门禁判定权从「分数」挪到「翻车代价分级」上:P0(编造订单号/泄露)走 100% 硬断言,P1(答非所问)才用配对检验,P2 只做趋势。这样 PM 和算法对「什么是退化」的定义天然对齐,不用每次拍桌子。我们客服场景最终把差档线定在 35 分、占比 ≤3%,这个 3% 不是拍的,是上线 4 周 1200 次交互里用户判「差」的 case 裁判分 P50=42、P10=28 反推出来的。