标注引擎契约
标注引擎用人工标签检验的六种契约,从选择性风险和 PPI 区间到替代标注者检验,以及每种契约在什么情况下不成立。
契约是关于最终标签的一项陈述,标注引擎在随机样本上用人工标签检验它。每份契约指定一个标注方案(schema),并带有一个 confidence(默认 0.9),即该陈述成立的概率。因此 confidence 为 0.9 时,已满足的契约有 10% 的可能是错的。
六种契约作出的陈述各不相同,适合不同的研究:
| 类型 | 陈述 | 适用于 |
|---|---|---|
selective_risk | 被接受的机器标签中,出错的至多占 error | 每个标签都必须可用的数据集和训练集 |
ppi | 每个标签的流行率(或平均分)的区间,无论机器质量如何都有效 | 报告比率,例如“12% 的帖子含有毒内容 [10.5, 13.6]” |
no_worse_than_human | 机器与人的一致程度至少和一个人与其他人的一致程度相当 | 替代标注者或 LLM 评审 |
budget_first | 一笔人工标注预算能换来什么 | 花钱之前做规划 |
distributional | 机器的标签分布与人们的意见分布接近 | 分歧本身就是数据的主观任务 |
threshold_legacy | 无,它接受高于固定置信度的标签 | 仅用于转换来的配置 |
这些契约都不保证标签没有错误。selective_risk 限定的是被接受标签中的错误率,而每份检验机器的契约,衡量的都是机器与标注样本的那些人之间的一致程度。
契约状态
每份契约都处于五种状态之一,显示在管理页面、potato label status 的输出和证书中:
| 状态 | 含义 |
|---|---|
met | 检验在当前级联上通过。 |
insufficient | 人工标签还不够,并给出还需要多少的估计。当这个估计超过语料中剩余可抽样的数量时,状态会说明用这份语料无法达到目标。 |
infeasible | 标签已经够了,但没有任何接受规则能通过,例如因为机器的置信度无法把对的答案和错的答案区分开。 |
violated | 对已接受标签的抽查显示错误率高于目标(需开启 features.drift,默认开启)。 |
stale | 自上次检验以来,来源、提示词或方案发生了变化。已接受的标签在 pending_recert 中等待。 |
只有当某方案上的每一份 selective_risk 和 threshold_legacy 契约都已满足并接受某个机器标签时,这个标签才会被接受。契约陈述的是标签必须满足的条件,所以未满足的契约会阻止接受,而不是被跳过;状态、管理页面和证书都会指出哪份契约没有满足。当任何规则都无法生效、也不再抽取样本时(某份契约 infeasible、校准样本已经抽完,或者无法作出任何预估),仍没有标签的条目会在 budgets.human_labels 的范围内交给人来标注。
dev 划分和 cert 划分
引擎把用来选定规则的标签和用来检验规则的标签分开保存。校准请求随机抽取,并记录入样概率,始终是盲态的,每个请求随机归入以下两个划分之一:
- dev(
humans.dev_fraction,默认一半)用来拟合校准器并选定阈值; - cert 用来检验选定的规则,除此之外没有任何东西读取它。
检视次数
对一份契约的每一次新检验都使用更严格的水平,所以随着标签陆续到来反复检验,并不会抬高置信度。第 k 次检视分到误差预算的 (1 - confidence) * 6 / (pi^2 k^2),对所有可能的检视求和恰好是整个预算,第一次检视分到其中的 61%。
- 检视次数按契约计算,涵盖这份契约曾在其下检验过的每一个级联,改名的契约保留旧 id 的检视次数。不断尝试提示词或模型直到有一个通过,每试一次都算一次检视。回到之前的某个级联也算一次新的检视,它之前的结果不会恢复。
- 对同一份数据重新检验不算新的检视。 同样的 cert 标签、同样的预测、在 dev 上选定的同一条规则,会返回存储的结果。无法进行的检验(例如某个类别没有 cert 标签)不消耗任何预算。
potato label certify会一次性检验新的 cert 标签和新的预测,对应的 REST、MCP 和 SDK 操作也一样。如果只有 dev 标签变了,它会返回存储的结果,并附一条说明,指出 dev 现在会选另一条规则;--retest会在下一次检视时检验那条规则。- 规划器会随着标签到来自动认证。 已满足的
selective_risk契约在其级联下保持满足,由抽查来监控。未满足的契约在其标签增长四分之一、且至少增加 10 条时会再次检验。ppi、distributional和no_worse_than_human的结果是估计值,而不是通过与否的检验,所以规划器会在同样的节点重新估计,并在校准样本完整时再估计一次。 - 修改过的 cert 标签算作新数据。 标注者修改答案时,这次修改的代价不会超过一条新标签。如果改回到已经检验过的状态,那次检验的结果会恢复。如果存储结果中的每一项检验在修改后都没有看到更多错误,结果和它的检视次数保持不变。否则,规划器会等到标签从第一次修改起增长四分之一,这样一连串更正只算作一次检验,在此期间已接受的标签仍保持接受,契约上会附一条说明。当不会再有更多标签时,它会立即检验,而显式的认证操作会在下一次检视时检验。
人们在看过机器答案之后给出的标签(核验请求)以及在引擎请求之外给出的标签,永远不会用于认证或估计任何东西。它们可以用来训练蒸馏模型。
selective_risk
selective_risk 限定被接受的机器标签中出错的比例。error 键是被接受标签中能容忍的最大错误率,必须设置:
- id: accuracy
kind: selective_risk
schema: sentiment
error: 0.05 # required: largest tolerated error among accepted labels
confidence: 0.9
per_class: true # test each predicted class separately
tolerance: 0.5 # graded families only: loss at or below this counts as correct规则是每一层级联的一个置信度阈值,开启 per_class 时则是每个预测类别各一个阈值。除最后一层外,每一层的阈值都在 dev 上选定,并在 cert 上检验一次。最后一层从 dev 选定的阈值开始,逐步尝试更宽松的阈值,依次检验,在第一个不通过的阈值处停止。这个过程就是固定顺序的 Learn-then-Test(Angelopoulos 等,2025)。每一次检验都是单侧二项检验,检验被接受标签中的错误率是否高于 error,显著性水平在各层和各类别之间分配。不通过的那一层不接受任何标签,它的条目交给人。
什么算“正确”取决于方案族。每个方案族的损失见下表,损失不超过 tolerance 时标签算作正确:
| 方案族 | 损失 | 默认 tolerance |
|---|---|---|
单选(radio、select) | 标签相同为 0 | 0 |
有序(likert) | 量表上的距离 / (点数 - 1) | 0 |
连续(slider、number) | 距离 / (max - min) | 0.05 |
多标签(multiselect) | 1 - Jaccard 重叠 | 0 |
图像区域(image_annotation) | 1 - 匹配形状的平均 IoU | 0.5 |
音频/视频片段、temporal_grounding、tiered_annotation | 1 - 平均时间 IoU | 0.5 |
3D 物体(spatial_annotation) | 1 - 平均 3D IoU | 0.5 |
智能体轨迹(process_reward、trajectory_eval……) | 双方都标注的步骤中标注不同的比例 | 0 |
区域、片段、3D 物体和轨迹的损失,与 /admin/iaa 上的一致性报告所用的相同,所以机器与人之间的评分方式,和两个人之间的评分方式一样。自由文本和成对比较方案目前还没有对应的方案族,证书会把它们列为不支持。
检验要求每一组被检验的 cert 条目是均匀样本。如果某一组条目是以不等的概率抽取的,就不会检验这一组,结果中会指出这一点。
在最后一层,只有当 dev 上的错误率不超过目标的一半、并且预计有足够多的 cert 标签能通过第一次检验时,才会在 dev 上选定阈值。对还需要多少标签的预估,只计入能以这种方式选定的阈值。如果 cert 已经有了预估所要求的标签数,检验却仍不通过,下一次预估就会使用 dev 和 cert 合起来显示的错误率,而不只是 dev 的。如果 dev 上的最低错误率低于目标、但高于目标的一半,就既不检验也不预估。结果会说明这一点并给出该错误率,因为只有在错误率最终更低时,更多标签才有帮助。
metrics.accepted_by_tier 是规则对整个总体(包括校准条目)的覆盖率,而不是交付的机器标签数量。证书中 "Machine labels accepted, by source" 一行统计的才是这个数量。
轨迹损失只比较双方都标注了的步骤,所以只标注了部分步骤的人,只在那些步骤上比较。没有人标注的步骤不会被检查;一个人如果只标注了第 0 步,并且在那一步与评审一致,就算作与整条轨迹的标签一致。在每一步都必须检查的场合,请要求人们标注每一步。
ppi
ppi 报告每个标签的流行率区间,或者某个平均分的区间,并对机器的错误作了校正:
- id: prevalence
kind: ppi
schema: sentiment
estimand: prevalence # or mean, for numeric scores
by: language # optional: an interval per value of this item field
confidence: 0.95
max_width: 0.05 # optional: met once every interval is at most this wide预测驱动推断(prediction-powered inference,Angelopoulos 等,2023)用机器在人工标注样本上的误差来校正机器的估计。无论机器质量如何,这个区间都有效。好的机器能让区间比只靠人更窄,差的机器也不会让它更宽。入样概率相等时,引擎使用带调优权重的 PPI++;入样概率不等时(分层抽样或不确定性驱动的抽样),使用 Horvitz-Thompson 差分估计量。它所用的机器标签,就是级联会交付的那个标签。by 字段在条目注册时从条目中复制过来。没有 max_width 时,契约只要有足够的标签可以报告就算满足。
no_worse_than_human
no_worse_than_human 检验的是,机器与人一致的频率是否至少和一个人与其他人一致的频率一样高:
- id: replaces-a-person
kind: no_worse_than_human
schema: verdict
epsilon: 0.1这份契约运行替代标注者检验(alternative annotator test,Calderon 等,2025)。它依次留出每一个人,检验机器与其余人一致的频率是否至少和被留出的那个人一样高,允许 epsilon 的差距。当机器胜过至少一半的人时就算通过,并控制跨人的错误发现率。
这项检验需要由多人标注的条目。请设置 humans.overlap(样本中被标注不止一次的比例)和 humans.overlap_k(每个条目的标注人数,至少 3),而检验还需要至少 3 名标注者、每人 30 个条目。在凑齐之前,契约一直是 insufficient。当固定的准确率目标主要测到的是标注者噪声时,就用这份契约。如果两个认真的人只有 85% 的时候意见一致,那么任何标注者都无法被证明有 95% 是“对”的。
budget_first
budget_first 在你花钱之前预估一笔人工标注预算能换来什么:
- id: plan
kind: budget_first
schema: sentiment
human_labels: 500 # or human_usd, priced at the crowd reward预估依据的是目前已收集的 dev 标签。对于网格上的每一个错误率目标,它给出在这笔预算下机器能被认证标注的语料比例,以及每个流行率区间会有多宽。只要有足够的 dev 标签可供预估,契约就是 met。它对标签本身不作任何承诺,这要等标签到齐后由 selective_risk 和 ppi 来做。
distributional
distributional 把机器的标签分布与人们的意见分布进行比较,适用于人们出于本应保留在数据中的理由而意见分歧的主观任务:
- id: disagreement
kind: distributional
schema: offensiveness
max_distance: 0.15 # optional
groups_by: age_band # optional: a prestudy question whose answer groups the annotators每个由多人标注的条目(humans.distribution_k,默认 5 人)都有一个人工标签分布。这份契约报告机器分布与人们分布之间的平均 Jensen-Shannon 距离,并附带自助法区间。它还会报告一个噪声上限,即每个条目上把人随机分成两半后两半之间的同一距离。机器离人们的距离如果比人们彼此之间的距离还近,就已经接近到数据所能允许的程度了。
机器的分布在来源提供概率时就是这些概率(决策模型、k_sample、logprob),否则就是把它的标签表示成独热向量。当区间上端不超过 max_distance 时,契约满足;没有 max_distance 时,只要有 20 个由 3 人或更多人标注的条目,契约就满足。当区间下端高于 max_distance 时,契约为 infeasible,因为更多条目只会把区间收窄到一个过大的距离周围。
设置 groups_by 时,同样的数字会按标注者分组报告。每组在某个条目上的分布只由该组的人构成,分组依据是他们对指定研究前问题的回答;如果没有人回答这个问题,契约会说明这一点。
threshold_legacy
threshold_legacy 接受高于固定置信度的机器标签,不运行任何统计检验:
- id: old-rule
kind: threshold_legacy
schema: sentiment
threshold: 0.8potato label migrate-config 会为 icl_labeling 写出这份契约,阈值取原来的 confidence_threshold,所以转换后的配置行为与之前相同;你也可以手动编写它。证书会把这些标签标为未认证,并报告它们在校准标签上测得的错误率,导出时这些标签的状态为 accepted_uncertified。
示例研究的结果
examples/labeling-engine/ 下的三个示例研究在运行时,把 LLM、评审和视觉来源都指向了 vLLM 服务器上的 Gemma 12B,而不是提交的配置中所用的 Ollama 模型。每个示例的 README 都列出了被修改的来源块;使用 Ollama 默认设置时,数字会有所不同。
- 文本情感(481 条评论,最后一层是使用 logprob 置信度的 Gemma 12B)。10%、0.9 的
selective_risk在 165 条人工标签上满足,316 条机器标签被接受。它们相对于真实标签测得的错误率是 7.6%,PPI 区间覆盖了全部三个标签的真实流行率。 - 图像(128 张 COCO 图像,YOLOv8n,视觉模型为 Gemma 12B)。“有人”标签在 10% 上通过了认证。边界框契约一直是
insufficient,因为在 IoU 0.5 下,YOLOv8n 的边界框在 32% 的 dev 图像上是错的。 - 智能体轨迹(288 条轨迹,评审为 Gemma 12B)。评审在 80% 的轨迹上是对的,但它的置信度始终是 1.0,所以
selective_risk为 infeasible。替代标注者检验为 insufficient,机器得分 0.82,人们为 0.93。PPI 估计的任务成功率为 0.66 [0.57, 0.76],真实值是 0.60,而评审单独给出的是 0.76,高了 16 个百分点。
延伸阅读
实现细节见源文档。
参考文献
- Angelopoulos, A. N., Bates, S., Candès, E. J., et al. (2025). Learn then test: Calibrating predictive algorithms to achieve risk control. The Annals of Applied Statistics. https://doi.org/10.1214/24-AOAS1998
- Angelopoulos, A. N., Bates, S., Fannjiang, C., et al. (2023). Prediction-powered inference. Science, 382(6671). https://doi.org/10.1126/science.adi6000
- Angelopoulos, A. N., Duchi, J. C., and Zrnic, T. (2023). PPI++: Efficient prediction-powered inference. arXiv. https://arxiv.org/abs/2311.01453
- Calderon, N., Reichart, R., and Dror, R. (2025). The alternative annotator test for LLM-as-a-judge: How to statistically justify replacing human annotators with LLMs. Proceedings of ACL 2025. https://aclanthology.org/2025.acl-long.782/