把 Microsoft-Decision-1 的输出分数当成候选筛选的门槛时,真正要定下来的是两件事:阈值取多少,以及分数低于阈值或贴着阈值的那批候选怎么处理。这两件事都不适合靠直觉拍板。通常的做法是取一段已经有人工结论的历史记录,把决策输出重新算一遍,按若干候选阈值回放比对,再挑一个能解释、能回退的边界,最后用没参与调参的样本复测一次。
阈值不要直接沿用模型默认分界点,也不要凭感觉取整。先抽一批已有人工结论的历史样本,把输出分数按几个候选阈值回放,记录每档阈值下的命中、漏放和误收;再按误判类型区分是输入问题还是边界问题。选定阈值时同步写明适用条件和人工回退动作,最后用未参与调参的样本复测,确认这个阈值不是只贴合那一批老数据。
从历史记录里抽出已有人工结论的样本
回放的前提是有一批可对比的样本,样本必须同时带上模型输入和人工结论,否则后面只能看分数分布,看不出对错。
- 样本来源:从已有的筛选记录里取,优先选流程完整、字段齐全的那批,例如历史提交表、人工审核结果表、下游处理记录。
- 人工标签:以人工最终结论作为参照标签,例如通过/拒绝、需要补充材料、转人工复核。标签口径要统一,避免同一批样本里混用两套判定标准。
- 排除标准:人工结论本身有争议的、输入字段缺失或空值的、同一对象重复提交的、结论后来被推翻的,建议先剔除,放进单独的观察集,不要混进调参样本。
- 样本量说明:样本量以能覆盖到每一类结论为准,量少时阈值只能当初始值,后续继续积累再校准;不要用几例样本就断言边界稳定。
-- 通用取样骨架,表名和字段按实际环境替换
select
s.request_id,
s.raw_input,
m.score as model_score,
r.human_label as human_label
from submit_record s
join decision_output m on m.request_id = s.request_id
join human_review r on r.request_id = s.request_id
where s.created_at between :start_time and :end_time
and r.human_label is not null
and s.field_missing_flag = 0
order by s.created_at;把 Microsoft-Decision-1 输出与人工结论按阈值对比
先把候选阈值列出来,再写一段回放脚本读同一批样本,逐个阈值算一遍命中、漏放、误收和需要人工复核的量。阈值本身建议放进配置,不要硬编码在业务代码里。
- 阈值列表:可以从输出分数的分位点取几个档,例如 0.3、0.4、0.5、0.6、0.7,再补上业务上可解释的点位;档位之间留出间隔,方便看清变化趋势。
- 对比表:表里只填回放得到的实际计数,不要用估计值。
| 候选阈值 | 命中数 | 漏放数 | 误收数 | 贴边待人工数 |
|---|---|---|---|---|
| 0.3 | 待填 | 待填 | 待填 | 待填 |
| 0.4 | 待填 | 待填 | 待填 | 待填 |
| 0.5 | 待填 | 待填 | 待填 | 待填 |
| 0.6 | 待填 | 待填 | 待填 | 待填 |
| 0.7 | 待填 | 待填 | 待填 | 待填 |
# 回放骨架:读样本,遍历候选阈值,输出计数
thresholds = [0.3, 0.4, 0.5, 0.6, 0.7]
for t in thresholds:
hit = miss = wrong = edge = 0
for s in samples:
pred = 1 if s["model_score"] >= t else 0
if pred == 1 and s["human_label"] == "pass":
hit += 1
elif pred == 0 and s["human_label"] == "pass":
miss += 1
elif pred == 1 and s["human_label"] != "pass":
wrong += 1
if abs(s["model_score"] - t) <= 0.05:
edge += 1
print(t, hit, miss, wrong, edge)记录不同阈值下的误判类型
只统计数量不够,还要把误判样本逐条看一遍,分清是输入信息不足导致的判断偏差,还是阈值本身卡在模糊区间上。这一步的产物是一张误判分类表,而不是一句“阈值再调调”。
| 误判分类 | 典型样本特征 | 可能原因 |
|---|---|---|
| 输入缺失 | 关键字段为空或格式异常,分数仍落在筛选区间内 | 上游校验没拦住,模型对缺失输入的输出不可靠 |
| 阈值过严 | 人工结论为通过,分数略低于当前阈值 | 阈值卡在高分位,长尾正常样本被漏放 |
| 阈值过宽 | 人工结论为拒绝,分数略高于当前阈值 | 阈值偏低,把边界样本一起放进候选 |
| 口径不一致 | 模型与人工对同一输入判断方向相反,且输入完整 | 人工规则与模型定义不同,需要先对齐口径再谈阈值 |
选一个可解释的阈值并写明回退动作
阈值选定后要落到配置里,并写清楚它在什么条件下有效、越界时谁来处理。
- 阈值:选一个在对比表中误收和漏放都可接受、且业务上能解释的点位,不要单纯选统计上最优的那一档。
- 适用条件:写明适用的业务流程、输入字段完整性要求、模型版本。字段缺失率升高或模型版本更换时,阈值需要重新回放确认。
- 回退动作:分数低于阈值但字段完好的,转人工复核;分数落在阈值附近的,走人工兜底而不是直接拒绝;输入缺失的直接退回补全,不进入筛选判断。
- 责任角色:配置变更由谁提交、谁复核、谁处理人工队列,都要在规则文档里写清,避免阈值改了没人知道。
{
"threshold": 0.5,
"edge_band": 0.05,
"on_below": "manual_review",
"on_edge": "manual_review",
"on_missing_input": "return_for_fix",
"owner": "review_team"
}用未参与调参的样本复测阈值
调参时看过的样本已经带上了人的选择,再用它验证容易得到偏乐观的结果。需要从同一时间段或相邻时间段里另取一批未参与调参、且带人工结论的样本跑一遍同样的回放。
- 复测样本:与调参样本来源一致但记录不重叠,字段完整性要求相同,标签口径保持一致。
- 复测结果:按选定阈值统计命中、漏放、误收,并与调参阶段的计数对比,重点看误判类型是否集中在同一类。
- 调整结论:复测结果与调参阶段方向一致,阈值可以先沿用并定期回看;若误收或漏放明显集中在某一类输入,先修输入校验或人工口径,再决定是否调整阈值;复测样本量太少时,只作为参考,不下最终判断。