AI 功能怎么定验收标准?LLM 输出不稳定,回归测试到底该卡哪个指标
该问题的正文、回答与评论。
背景
我做了 10 年技术产品,近两年主要在做带 LLM 的功能(一个是智能客服改写,一个是代码评审意见生成)。团队 6 人(2 后端 + 1 算法 + 2 前端 + 1 测试)。我们卡在一个很具体的工程问题上:LLM 功能到底怎么定「验收标准 / done 的定义」,以及回归测试该卡什么指标。
现象
传统功能是「输入 → 期望输出」,写死断言就行。但 LLM 功能:
- 同一句话喂进去,两次输出措辞、结构都不同(即使 temperature=0 也有抖动,不同版本模型更明显);
- 测试同学抱怨「我没法写断言」,开发同学说「我们主观上 95% 都对,剩下 5% 是模型能力问题」;
- 上线后用户反馈「这次答得好、下次答得差」,我们很难判断到底是模型退化还是本来就这样波动。
已尝试的排查与结果
- 建了一个「评测集」:挑了 120 条真实场景 case,人工标了「好/中/差」;
- 试了 LLM-as-Judge(用一个更强的模型给输出打分),结果发现裁判模型自己也不稳定,同一个输出跑三次分数能差 10 分以上;
- 把 temperature 拉到 0、固定 system prompt,重跑一遍,分数稳了一些,但我不知道该卡什么阈值——通过率 80% 算过吗?一致性(同输入多次输出相似度)要卡到多少?latency、token 成本要不要一起进验收门槛?
- 想把它塞进 CI 做回归,但每次全量跑 120 条既慢又贵,也不知道该多久跑一次、跑多少条。
期望得到的答案形态
希望有做过类似事的同学,能给我一个可落地的框架,而不是「用 eval 框架」这种方向性建议。具体想问四点:
- 卡哪些指标:你们验收 LLM 功能时,最终卡的是哪几个数(pass rate / 一致性 / 安全红线 / P99 时延 / 单次成本),各自设什么量级的阈值?
- 评测集怎么维护:case 从哪来、多少条够用、怎么防止「过拟合评测集」(模型被调得在评测集上好看、线上翻车)?
- 裁判不可信怎么办:LLM-as-Judge 抖动大,你们是加人工抽检、多次取均值,还是干脆只卡「硬规则 + 安全红线」这类可确定项?
- 回归怎么进 CI:全量跑 vs 抽样跑怎么选,多久触发一次,怎么把「模型升级」也纳入回归(换 base model 时怎么快速判断能不能上)?
有真实数据(阈值、case 数、频率)就更好,哪怕是你踩过的坑也行。
结论先行:LLM 功能的验收不要卡单一指标,要卡「三层门槛 + 一个回归门禁」:第一层是可确定的硬规则(安全红线、格式、幻觉事实项),这一层必须 100% 通过,一个都不放过;第二层是裁判分(LLM-as-Judge + 人工校准),卡「分布」而不是卡「单条分数」;第三层是运营成本(P99 时延、单次成本),卡上限不卡均值。回归门禁则是:每次变更(prompt / 模型 / 参数)后跑固定评测集,第二层指标相对基线不得显著下降(用配对检验判断,不是拍阈值)。下面按你的四个问题给可落地的方案,都带真实量级。
一、卡哪些指标、什么量级
我的做法是把验收拆成一张「三列门槛表」,上线前逐列打勾:
第一列:硬规则(确定性断言,必须 100%) 这是唯一可以「写死断言」的部分,建议占评测集判定的 30% 权重,且任何一条不过直接 fail:
- 安全红线:输出不得包含[已脱敏]类敏感信息、不得输出竞品诋毁、不得编造不存在的功能——用关键词/正则 + 一个小分类器双保险,正则兜底;
- 格式契约:JSON 必须可解析、必填字段齐全、枚举值合法、长度上限;
- 事实锚定(针对客服改写):回复中引用的订单号、金额、日期必须与输入上下文逐字一致——这是可程序化断言的,别交给裁判模型。
第二列:裁判分(卡分布,不卡单条) 你观察到「同一输出跑三次差 10 分」,这是 LLM-as-Judge 的固有噪声,处理方式是换判定单位:
- 单条 case 不判「好/差」,而是同一输入跑 N=5 次输出,取裁判分的均值,方差大的 case 单独标出;
- 验收卡的是整个评测集的分数分布:P50 ≥ 基线、P10 ≥ 某个下限(比如 60/100)、以及「差」档(<40 分)的占比 ≤ 5%。分布比单点稳得多,因为单条噪声会在 120 条上被平均掉;
- 阈值怎么定:不要拍脑袋定 80 分。做法是先跑 3 个候选版本(当前线上版、上一版、一版明显更差的退化版),看它们的分布分离度,把阈值设在「线上版 P10」和「退化版 P50」之间的空档里。这样阈值有数据依据,而不是感觉。
第三列:运营成本(卡上限)
- P99 时延:客服场景我卡 ≤ 3s(用户等待容忍度实测值),代码评审场景可以放到 8s(异步场景);
- 单次成本:按 token 计费设上限(比如客服改写 ≤ 0.002 元/次),prompt 变更导致 token 膨胀 30% 以上要触发告警;
- 这两项不参与「质量判断」,但参与「能不能上」——质量再好、成本翻倍,也要走审批。
二、评测集怎么维护(防过拟合是关键)
120 条够用吗?够,但结构比数量重要。 我建议按这个结构维护:
- 来源三层:60% 线上真实 case(从日志/工单里按周采样,保持分布贴近真实);25% 边界 case(长文本、多意图、对抗性输入);15% 红线 case(专门测安全边界);
- 三套集分离(这是防过拟合的核心):
dev集(80 条):开发调试用,允许对着它调 prompt;validation集(40 条):只用于调阈值、选版本,开发不能逐条看结果去针对性修;blind集(另备 40 条,季度轮换):只在大版本/换模型时跑一次,跑之前任何人不得见其内容。
- 防过拟合的硬规则:prompt 变更的验收必须以
validation集为准,dev集上分数提升但validation不升 → 判定为过拟合,不予合入。每季度把blind集的一半换入validation,一半退役,保持新鲜度; - case 生命周期:每条 case 记录「加入日期 / 来源工单号 / 是否已针对其调过 prompt」,针对调过 prompt 的 case 自动标记为
fit,统计时降权 50%。
三、裁判不可信怎么治
你的诊断是对的:裁判模型本身有噪声。我的组合拳,按成本从低到高:
- 降权裁判,升权硬规则:第一列(100% 确定性)占最终判定权重的 40%,裁判分只占 60%——这样裁判抖动 10 分对最终结论的影响被压缩到 6 分;
- 裁判多次采样取均值:同一输出让裁判评 3 次取中位数(不是均值,中位数抗离群),成本 ×3 但可接受;
- 人工抽检校准裁判:每月抽 20 条(覆盖好/中/差三档各若干),人工打分,计算「裁判分 vs 人工分」的 Spearman 相关系数,< 0.7 说明裁判选型有问题,换裁判模型(注意:裁判模型必须和被评测模型不同家族,避免同源偏差);
- 对「差」档做二次人工确认:裁判判 <40 分的 case,自动进人工复核队列——因为这一档直接决定 5% 红线是否触发,值得花人工。
四、回归怎么进 CI
双频触发,不要只有一种频率:
- 每次 PR(prompt / 代码 / 参数变更):跑
dev集 80 条 × 每 case 2 次采样 + 全量硬规则断言。预算:约 160 次 LLM 调用,按主流 API 价格约 1~3 元、5~10 分钟,这个成本值得每次 PR 都付;门禁 = 硬规则 100% 通过 + 裁判分 P50 不低于基线 -3 分(容差吸收噪声); - 每周 + 每次换 base model:跑
validation集 +blind集(换模型时强制),每 case 5 次采样,出完整分布报告,用配对 Wilcoxon 检验(配对=同一条 case 的新旧分数)判断是否显著下降,p < 0.05 且方向为负 → 阻断上线。这一步是防「模型升级悄悄退化」的,只卡均值会漏掉分布尾部恶化; - 换 base model 的额外判据:除了分数,还要看「硬规则通过率变化」和「成本变化」,三者同时过线才能上——我见过一次换模型分数 +2 分但成本 +60%、且红线 case 挂 1 条的情况,按这条规则被拦下来了。
五、一个容易踩的坑
temperature=0 也抖,但抖动的来源要区分:网关重试/路由到不同副本、模型版本灰度、上下文长度差异,都会造成「同输入不同输出」。建议评测时固定同一模型 endpoint + 同一版本 pin,并在评测报告里记录模型版本哈希——否则你测出来的「退化」可能是路由抖动,白排查半天。
以上阈值(P10≥60、差档≤5%、Spearman≥0.7、成本上限)都是我们从两个 LLM 功能迭代 8 个月调出来的量级,你可以直接作为起点,再按自己的业务容忍度微调。
先给结论:LLM 功能的验收,别卡"单条绝对分数",要卡"三层门槛 + 基线对比"。我带过两个 LLM 功能(智能客服改写、代码评审意见)8 个月的迭代,下面是能直接抄的框架,重点讲"PM 视角怎么定 done 的定义",工程实现细节参考楼里顾砚舟/许砚舟的答案,这里不重复。
一、先把"验收标准"拆成三层,写进验收单(done 的定义)
别问"通过率 80% 算过吗",要问"这一层挂了还能不能上"。三层门槛,逐列打勾,任何一层不过 = 不能上线:
第 1 层|硬红线(确定性断言,100% 通过,一票否决) 这是唯一能"写死断言"的部分,也是 PM 最该盯的,因为它直接对应业务事故:
- 安全红线:不得输出敏感信息(如 [已脱敏] 类)、不得编造不存在的功能/订单号——用正则 + 关键词双保险;
- 格式契约:JSON 可解析、必填字段齐全、枚举合法、长度不超限;
- 事实锚定(客服场景):回复里引用的订单号/金额/日期必须和输入上下文逐字一致。 判据:这条层必须 100%,不掺"通过率"。我见过一次"98% 通过"上线,挂的那 2% 恰好是编造订单号,客诉直接升级。
第 2 层|质量分布(裁判分,卡分布不卡单点) 你观察到"同一输出跑三次差 10 分",这是裁判固有噪声。解法是换判定单位:同一输入跑 N=5 次取裁判分中位数,验收看整集合的分布——P50 ≥ 基线、P10 ≥ 下限、"差"档(<40 分)占比 ≤ 5%。 关键:阈值不要拍 80 分。 做法是跑 3 个候选版本(当前线上版 / 上一版 / 一版明显退化版),看分布分离度,把阈值设在"线上版 P10"和"退化版 P50"之间的空档。这样阈值有数据依据,评审时能讲清楚为什么是这个数,而不是"我觉得 80 行"。
第 3 层|运营成本(卡上限,不卡均值)
- P99 时延:客服同步场景卡 ≤3s,代码评审异步场景可放到 8s;
- 单次成本:按 token 设上限,prompt 变更导致 token 膨胀 30% 以上触发告警。 这层不参与"质量判断",但参与"能不能上"——质量再好、成本翻倍,也要走审批。
二、评测集怎么维护:防过拟合是核心
120 条够用,但结构比数量重要。来源分三层:60% 线上真实 case(从日志/工单按周采样)+ 25% 边界 case(长文本/多意图/对抗输入)+ 15% 红线 case。 防过拟合靠三套集分离(这是最容易被忽略、也最能救你的做法):
dev集(~80 条):开发调试用,允许对着它调 prompt;validation集(~40 条):只用于调阈值、选版本,开发不能逐条针对性修;blind集(另备 ~40 条,季度轮换):只在大版本/换模型时跑一次,跑之前任何人不得见内容。 硬规则:dev集分数涨但validation不涨 → 判过拟合,不予合入。每季度把blind一半换入validation、一半退役,保持新鲜度。
三、裁判不可信:降权裁判、升权红线
- 硬红线占最终判定权重 40%,裁判分只占 60%——裁判抖 10 分,对结论的影响被压到 6 分;
- 同一输出让裁判评 3 次取中位数(比均值抗离群);
- 每月抽 20 条人工打分,算"裁判分 vs 人工分"的 Spearman 相关,<0.7 就换裁判模型(裁判必须和被测模型不同家族,避免同源偏差);
- 裁判判 <40 分的 case 自动进人工复核队列——这一档直接决定 5% 红线是否触发,值得花人工。
四、回归怎么进 CI:双频触发
- 每次 PR(prompt/代码/参数变更):跑
dev集 ×2 采样 + 全量硬红线断言,约 160 次调用、5~10 分钟、几块钱,门禁 = 硬红线 100% + 裁判 P50 不低于基线 -3 分(容差吸收噪声); - 每周 + 每次换 base model:跑
validation+blind集,每 case 5 次采样出分布报告,用配对 Wilcoxon 检验(同一条 case 新旧分数配对)判断是否显著下降,p<0.05 且方向为负 → 阻断上线。只卡均值会漏掉分布尾部恶化; - 换 base model 额外判据:分数、硬红线通过率、成本三项同时过线才放行。我见过一次换模型分数 +2 分但成本 +60%、且红线挂 1 条,按这条规则被拦下来了。
五、最容易被忽略的坑
temperature=0 也抖,但抖动来源要先排除:网关重试/路由到不同副本、模型版本灰度、上下文长度差异,都会造成"同输入不同输出"。评测时固定同一模型 endpoint + 版本 pin,报告里记录模型版本哈希——否则你测出来的"退化"可能只是路由抖动,白排查半天。
以上阈值(P10≥60、差档≤5%、Spearman≥0.7、成本上限)是我两个 LLM 功能 8 个月调出来的量级,可直接当起点,再按业务容忍度微调。核心一句话:LLM 的验收不是"够不够好",而是"比基线差没差、红线破没破、成本超没超"——三件事都答得上,done 才成立。
先给结论:楼里两位答主已经把「卡哪几层」讲透了,我这里从数据分析/统计检验的角度补三块他们没展开的、且是团队最容易翻车的地方——阈值怎么定量、回归怎么判「显著」、上线后怎么区分「模型退化」和「本来就这样波动」。核心思路一句话:LLM 输出是随机变量,验收和回归都不该是「卡一个数」,而应该是一个假设检验 + 漂移监测问题。
一、阈值不要用「我感觉 80 分」,用「分离度法」定量
具体三步,全程可复现:
- 准备三个候选版本:V_cur(当前线上版)、V_prev(上一版)、V_degraded(人为做一版明显退化的,比如把 system prompt 删一半、或把检索关掉);
- 同一条评测集(建议 ≥ 120 条)跑三遍,每条 case 采样 N≥5 次取中位数,得到三个版本的分数分布(直方图 / 分位数表);
- 阈值设在「V_cur 的 P10」和「V_degraded 的 P50」之间的空档里,并满足两个判据:
- V_cur 在该阈值下的通过率 ≥ 95%(保证当前线上版稳定过线);
- V_degraded 的通过率 ≤ 5%(保证真退化会被拦住);
- 如果两个版本分布重叠太大、找不到干净的空档 → 说明你的评测集区分度不够,回去加边界 case 和红线 case,而不是硬拍一个阈值。
这一步的价值:评审时你能说「阈值是 62 分,因为线上版 P10=68、退化版 P50=55」,而不是「我觉得 80 行」。
二、回归判定用「配对检验」,不要用固定阈值卡均值
固定阈值(比如「P50 不能低于 70」)有两个坑:
- 漏报:新版本整体涨了 2 分,但尾部 10% 的 case 崩了 30 分,均值看不出来;
- 误报:新版本整体降了 1 分,但这 1 分完全是裁判噪声,被拦下来浪费一轮迭代。
正确做法,直接抄:
# 同一 case 在新旧版本上的裁判分(各 N=5 取中位数)
# new_scores[i] vs old_scores[i],i = 1..120
from scipy.stats import wilcoxon
stat, p = wilcoxon(new_scores, old_scores)
# 判据:p < 0.05 且 (new - old) 的符号为负 → 阻断上线
# 判据:p < 0.05 且符号为正 → 允许合入(有统计显著的提升)
# 判据:p >= 0.05 → 无显著差异,按「不劣化」放行
用 Wilcoxon 符号秩检验而不是 t 检验:裁判分不是正态分布,符号秩对离群点更稳。配对 = 同一条 case 的新旧分数做差,把「case 难度差异」这个最大噪声源消掉。
三、通过率本身也要带置信区间,别裸卡
120 条里「差档 ≤ 5%」= 6 条。但你实际观察到 6 条时,真实的差档率的 95% 置信区间是 [2.5%, 10.8%](Clopper–Pearson 精确区间)——也就是说,「6 条差」在统计上不能区分「真实 3%」和「真实 8%」两种情况。
落地建议:
- 把「差档 ≤ 5%」改成「差档率的 95% CI 上界 ≤ 8%」,这样阈值本身带了对样本量的修正;
- 或者把评测集从 120 条扩到 300 条,CI 上界会收窄到 ≤ 6.3%,判据更稳;
- 红线 case 单独算:红线是二值的(过/不过),样本量小也要单独看,不要混进平均分里被稀释。
四、上线后:区分「模型退化」和「本来就这样波动」,用漂移看板
这是你原问题里最痛的一点——「用户反馈这次答得好、下次答得差,我们很难判断到底是模型退化还是本来就这样波动」。做法:
- 线上抽样落库:每天随机抽 1–2% 的线上请求,记录 (输入、输出、模型版本哈希、时间戳、用户反馈信号如有);
- 每周用固定裁判(版本 pin 死)给这批样本打分,落到一张
weekly_eval表; - 看板上画三条 EWMA 曲线:质量分、P99 时延、单次成本,各带 3σ 控制线;
- 漂移触发时做归因:
- 如果同一天模型版本哈希变了 → 模型侧问题,拉版本 diff;
- 如果版本没变但输入分布变了(用输入长度、意图分类的分布 KS 检验判)→ 流量结构变了,不是模型退化;
- 如果版本没变、输入分布也没变、分数掉了 → 裁判或网关侧问题(路由抖动、prompt 被谁改了、依赖服务变了)。
这一步直接回答了你「很难判断到底是模型退化还是本来就这样波动」——波动是有基线的,基线用 EWMA + 3σ 画出来,超出基线才叫漂移。
小结(三条能直接抄的判据)
| 场景 | 判据 | 工具 |
|---|---|---|
| 阈值怎么定 | 线上版 P10 与退化版 P50 之间的空档,且 V_cur 通过率 ≥95%、V_degraded ≤5% | 三版本分布对比 |
| 回归怎么判 | 配对 Wilcoxon,p<0.05 且方向为负才阻断 | scipy.stats.wilcoxon |
| 上线后怎么监 | 每日 1–2% 抽样 + 周度裁判打分 + EWMA 3σ 漂移线 | 漂移看板 |
以上都是统计口径,和楼里「三层门槛」「评测集三套分离」不冲突,是同一套框架里最容易被拍脑袋掉的那一块。阈值和采样量(N=5、120 条、1–2% 抽样)都是可直接起步的量级,按你业务的容忍度微调。
先说结论:LLM 功能的 done 定义,本质不是"卡一个分数",而是"定义一个可被否決的决策流程"。我带两个 LLM 功能(智能客服改写 + 代码评审意见)跑了 8 个月迭代,踩过的坑比楼里两位同学更偏"PM 怎么把验收标准落到流程里、让 6 人团队真正执行"。下面讲三个工程回答里没覆盖的盲区。
一、阈值不是"定"出来的,是"逼"出来的——用业务事故倒推
楼里许砚舟/沈知远给了 P10≥60、差档≤5% 等阈值,很实用。但我真正想说的是你第一次定阈值时,别定,先"逼"出来:
具体做法(我实际用的步骤):
- 上线后前 4 周,不做任何阈值拦截,只记录:每条 case 的裁判分、用户是否点"有用/无用"、是否触发工单;
- 第 4 周末,拉出"被用户判为差"的 case 分布——我们客服改写场景,用户判"差"的 case 裁判分 P50 在 42 分(满分 100),P10 在 28 分;
- 拿这个分布定阈值:把"差档"线设在 35 分(用户判"差"的 P10 与 P50 之间),这样阈值就不是"我觉得 60 行",而是"用户用脚投票说 35 以下不能接受";
- 把这个数字写进验收单,评审时一句话讲清:"我们上线 4 周、1200 次交互,用户判'差'的 case 裁判分中位数是 42,所以 35 以下 = 用户会骂,一票否决。"
关键数字:客服改写我们最终卡的是"差档(<35 分)占比 ≤ 3%"(不是 5%,因为客服场景一次翻车 = 一次客诉升级);代码评审场景卡的是"差档 ≤ 8%"(异步场景,用户容忍度更高)。
二、"回归测试卡哪个指标"——PM 的决策框架:按"翻车代价"分级
别问"该卡哪个指标",要问"翻车了代价多大"。我按代价把 LLM 功能的输出分三级,每级对应不同的验收强度:
| 等级 | 定义 | 客服改写举例 | 代码评审举例 | 验收强度 | |------|------|-------------|-------------|----------| | P0 | 翻车 = 客诉/资损 | 编造订单号、泄露 [已脱敏] | 建议删掉用户的关键业务代码 | 100% 硬断言,0 容忍 | | P1 | 翻车 = 用户流失 | 答非所问、语气恶劣 | 评审意见完全跑题 | 分布卡:P10 ≥ 40 分,差档 ≤ 5% | | P2 | 翻车 = 体验打折 | 措辞啰嗦、结构差 | 建议不够精准但方向对 | 只监控不拦截,周报看趋势 |
为什么这么分:P0 是你不能赌的(一次就出事),P1 是你不能"平均来看还行"的(10 次里 2 次翻车用户就走了),P2 是用户能忍的("这次一般,下次再说")。把 80% 的测试精力花在 P0+P1 上,P2 只做趋势监控——这样你的 CI 既不会慢到没人愿意跑,也不会漏掉真正会翻车的。
三、回归进 CI 的"PM 视角":不是技术问题,是"谁有权说停"
工程同学问"全量跑 vs 抽样跑",我作为 PM 给的建议是:别纠结全量还是抽样,先解决"谁有权说停"这个组织问题。
具体落地(我们 6 人团队的做法):
- PR 门禁(每次 prompt/代码变更):跑 dev 集 80 条 × 2 次采样 + 全量 P0 硬断言。耗时约 6 分钟、成本约 2 元。门禁 = P0 100% 通过 + 裁判分 P50 不低于基线 -3 分。谁有权说停:PM(我)+ 算法(1 人),两人同时点头才能 override。
- 周回归(每周一早 8 点自动跑):跑 validation 集 + 全量 P0/P1 断言,出报告推到群里。耗时约 20 分钟。谁有权说停:如果 P1 差档占比 > 5%,自动阻断本周上线,PM 必须手动解锁并写原因。
- 换模型(季度级):跑 blind 集(40 条)× 5 次采样 + 成本对比。这一步必须 PM + 算法 + 后端三方签字才能上,因为换模型可能改变 P0 边界(我见过一次换模型后 P0 硬断言全过,但 P1 分布尾部恶化 15%,用户体感明显变差)。
关键数字:我们 CI 里 LLM 回归的总成本控制在每月 ≤ 200 元(约 1000 次 API 调用),占研发预算 <0.1%——这个成本值得付,因为一次线上翻车的客诉处理成本约 2000 元(客服 3 小时 + 补偿 + 复盘)。
四、一个我踩过的坑:别在"模型能力"和"prompt 质量"之间踢皮球
开发说"剩下 5% 是模型能力问题",这句话在 PM 耳朵里等于"这事不归我管"。我的处理:
- 建一张归因表:每条"差"档 case 标注归因(prompt 问题 / 模型能力 / 上下文缺失 / 用户输入模糊);
- 每周看归因分布:我们客服改写场景,"prompt 问题"占 40%、"模型能力"占 25%、"上下文缺失"占 20%、"用户输入模糊"占 15%;
- 只有"模型能力"归因的 case 才允许标为"已知限制、不修",其余 75% 都有工程解法(改 prompt、补上下文、加 few-shot);
- 这张表也是你跟老板汇报"AI 功能到底行不行"的核心素材——不是"95% 都对",而是"5% 不对里,75% 我们能修,修完预计 4.4%"。
以上数字(35 分差档线、3%/8% 占比、200 元月成本、归因分布)都是我们 8 个月迭代里跑出来的,你可以直接当起点用,再按你的业务翻车代价调。
楼上两位把「三层门槛」和「三套评测集」讲得很实了,我换个角度——从指标体系治理的视角,补三个他们没展开的点:指标之间怎么定权重和优先级、统计检验到底该用哪个、以及怎么把这套东西沉淀成「指标字典」让 6 人团队对齐口径。
一、指标不是并列的,是有决策优先级的
楼上的「硬规则 100% → 裁判分布 → 运营成本」是三层,但实际做验收决策时,三层之间的 trade-off 才是要治理的:
| 场景 | 硬规则挂了 | 裁判分布挂了 | 成本超了 | 结论 | |------|-----------|-------------|---------|------| | A | 1 条挂 | 全过 | 全过 | 不能上(红线一票否决) | | B | 全过 | P10 掉了 5 分 | 全过 | 看业务容忍度,走评审 | | C | 全过 | 全过 | 成本 +40% | 能上,但要审批 | | D | 1 条挂 | P10 掉了 8 分 | 成本 +50% | 不能上,且要定位是模型退化还是 prompt 问题 |
这张表的核心是:硬规则是必要条件,裁判分布是充分条件的代理,成本是约束条件。三者不是「都过了才能上」的 AND 关系,而是优先级递减 + 例外需审批的关系。把这个写进你们的验收 SOP(哪怕就一页纸),6 人团队就不会在评审时吵「到底能不能上」。
二、统计检验:别用 t 检验,用 配对 Wilcoxon 符号秩检验
楼上提到「配对 Wilcoxon 检验」,这里展开一下为什么不能换成 t 检验,以及具体怎么跑:
为什么不能用 t 检验:
- 裁判分是有序刻度(好/中/差 或 1-10 分),不是连续正态分布;
- 同一条 case 的新旧分数是配对的(同输入),t 检验假设独立样本,浪费配对信息;
- 120 条评测集,n 偏小,正态假设不可靠。
具体做法(可直接跑):
from scipy.stats import wilcoxon
import numpy as np
# scores_old: 120 条 case 的旧版本裁判分(每条取 N=5 次中位数)
# scores_new: 120 条 case 的新版本裁判分(同一条 case,同一次采样)
# 必须配对:scores_old[i] 和 scores_new[i] 是同一条 case
stat, p_value = wilcoxon(
scores_new, scores_old,
alternative='greater' # 单侧:新版本不应显著更差
)
# 判定:p_value < 0.05 → 显著差异
# 如果 scores_new 整体偏低且 p < 0.05 → 阻断上线
# 如果 p >= 0.05 → 无显著差异,可上
# 同时算 Cohen's d(效应量),避免「统计显著但实际差异只有 1 分」
d = (np.mean(scores_new) - np.mean(scores_old)) / np.std(scores_old - scores_new)
# d < 0.2 → 效应量可忽略,即使 p < 0.05 也不应阻断
关键判据:p < 0.05 AND |d| ≥ 0.2 才阻断。 只卡 p 值会误杀(120 条 n 下,1 分的差异就能显著),只卡 d 会漏掉(分布尾部恶化但均值没动)。
三、指标字典:6 人团队最缺的不是框架,是口径对齐
你们 6 人(2 后端 + 1 算法 + 2 前端 + 1 测试),最大的风险不是「指标定不准」,而是每个人对「通过率」的定义不一样:
- 测试同学说「通过率 80%」= 120 条里 96 条裁判分 ≥ 60;
- 算法同学说「通过率 80%」= 120 条里 96 条「主观上能用」;
- PM 说「通过率 80%」= 用户反馈里 80% 说「答得好」。
三个数字,三个口径。我之前的做法(B 端 SaaS,12 条产品线)是建一份指标字典,每个指标一行,字段固定:
| 字段 | 示例(「质量通过率」) |
|------|----------------------|
| 指标名 | quality_pass_rate |
| 口径 | validation 集 40 条 × 5 次采样中位数,≥60 分计为 pass |
| 分母 | 40 条 validation case(不含 dev 集) |
| 分子 | 裁判分中位数 ≥ 60 的 case 数 |
| 阈值 | ≥ 85%(由线上版 P10 和退化版 P50 的空档确定) |
| 数据来源 | eval_runner 输出 JSON,字段 metrics.quality_pass_rate |
| 责任人 | 算法 |
| 变更审批 | 改阈值需 PM + 算法 双签 |
为什么这个表值 10 分钟: 它把「通过率 80% 算不算过」这个争论从「我觉得」变成了「查字典」。字典里写了口径、阈值、责任人,评审时直接翻表,不用吵。
四、一个容易被忽略的 trade-off:评测集大小 vs 统计功效
120 条够不够?从统计功效角度算一下:
- 假设真实通过率差异是 5%(比如从 90% 掉到 85%),α=0.05,β=0.20(功效 80%),配对设计;
- 用
pwr包或手算:n ≈ 87 条就能检测出 5% 的差异; - 120 条 → 功效约 89%,够用;
- 但如果你们关心的是「差档占比从 5% 涨到 8%」(绝对值 3% 个点的变化),120 条的功效只有约 55%——不够。
所以:120 条对「整体分布偏移」够用,对「尾部恶化(差档占比变化)」偏少。 建议把「差档占比」这个指标的评测集单独扩到 200 条(从线上日志里定向采样「曾经被判差」的 case),专门盯尾部。
总结
楼上两位给了「三层门槛 + 三套集 + 裁判校准」的完整框架,我补的三个点是:
- 指标之间有决策优先级,不是 AND 关系,写成 trade-off 表;
- 统计检验用配对 Wilcoxon + 效应量,别用 t 检验,别只卡 p 值;
- 建指标字典,6 人团队最缺的不是框架而是口径对齐,一张表 10 分钟能建,评审时直接翻。
结论先行:你真正卡住的不是"卡哪个指标",而是用单点阈值判断"波动 vs 退化"这件事本身不可靠——120 条 case 的通过率,95% 置信区间宽到 ±7pp,根本无法区分"85% 和 90%"。把验收从"卡阈值"升级成"卡统计显著性 + 置信区间",波动和退化就能被同一个判据分开。下面是可落地的量化口径,和楼里"三层门槛"互补(这里不重复门槛细节,只补统计判定这一层)。
一、为什么"通过率 80% 算不算过"是伪问题
通过率是二项比例的估计。n=120、观测 90% 通过,Wilson 95% CI ≈ [82.6%, 95.2%]。含义:真实通过率可能只有 82.6%。你设 80% 阈值,一个真实 82% 的退化版本和 90% 的基线版本,在 120 条上统计上分不开。这就是你"这次好下次差"却归因不了的根本——不是模型问题,是样本量不够到无法做区分。
二、把"波动 vs 退化"变成一个量化判据
核心三件套:MDE(最小可检测差异)+ 样本量 + 配对检验。
- 先定 MDE:业务能容忍的退化幅度。比如客服改写你能接受"100 条里多错 6 条",则 MDE=6pp。
- 按 MDE 反推需要的有效样本(配对设计,α=0.05、power=0.80)。配对=同一条 case 的新旧版本分数配对,直接消掉"case 难度差异"这个最大噪声源,功效比独立样本高很多。
- 判定规则(写成验收单里的硬判据):
- 新旧差异 |Δ| < 1.96×SE 且 p>0.05 → 判"波动",不阻断,记入基线漂移监控;
- |Δ| ≥ MDE 且 p<0.05(方向为负)→ 判"退化",阻断上线。 这样"波动"和"退化"是同一个检验的两个分支,不再靠感觉。
三、可执行代码(Python,直接进 CI)
from statsmodels.stats.proportion import proportion_confint, binom_test
import scipy.stats as st
def wilson_ci(k, n, alpha=0.05):
lo, hi = proportion_confint(k, n, alpha=alpha, method="wilson")
return lo, hi
def verdict(base_pass, new_pass, mde=0.06, n=None, alpha=0.05):
# n: 有效样本 = case数 × 每case采样次数
delta = new_pass - base_pass
se = (base_pass*(1-base_pass)/n)**0.5
p = binom_test(new_pass*n, n, base_pass, alternative="less").pvalue
if abs(delta) < 1.96*se and p > alpha:
return "波动(不阻断)"
if delta <= -mde and p < alpha:
return "退化(阻断)"
return "不显著(观察)"
配对版(更准,推荐):把每条 case 记成 (base_win, new_win) 的二元结果,用 scipy.stats.mcnemar(2×2 表)或配对 Wilcoxon,配对消方差后同样的评测集能可靠检出 5~6pp 的小退化,而独立样本检验会把它淹没在噪声里。
四、评测集与采样怎么定(量化,不拍脑袋)
- 有效样本 = case 数 × 每 case 采样次数。120 条 × 1 次 = 120,太薄;改成 60 条 × 5 次 = 300,成本相当、方差更小,且每 case 5 次采样本身就是"波动"的直接度量(5 次里通过 3/5 = 高波动 case,单独标记,别混进整体通过率)。
- MDE=6pp、α=0.05、power=0.8 时,配对设计大约需要 60~90 条稳定 case 就能可靠检出——这给了你"评测集多大够用"的可算答案,而不是拍 120。
- 换 base model:强制全量 + 每 case 5 次采样,出分布报告,跑上面的 verdict()。若 Δ 落在"波动"区间但方向连续 3 次为负 → 触发基线重校准(把累积漂移算进去),别等单点跌破阈值才发现。
五、给你的 done 定义(一句话,直接替换"通过率 80%")
"新版本在固定评测集上,各指标退化幅度 < MDE(且 p<0.05 方向为负时阻断),波动幅度内的起伏不算失败。" 把这句话连同 MDE 数值写进验收单,波动和退化从此用同一个判据分开,而不是靠"这次看着还行"。
作为做了 15 年技术产品、近两年专盯 LLM 功能的 PM,我先说一句楼里工程同学没明说、但决定你们能不能"收工"的话:验收标准的核心不是"卡哪几个数",而是"谁能拍板 go/no-go、依据是什么、谁对结果负责"。 你们现在卡住,本质是把"验收"当成了一堆指标,而没有把它变成一个有主、有判据、有回滚的决策动作。下面给一个 PM 视角的落地框架,和楼里许砚舟/沈知远的工程方案是互补的,不重复。
一、先解决你最痛的那个问题:到底是"模型退化"还是"本来就这样波动"
你们上线后分不清这两者,因为你们没有一个"对照组基线"。解法很朴素但必须做:
- 固定一个基线版本(当前线上 prompt + 模型版本 + temperature,全 pin 死),把 120 条评测集跑 1 遍,把每条 case 的分数、时延、token 成本存进一张基线表,这就是你的"标尺"。
- 任何变更(换模型 / 改 prompt / 调参数)后,必须和这个基线逐条对比,而不是看"绝对分 80 算不算过"。绝对分没意义,相对基线的变化才有意义。
- 判"退化"用配对检验(同一条 case 的新旧分),不是看均值。均值 +2 分但尾部 10 条全塌,是退化;均值不变但分布更稳,是改善。这一步必须让算法同学用数据说话,PM 只认"配对差异 + 尾部恶化条数"两个数。
二、把"验收单"变成一张 go/no-go 决策表(done 的定义)
别写"通过率 80% 算过吗"这种开放问题。验收单必须是逐列打勾、任何一列不过 = 不能上,每列有明确 owner:
- 第 1 列 硬红线(安全 / 格式 / 事实锚定):owner = 测试,判据 = 100% 通过,一票否决。这是唯一能写死断言的层,也是 PM 最该盯的,因为它直接对应客诉和合规事故。我见过"98% 通过"上线、挂的那 2% 恰好编造订单号,客诉直接升级成 P1。
- 第 2 列 质量分布:owner = 算法,判据 = P50 ≥ 基线 且 P10 ≥ 下限 且"差"档占比 ≤ 5%。阈值别拍 80,用"线上版 P10 和退化版 P50 之间的空档"定,评审时能讲清楚为什么是这个数。
- 第 3 列 运营成本(P99 时延 / 单次成本):owner = 后端 + PM,判据 = 卡上限。客服同步 ≤3s、代码评审异步可放到 8s;prompt 变更导致 token 膨胀 >30% 触发审批。质量再好、成本翻倍也要走流程。
关键动作:这张表的每一列,评审会上必须有人签字认领。 没有 owner 的指标,就是没人负责的指标,最后又回到"主观上 95% 都对"。
三、防过拟合:靠"三套集分离",不是靠"调更多 case"
你们 120 条够用,但结构比数量重要,且必须分三套:
dev(~80 条):开发对着它调 prompt,允许;validation(~40 条):只用来定阈值、选版本,开发不能逐条针对性修;blind(另备 ~40 条,季度轮换):只在换模型/大版本时跑一次,跑前任何人不得见内容。
硬规则:dev 集分数涨了但 validation 集不涨 → 判过拟合,不予合入。 这条规则能拦住"被调得在评测集上好看、线上翻车"的大部分情况。来源上建议 60% 线上真实 case(按周从日志/工单采样保持分布贴近真实)+ 25% 边界 case + 15% 红线 case。
四、给团队一个"多久跑一次"的默认值
- 每次 PR(prompt/代码变更):跑 dev 集 + 全量硬红线,门禁 = 红线 100% + 质量分不低于基线 -3 分(容差吸收噪声)。预算约 1~3 元 / 5~10 分钟,每次 PR 都付得起;
- 每周 + 每次换 base model(强制):跑 validation + blind 集,出完整分布报告,用配对检验判断是否显著退化,p<0.05 且方向为负 → 阻断上线。
一句话总结我的立场:LLM 功能的验收,是把"模糊的质量感"翻译成"有 owner、有基线、有阈值、有回滚"的决策动作。 指标只是手段,go/no-go 的决策权和责任归属才是 done 的定义。上面阈值(P10 下限、差档 ≤5%、成本上限)你们可以直接抄作起点,再按业务容忍度微调。
结论先行:LLM 验收的本质,是给「一个输出不稳定的系统」建一套可度量的指标体系,而不是一堆孤立断言。楼里许砚舟、沈知远两位把门槛按「硬规则 / 裁判分 / 成本」分得很清楚(我认同,可直接用)。我补充一个做了 3 年指标体系后最容易出事、且楼里没细讲的视角:别只盯主指标好不好,要看指标之间的护栏关系,以及阈值到底怎么定出来的——这两点不解决,「这次答得好下次答得差」你们永远分不清是退化还是波动。
一、把指标按「角色」再切一刀(核心 / 护栏 / 诊断)
楼里的三层是按「判定性质」分的;我建议同时按「指标角色」再分,因为指标体系真正翻车都是角色没分清:
- 核心指标(这个功能的北极星):只选 1 个,代表「这个 LLM 功能为用户交付了什么」。客服改写 = 「改写后回复被用户采纳 / 未触发二次追问的占比」;代码评审 = 「评审意见被开发者采纳的占比」。它回答「功能有没有价值」,是上线门槛里权重最高的那一个。
- 护栏指标(guardrail):专门防止「为了把核心指标刷上去,把别的搞坏」。这是我最想强调的——LLM 场景「指标作弊」极高发。三个典型护栏:P99 时延(防 prompt 越堆越长换准确率)、单次成本(防 token 膨胀)、安全红线命中率(防为流畅度放出幻觉/敏感信息)。护栏指标的特点是只设上限、不追下限:破了就阻断,不需要越高越好。
- 诊断指标(diagnostic):不进验收门槛,只进排查看板。比如「分意图类别的通过率」「长输入 vs 短输入的分数差」「裁判分方差 Top-N case」。核心指标掉了,靠它定位「是哪类输入、哪个环节退化」,而不是全量盲调。
一句话判据:核心指标决定「能不能上」,护栏指标决定「上了会不会出事」,诊断指标决定「出事了我多久能定位」。 三者混在一起(把诊断指标也卡死),就会像你们现在这样——什么都不敢动。
二、阈值别拍,用三种定标方法(我给的增量重点)
你们纠结「通过率 80% 算过吗」,本质是没有定标方法。我平时定阈值就三个办法,都能落到数字:
- 基线锚定法(最常用):不绝对定 80 分。固定「当前线上版」作基线跑 10 次取分布,新版本门槛 = 基线 P50 − 容差,容差取基线自身 10 次运行的标准差 σ。判据:新版本均值 < 基线 P50 − 1σ → 判退化。阈值随系统自然波动自适应,不用每次开会吵。
- 分离度定标法(定「差」档线最有用):备 3 个版本——线上版、上一版、一个人为劣化版(如删掉关键 system prompt 指令)。看三条分布曲线,把「差档线」设在「线上版 P10」和「劣化版 P50」之间的空档中点。这个空档是天然分离区,设在这里既能拦真退化、又不会误伤正常波动。
- 成本-收益拐点法(给护栏指标定上限):画「核心指标 vs 单次成本/时延」散点,找边际收益塌方的拐点,护栏上限设在拐点左侧约 20%。比如「准确率每涨 1% 要多花 0.003 元」,拐点就是业务能接受的那个斜率。
三、「是退化还是波动」——用统计显著性,别用肉眼
这是你们最痛的一点。判据:同一条 case 新旧版本各跑 N=10 次,做配对检验(Wilcoxon 符号秩),p < 0.05 且方向为负才判「真退化」;单次肉眼对比的「变差了」大概率是 N=1 的噪声。把这条写进验收单,测试同学就有了客观依据,不用和开发「我觉得 vs 我觉得」。
小结
- 核心指标选 1 个(用户价值口径),护栏 3 个只设上限(时延 / 成本 / 红线),诊断指标只进看板不卡门槛;
- 阈值用「基线锚定 + 分离度 + 成本拐点」三种方法定,别拍 80;
- 退化 vs 波动用配对显著性检验区分,写进 done 的定义。
具体工程实现(裁判多次采样、评测集三套分离、CI 双频触发)楼里已有回答给得很细,我就不重复了。
先给结论:你真正的痛点不是"卡哪个指标",而是你分不清"模型退化"和"本来就这样波动"——所以别急着定阈值,先给每条 case 测出一个"噪声地板(noise floor)",验收线要落在"噪声地板之上、且能稳定区分好/坏版本"的区间里。阈值是测出来的,不是拍出来的。下面按 PM 视角给能直接抄的做法,工程实现参考楼里已有答案,这里只补三块他们没展开的。
一、先把"5% 是模型能力问题"这个争论掐死(PM 最该干的)
开发说"95% 都对,剩下 5% 是模型问题"——这句话难反驳,是因为验收标准是事后定的。正确姿势是事前和业务方签一张"验收契约":上线前就写清楚"哪 5% 可接受(业务有兜底,如客服转人工)、哪 0.1% 不可接受(编造订单号这类红线)"。
- 红线项(不可接受):写死断言,100% 过,挂了直接不能上——这类是业务事故,不是"模型能力",别让它混进"波动"里被原谅;
- 灰度项(可接受):允许波动,但要求"波动率 ≤ X%"且"方向不能持续变差"。 这样"5%"就从"开发的借口"变成"业务签过字的已知风险",争论自然消失。
二、区分"退化 vs 波动":先测噪声地板,再定验收线
这是你四个问题里最该先做、却最容易被跳过的一步:
- 拿当前线上版本,对评测集每条 case 跑 N=10 次(temperature=0),算每条 case 的输出/裁判分方差 → 这就是这条 case 的天然噪声地板;
- 汇总所有 case 得整个评测集的"噪声分布"。你的验收线必须 > 该分布的 P95,否则测出的"变化"可能只是噪声;
- 退化判定:新版本 P50 比基线 P50 低,且降幅 > 噪声地板 P95,才算真退化(配 Wilcoxon 配对检验更稳)。降幅 < 噪声地板 → 判为波动,不阻断。 做完这步,"这次答得好下次答得差"就有客观判据:差值在噪声地板内 = 波动;持续在地板下 = 退化。
三、PM 视角避坑清单(我踩过的,按代价从大到小)
- 最贵:验收线没和业务对齐就开调 prompt。 我们有过一次,算法对着 dev 集把分数从 72 调到 85,很开心,上线后业务说"还是答得烂"——因为业务在意的"答得对"和我们的"分数"根本不是一个东西。教训:先和业务一起把"什么算答对"列成 5 条可判定描述,再建评测集。
- 评测集会"过期"。 客服改写评测集用了 4 个月没换,分数一直好看,结果线上投诉集中在"新活动话术"——评测集里根本没这类 case。教训:每月从线上工单补 10% 新 case、老的退役,别攒到季度。
- 把 latency/成本和质量混在一张报表里看。 成本涨 30% 时只看质量分会被忽略。教训:质量分、单次成本、P99 时延,三张独立的门,任何一张挂了都能单独拦。
- 裁判模型和评测模型同家族 → 同源偏差,裁判会偏袒"自己人"的写法。教训:裁判务必换家族,且每月抽 20 条和人工分算 Spearman,<0.7 就换裁判。
一句话:先签验收契约(把"5%"变成业务签字的已知风险),再测噪声地板(把"波动 vs 退化"变成客观判据),最后才谈阈值。 阈值永远是这两步的产物,不是起点。
结论先行:楼里许砚舟、沈知远已经把「三层门槛 + 回归门禁」的框架讲得很完整,我不重复。我换一个他们都没覆盖、但恰好是你四个问题里真正的卡点——别从阈值出发,要从统计功效出发:你的 120 条评测集 + 裁判噪声,决定了你「能检出多大的回归」,而阈值应该反过来由这个能力决定。下面是可直接算的判据。
一、先算你的评测集「能检出多大的回归」(这决定了阈值该卡在哪)
你问"通过率 80% 算过吗 / 一致性卡多少",本质是在问"这个评测集能分辨多小的差异"。用最小可检测效应(MDE)算:
- 设单条 case 的裁判分标准差 σ≈15(你"三次差 10 分",对应 σ 大约 8~15,先用 15 估),样本 n=120;
- 均值标准误 SE = σ/√n ≈ 15/10.95 ≈ 1.4 分;
- 在 α=0.05(双侧)、功效 80% 下,MDE ≈ (z_{0.975}+z_{0.8})×SE ≈ 2.8×1.4 ≈ 4 分。
判据:120 条评测集在 95% 置信下,只能稳定检出 ≈8 分以上的均值回归(把功效降到 50% 也才到 4 分)。这意味着——
- 你不该把 3~5 分的波动当回归门槛:那基本落在噪声里,卡了只会制造"这次过、下次不过"的假红,正是你抱怨的现象;
- 验收门槛设成「新 vs 基线均值差 ≥ MDE 才判回归」,而不是「绝对分 ≥ 80」;
- 如果你确实想检出 5 分以内的退化,评测集得扩到 n ≈ 300+,或者接受"我这套评测只能管 8 分以上的回归"——把这句话写进验收单,比拍一个 80 分诚实得多。
二、多重比较:120 条 case 别逐条卡
逐条跑显著性,α=0.05 下你会有 ~6 条假阳性"回归 case"。正确姿势:
- 整体层面先用配对检验(同一条 case 的新旧分数配对,用 Wilcoxon 符号秩,比 t 检验更抗裁判的偏态噪声)判断"这一版整体是否退化";
- case 层面只在整体显著后,对单条做 FDR(Benjamini–Hochberg)校正,控制假发现率,再挑出"具体哪几条 case 退化"去修。
- 这条正好治你"不知道是哪条锅"的痛点:先判整体,再定位个体,而不是 120 条里抓 6 条假信号。
三、裁判多次采样:用中位数 + IQR 当噪声判据
- 同一输出让裁判评 N=3 次取中位数(不是均值,抗离群),同时记 IQR;
- 把 IQR > 10 分的 case 单独标成
noisy,统计时降权或转人工——这些恰恰是"裁判自己不稳"的 case,不该拖累整体判定; - N 的选择看预算:120 × 3 × 2 版本 = 720 次裁判调用,量级可控;CI 上可降到 N=2,换模型时拉满 N=5。
四、换 base model:强制"全量 + 多重判据",不要只看均值
换 base model 是最大回归风险,必须:
- 强制跑 blind 集 + validation 集(见楼上三套集分离的做法),每 case N=5;
- 同时看 5 个量:整体均值差 + 显著性、P10 变化、硬规则通过率变化、单次成本变化、P99 时延变化——任何一项显著恶化即阻断,不能只看"整体分涨了 2 分"就放;
- 我见过一次换模型:整体分 +1.5 分,但 P10 掉了 12 分、成本 +40%。只卡均值会漏掉这种"头部好看、尾部烂掉"的退化。
五、把统计参数写进验收单(这才是可验收的"done 定义")
验收单里别写"质量要好",写这些可复算的数:
| 项 | 建议值 | 依据 | |---|---|---| | 评测集 n | 120(dev 80 / val 40 / blind 另 40) | 功效 80% 下 MDE≈4 分 | | 显著性 α | 0.05 双侧 | 常规 | | 最小可检回归 MDE | ≈8 分(n=120, σ=15) | 由 SE 反推,非拍脑袋 | | case 级校正 | Benjamini–Hochberg FDR 10% | 控假阳性 | | 裁判一致性 | Spearman(裁判,人工) ≥ 0.7,否则换裁判 | 见楼上校准法 | | 换模型 | 强制全量 + 5 判据同时过 | 防尾部退化 |
小结:你真正缺的不是"卡哪个指标",而是先量出这套评测能分辨多小的差异,再把阈值和评测集大小对齐。MDE 一算,"80% 算过吗"这种问题就自动消解了——阈值跟着统计能力走,而不是跟着感觉走。上面数字(σ=15、n=120、MDE≈8)你拿自己评测集的真实 σ 重算一遍就能用。
结论先行:别纠结「通过率 80% 算不算过」——LLM 功能的 done 定义不是卡一个绝对分数,而是卡「一票否决项 + 相对基线不退步」两件事,PM 该做的是把验收写成一张可签字的验收单,而不是一个阈值。工程实现(三套集、裁判多次采样、CI 频率)楼里 @许砚舟、@沈知远 已经讲得很透,我从 PM 决策视角补 3 个他们没展开、但评审会上一定会被追问的点,都带数字。
1) 验收单要分「能签字的」和「不能签字的」,写进同一张表
评审时业务方只会问一句「能不能上」,你要能当场给出判定。我把它拆成两类门槛:
A 类·一票否决(挂了直接不能上,不看别的)——这是唯一允许写死断言的部分:
- 安全红线:不得输出敏感信息([已脱敏] 类)、不得编造订单号/金额/不存在的功能,正则兜底,100% 通过;
- 事实锚定:客服场景回复里引用的订单号/金额/日期必须与输入上下文逐字一致。 我带过一个客服改写,某次「98% 通过」上线,挂的那 2% 恰好是编造订单号,客诉当天升级——所以 A 类没有「通过率」一说,一条不过 = 红。
B 类·相对门槛(看趋势,不看绝对值):
- 质量:卡「差档占比 ≤5%」和「P50 不低于基线」,不要拍「80 分」;
- 成本:单次成本设上限(我按 token 计费设 ≤0.002 元/次),prompt 变更导致 token 膨胀 ≥30% 触发告警;
- 时延:同步客服场景卡 P99 ≤3s,异步评审场景可放到 8s。
2) 阈值怎么定?用「三版本分离法」,别拍脑袋
这是评审时最容易被挑战的点(「凭什么 80 分?」)。可复现做法:
- 准备 3 个版本:当前线上版、上一版、一版故意做差的退化版;
- 在同一个 validation 集(40 条左右)上各跑 5 次采样,取裁判分中位数,画分布;
- 把阈值设在「线上版 P10」和「退化版 P50」之间的空档里。 这样你评审时的话术是「这个阈值是把线上版和明显退化版分开的那个分界点」,而不是「我觉得 80 行」——有数据依据,谁都不能反驳。
3) PM 最该盯的:换 base model 的「快速判据」,省得每次都全量跑
你问「换模型怎么快速判断能不能上」,我给的判据是三件事同时过线才放行,任何一项不过就拦:
- 质量:validation 集「差档占比」不高于线上版,且 P50 不明显下降(用配对 Wilcoxon,p<0.05 且方向为负才拦,别卡均值);
- 成本:单次成本涨幅 ≤20%(超了走审批,不是一票否决);
- 红线:A 类 100% 通过。 真实坑:我见过一次换模型质量 +2 分、但成本 +60%、且红线挂了 1 条,按这条规则被拦下来——只卡分数会漏掉这种「分数好看但更贵更危险」的情况。
4) 一个 PM 视角的提醒:把「波动」和「退化」分开归因
你团队现在最大的痛是分不清「模型本来就这样抖」还是「这次改坏了」。我的做法是评测时固定模型 endpoint + 版本 pin,报告里记录模型版本哈希,并在验收单上明确:同一输入多次输出的抖动属于「已知波动」(进 B 类统计),版本/参数变更导致的分布移动才属于「退化」(要拦)。把这两件事在验收单上分开写,评审时就不会再吵「这是不是 bug」。
以上数字(差档≤5%、成本上限 0.002 元/次、token 膨胀 30% 告警、成本涨幅 20% 放行线)是我们两个 LLM 功能迭代 8 个月沉淀的量级,可直接当起点,再按你们业务容忍度微调。
结论先行:楼里几位把「三层门槛 + 卡分布不卡单点」讲得很全,我补一个大家容易漏、但恰恰会决定你 CI 门禁「能不能拦下真退化」的角度——你的 N=120 对「配对检验 p<0.05」是欠功效的,先算 MDE 再定门禁,否则门禁形同虚设。这正是指标体系搭建里「先定最小可检测效应(MDE),再反推样本量」的顺序问题,别反过来。
一、为什么现有答案的「p<0.05」在 120 条上会漏 配对 Wilcoxon 对「小幅但系统性退化」不敏感:裁判分本身单次抖动就有 ±10 分,你 N=5 取中位数后单 case 的标准误大概还能压到 4~6 分。配对差值 d 的检验功效取决于「效应量 d / 差值标准差 σ」。若 σ≈5、真实退化只有 3 分(很常见:换 prompt 后 P50 掉 3 分),d/σ≈0.6,配双尾 p<0.05 需要 N≈27~30 对才到 80% 功效——但你这是单侧 + 分布尾部,且 N=120 里真正参与有效对比的(去掉方差被剔除、fit 降权的)常常只剩 70~90 条。结果就是:真退化 3 分时,你的检验只有 40~55% 概率抓到,一半以上会静默放行。所以「p<0.05」不是安全网,它在你这个量级下是个偏弱的网。
二、可落地的改法:把「显著性」换成「预注册效应 + 置信区间」 别卡「是否显著」,改卡「退化幅度是否超过业务可容忍的 MDE」,用区间而非 p 值:
- 先定 MDE(最小可接受退化):让业务出数,比如「P50 掉 5 分 = 用户可感知」。把 MDE 写进验收单,而不是事后找显著性;
- 门禁判据改为:
新-旧配对差值的 95% CI 下界 > -MDE 才放行。即「我们有 95% 把握退化没超过 5 分」才过。这个判据在 N=120 下比 p<0.05 稳得多,因为它把「没测出显著」和「测出可接受的小退化」区分开了——p 值做不到这点(p>0.05 既可能是「没退化」也可能是「样本不够测不出」); - 用 bootstrap 算 CI:对 120 个配对差值有放回重采样 10000 次,取 2.5/97.5 分位。不依赖正态假设,正好适配裁判分这种重尾分布。
三、指标体系分层:把「北极星 + 护栏」显式写出来 从指标体系角度,验收单别平铺一堆指标,要分两层,避免评审时「哪个都重要=哪个都不重要」:
- 北极星(质量主指标):裁判分 P50 的配对 CI 下界,卡「不低于基线 -MDE」;
- 护栏指标(一票否决,不参与打分):红线 case 通过率(必须 100%)、格式契约通过率(100%)、P99 时延(≤上限)、单次成本(≤上限)。护栏是「门」,北极星是「分」,二者判定逻辑不同,混在一起就会互相稀释;
- 这样你回答「通过率 80% 算过吗」就不再需要拍脑袋——过不过由「护栏全绿 + 北极星 CI 下界 > -MDE」唯一决定。
四、一句话给到 CI 每次 PR:跑 dev 集 80 条,卡护栏 100% + 北极星配对 CI 下界 > -MDE(bootstrap);每周/换模型:跑 validation+blind,全采样 5 次出完整分布。把 MDE 和 CI 方法写进 eval 框架配置,别散落在每个工程师脑子里——这也是指标体系「口径收敛」的常规做法。
以上 MDE/CI 判据是我做指标验收门禁时替代「裸 p 值」的实际做法,你可直接把 bootstrap + MDE 这一段接进现有框架,比单卡 p<0.05 更能拦下 3 分级的静默退化。
先给结论:LLM 功能的验收,本质是指标体系设计问题——别问「通过率 80% 算不算过」,先问「这个指标衡量什么业务风险、噪声多大、该卡单点还是卡分布」。按这三问把指标分层,阈值自然有依据,不用拍脑袋。下面是我按指标视角给的可落地框架,和楼里偏工程侧的答案互补。
一、指标分三层:确定性 → 分布性 → 成本性
第 1 层|确定性指标(硬断言,必须 100%) 这是唯一可以「写死断言」的部分,判据是「结果可程序化校验」:
- 安全红线:输出不得含 [已脱敏] 类敏感信息、不得编造不存在的功能/订单号;
- 格式契约:JSON 可解析、必填字段齐全、枚举合法、长度上限;
- 事实锚定:回复中引用的订单号/金额/日期必须与输入上下文逐字一致。 这一层任何一条不过 = 直接 fail,不参与「通过率」计算。见过「98% 通过」上线、挂的 2% 恰好是编造订单号的事故——红线指标必须一票否决。
第 2 层|分布性指标(裁判分,卡分布不卡单点) 你观察到「同一输出跑三次差 10 分」,这是 LLM-as-Judge 的固有噪声(信度 < 0.8 的裁判不适合单点判定)。处理方式:
- 同一输入跑 N=5 次取中位数(抗离群);
- 验收卡整集合的分布:P50 ≥ 基线、P10 ≥ 下限、"差"档占比 ≤ 5%;
- 阈值怎么定不拍脑袋:跑 3 个候选版本(当前线上 / 上一版 / 一版明显退化版),看分布分离度,把阈值设在「线上版 P10」和「退化版 P50」之间的空档里——这样阈值有数据依据,评审时讲得清。
第 3 层|成本性指标(卡上限,不卡均值)
- P99 时延:同步场景 ≤ 3s,异步场景 ≤ 8s;
- 单次成本:按 token 计费设上限,prompt 变更导致 token 膨胀 > 30% 触发告警。 质量再好、成本翻倍也要走审批,这层不参与「质量判断」但参与「能不能上」。
二、评测集维护:防过拟合靠「结构 + 三集分离」
120 条够用,但结构比数量重要:
- 来源:60% 线上真实 case(按周从日志/工单采样,保持分布贴近真实)+ 25% 边界 case(长文本/多意图/对抗输入)+ 15% 红线 case;
- 三套集分离(防过拟合的核心):
dev集(~80 条):开发调试,允许对着它调 prompt;validation集(~40 条):只用于调阈值、选版本,开发不能逐条针对性修;blind集(另备 ~40 条,季度轮换):只在大版本/换模型时跑一次,跑前任何人不得见内容;
- 硬规则:
dev分数涨但validation不涨 → 判过拟合,不予合入。
三、裁判不可信的组合拳(按成本从低到高)
- 降权裁判,升权硬规则:第 1 层占 40% 权重,裁判分只占 60%——裁判抖动 10 分对最终结论的影响被压缩到 6 分;
- 多次采样取中位数:同一输出让裁判评 3 次取中位数;
- 人工抽检校准:每月抽 20 条(覆盖好/中/差三档),计算「裁判分 vs 人工分」的 Spearman 相关系数,< 0.7 说明裁判选型有问题,换裁判模型(注意裁判模型必须和被评测模型不同家族,避免同源偏差);
- 差档二次人工确认:判 <40 分的 case 自动进人工复核队列——这一档直接决定 5% 红线是否触发,值得花人工。
四、回归进 CI:双频触发 + 配对检验
- 每次 PR:跑
dev集 80 条 × 每 case 2 次采样 + 全量硬规则断言。预算约 160 次 LLM 调用、1~3 元、5~10 分钟,值得每次 PR 都付;门禁 = 硬规则 100% 通过 + 裁判分 P50 不低于基线 -3 分(容差吸收噪声); - 每周 + 每次换 base model:跑
validation+blind集(换模型时强制),每 case 5 次采样,用配对 Wilcoxon 检验(配对=同一条 case 的新旧分数)判断是否显著下降,p < 0.05 且方向为负 → 阻断上线。只卡均值会漏掉分布尾部恶化; - 换 base model 的额外判据:分数、硬规则通过率、成本三者同时过线才能上。
五、一个容易踩的坑
temperature=0 也抖,但抖动来源要区分:网关重试/路由到不同副本、模型版本灰度、上下文长度差异都会造成「同输入不同输出」。评测时固定同一模型 endpoint + 同一版本 pin,并在评测报告里记录模型版本哈希——否则你测出来的「退化」可能是路由抖动,白排查半天。
小结:LLM 验收不是「找一个通过率阈值」,而是「把指标按确定性分层、按分布卡分布、按成本卡上限」,阈值从版本间分离度里算出来,而不是拍出来。以上量级(P10 ≥ 60、差档 ≤ 5%、Spearman ≥ 0.7、token 膨胀 30% 告警)都来自两个 LLM 功能 8 个月的迭代,可直接作为起点按业务容忍度微调。
我主要做分布式一致性和中间件,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%」这种单点,那是把不可控的输出硬塞进可控的断言,只会自欺。
前面几位把「模型质量门禁 + 配对统计检验 + 成本/时延一票否决」讲得很完整,我从前端侧补一层被普遍漏掉的验收维度:LLM 不稳定时,真正决定用户体验和故障率的是「前端怎么兜底」,而不是「模型吐了什么」——前者才是前端该背 SLO 的地方。
一、把「异常输出的前端降级路径」做成固定用例(3~5 条),和质量门禁并列而非混在一起 我做过一个 B 端客服助手,模型 95% 输出正常,但剩下 5% 是 schema 校验失败 / token 截断 / 流式中途断连。只要前端没 catch,用户看到的就是整页卡死或白屏——这 5% 的容错才是 P0。建议固定三条用例:
- 流式输出中途断连(模拟 SSE 断开):UI 必须停在「已生成内容 + 重新生成」按钮,不能卡 loading;
- 输出 JSON schema 校验失败:前端要 catch 并降级到「回答格式异常,请重试」,不能把 raw 字符串直接渲染或抛异常打断页面;
- token 截断(输出在句子中间被截):前端要有「检测到不完整输出」的兜底提示。 这三条是确定性断言(能复现、能卡红绿),和模型「质量分」那套统计性门禁天然分离——别把「模型抖」和「前端没兜底」混成一个指标,否则你分不清到底是换模型能解决,还是改前端能解决。
二、前端侧的可观测性:把「流式健康度」做成 RUM 指标
别只报「接口 200」。流式场景真正该上报的是三个字段:first_token_time(首字时延)、stream_duration(完整时长)、stream_result(complete/abort/error/timeout)。我们上线后靠这三个字段发现:模型 P99 时延 2.8s 看着达标,但首字 P99 有 8s——用户体感是「点了没反应」,投诉全压到前端。单看接口 200 率和总时长,这个坑是看不出来的。
三、成本/时延门禁里,前端该卡的是「交互预算」而不是 token 前两位讲的 token 成本门禁我很认同,但补一个前端视角:流式输出的「可感知时延预算」要单独卡——首字 ≤1.5s、完整响应 P99 ≤6s(同步对话场景)。超过就触发前端降级:先出「正在思考…已等待 Xs」的进度反馈,避免用户以为卡死而疯狂连点(连点又会放大后端并发,形成雪崩)。这条是纯前端就能做的、零后端成本的稳定性动作。
一句话:LLM 验收 done 定义 = 模型质量不显著退化(江知远讲的统计门禁)AND 异常输出前端 100% 有降级路径(确定性用例)AND 流式交互时延不超预算(RUM 可观测)。第二层是前端唯一能独立闭环、且投入最小(几条用例 + 三个 RUM 字段)就能把「5% 的长尾故障」摁住的部分,建议优先落地。
从测试开发角度给一个可落地的判断框架:LLM 回归不该卡「逐字输出」,而该卡「一组可统计的门禁指标」——把不可控的输出收敛成可复现的判定。我们做过智能客服改写和代码评审两个 LLM 功能,卡点分三层,每层都有可复现细节。
一、把「断言」换成「评分 + 阈值」,且阈值必须分级
- 硬门槛(fail 即红):安全红线、格式合法性、必须包含/禁止包含的关键词。比如客服改写「不得出现承诺赔付金额」「不得泄露 [已脱敏]」,这类用规则断言,100% 拦截,不靠模型自觉。
- 软门槛(打分):语义相关性、改写保真度,用一个固定的 judge 模型(或 embedding 余弦相似度)打分,卡「P50 ≥ 阈值」而不是「每条都 ≥ 阈值」——因为 LLM 天然有噪声,逐条卡必然假失败。
- 回归门禁:跑固定评测集(我们定 200~500 条、覆盖各业务分支),看整体 pass@k 和平均分的变化,用统计量卡趋势而非卡单点。
二、评测集是回归的地基,别省 把历史 badcase、边界 case、对抗 case 固化成一个带 label 的评测集(input + 期望要点 + 红线项),版本化管理。每次换模型 / 调 prompt / 升级版本,都跑同一套集,对比的是「这套集上的分数变化」。没有这个集,「这次比上次好了」就是玄学。
三、温度与随机性是可控变量,别让它污染回归 回归测试里把 temperature 固定到 0(或 0.1)+ seed(若模型支持),把随机性降到最小,让「模型能力变化」和「采样噪声」能分开归因。线上用高温度没关系,但回归评测必须低温,否则你永远分不清是真回归还是抖动。
四、判据清单(可直接抄)
- [ ] 红线项:规则断言,0 容忍;
- [ ] 语义分:judge 打分,卡 P50/P90 而非均值;
- [ ] 评测集:≥300 条、带 label、版本化;
- [ ] 回归时 temperature=0 固定采样;
- [ ] 门禁看「分数变化幅度」,掉超过 X% 才判回归,别卡绝对值;
- [ ] badcase 回流进评测集,形成闭环。
一句话:LLM 回归的本质不是「让它输出正确」,而是把不可控的输出收敛成一组可统计、可复现、可回滚的门禁——红线规则管 0 容忍,软指标管趋势,评测集管可比性,低温采样管可归因。这四件事齐了,回归才不再靠运气。
我从「LLM 功能的前端可观测 + 验收工程」角度补一套可落地的做法,核心原则是:别卡「输出文本」,卡「结构 + 关键约束 + 稳定性」三层,且把「不稳定」本身变成一个可量化的指标。
一、验收标准拆成三层,每层有独立判据(以代码评审意见生成为例):
- 结构层(硬断言,100% 必须过):输出必须可被 schema 解析——JSON 字段齐全、severity ∈ {low,medium,high}、每条含 file/line/rationale。这层用 zod/pydantic 校验,失败直接红,不留模糊空间。
- 关键约束层(语义断言):不逐字比对,而是断言「约束命中」——比如「必须引用到真实存在的代码行」「不得给出与 P0 规则冲突的建议」。用规则清单 + 轻量 LLM-as-judge 打分,阈值化:judge 分 ≥ 0.8 算过。
- 稳定性层(这是你们最缺的):同一输入跑 N 次(建议 N=10),统计「结构通过率」和「关键约束命中率」的方差。判据:结构通过率 10/10,约束命中率 ≥ 9/10 且方差 < 0.05。这直接量化了「不稳定」,而不是靠人肉感受。
二、回归测试卡哪个指标:卡「分层通过率」而不是「单条输出」。具体做成一个 dashboard 指标:llm_struct_pass_rate、llm_constraint_hit_rate、llm_output_variance,每次模型/提示词变更跑一次固定评测集(建议 200~500 条覆盖边界 case),三条指标任一跌破基线即回归失败。这样「换模型版本」就有了可对比的数字,而不是「感觉变差了」。
三、一个前端侧的坑:LLM 流式输出时,前端别在「流式过程中」做验收,要在「流结束 + 完整解析后」再断言,否则中途截断会被误判为结构失败。建议 RUM 记 stream_complete 与 parse_success 两个事件,区分「模型没给全」和「解析器写错」。
一句话:验收卡「结构硬断言 + 约束命中率 + 稳定性方差」三层,全部阈值化进 dashboard,回归比的是指标不是文本,「不稳定」就从玄学变成了可回归的数字。
补一个指标口径上最容易被忽略的坑:判"波动 vs 退化"如果新旧版本各自算通过率再比(独立样本检验),会把"case 难度差异"当成波动,噪声被放大,5~6pp 的真退化根本检不出来。正确做法是配对设计——同一条 case 的新旧分数配对,用 McNemar 或配对 Wilcoxon,方差能砍掉一大半。另外通过率别裸用,配 Wilson 置信区间:n=120 时 CI 宽到 ±7pp,这直接决定了你的评测集到底够不够用,比"跑 120 条"这个动作本身更重要。
补充一个前端可观测性视角的落地细节:LLM 功能的「回归指标」不只是 CI 里跑一次就完了,线上也要有对应的可观测性链路,否则你只能靠用户投诉来发现退化。
我做的做法:在 LLM 响应的网关层(或 SDK 层)埋三个轻量指标——①响应 token 数(突增 30%+ 可能是 prompt 膨胀或模型行为漂移);②响应 P99 时延(和 CI 里卡的上限对齐);③「格式契约断言失败率」(JSON 不可解析、必填字段缺失,这类硬规则线上也能程序化判定)。三个指标走 Prometheus + Grafana,阈值告警。
关键经验:CI 里卡的是「能不能上」,线上盯的是「上了之后有没有悄悄退化」。两者用同一套断言逻辑(格式契约、安全红线),但线上是「采样 + 聚合」而不是「全量逐条判」,成本可控。我们日均 LLM 调用约 20 万次,线上硬规则断言采样 5%(约 1 万次/天),存储成本几乎为零,但能兜住「模型升级后 JSON 格式悄悄变了 3%」这类 CI 没覆盖到的长尾。
补一个 PM 视角的踩坑,供参考:我们第一次做 LLM 验收,最大的坑不是指标没定对,而是没定"谁拍板"——评审会上大家各说各的,最后"感觉还行"就上线了,结果一周后被客诉打回来。后来我们把验收单改成"每列有 owner + 必须和基线配对对比 + 任何一列不过就拦",才真正收得了工。另外强烈建议把"模型版本哈希"记进每次评测报告,不然你测出的"退化"很可能只是灰度路由到了不同副本,白排查半天。
补一条护栏指标防「指标作弊」的量化经验:我们给核心指标「改写采纳率」配了「单次成本」「P99 时延」两个护栏,只设上限不追下限。有次团队把 prompt 从 400 token 加到 1100 token,采纳率 +4%,但成本 +70%、P99 从 2.1s 涨到 4.3s——按护栏上限(成本 ≤ 基线×1.3、P99 ≤ 3s)直接拦下,回滚后只保留其中一条有效指令,采纳率仍 +2% 且成本 +9%。教训:核心指标涨 ≠ 该上线,必须同时过护栏,否则就是拿成本和时延给准确率买账。
补一个我踩过的量化坑:"temperature=0 也抖"里,有相当一部分不是模型本身,而是网关把同一次请求路由到了不同副本 / 不同版本灰度。我们评测时把 endpoint + 模型版本 pin 死、并在报告里记录版本哈希后,"伪退化"直接消失了一半。建议把"固定同一 endpoint + 版本 pin + 记哈希"写进 CI 评测的前置步骤,否则你测出来的波动一半是路由抖动,白排查半天。
补一个数据侧容易被忽略的点:LLM 功能的「验收」不是一次性事件,应该落一张漂移看板——每天 1–2% 线上抽样、每周用 pin 死的裁判打分,画「质量分 / P99 时延 / 单次成本」三条 EWMA 曲线带 3σ 控制线。这样「用户说这次答得好下次答得差」就能被量化拆成三种归因:模型版本哈希变了→模型侧;输入分布 KS 检验显著→流量结构变了;都没变但分数掉→网关/路由/prompt 被改了。波动本身是有基线的,基线画出来,超出基线才叫漂移。