Skip to content

标注引擎

用模型为数据集打标签,用一份盲态随机抽取的人工标签样本检验这些机器标签,并为发布的数据集附上一份证书,记录检验了什么。

标注引擎用模型为数据集打标签,再用人来衡量模型出错的频率。你在一份契约里声明最终标签必须满足的条件,例如“被接受的机器标签中至多 5% 是错的,置信度为 90%”。引擎向人索取检验这一说法所需的标签,接受检验所支持的机器标签,把其余条目交给人来标注。产出是数据集,外加一份证书,记录检验了什么、用了多少条人工标签。

标注引擎从 Potato 2.11 起提供。标注服务器、potato label 命令行、REST API、MCP 服务器和 Python SDK 都通过任务目录里同一个 engine.sqlite 文件来驱动它。

什么样的研究适合用引擎

当人没法标完所有条目、而模型能标好大部分时,引擎才划算。如果人无论如何都会标完每个条目,引擎就没有任何增益,这时普通的分配策略是更好的选择。以下三种情况适合使用:

  • 条目多到人标不完,而你有一个大多数时候都对的模型。
  • 你需要报告标签有多好,而不只是说明它们出自模型,无论是为了论文、数据集发布,还是一份别人要用的训练集。
  • 你在用 LLM 评审来评测一个模型或智能体,需要知道这个评审能否代替人。

从模型预测到最终标签

引擎把机器预测、人工请求和契约结果存放在同一个存储里,每个条目都经过同样的六个步骤:

  1. 来源就是模型。来源可以是 LLM、视觉语言模型、决策模型(Laya、Jev 或 OpenJev)、目标检测器、LLM 评审、用本研究自身标签训练的模型、由其他来源组成的评审团,或者你已有的标签。每个来源在给出每条预测时都会记录一个置信度。
  2. 级联给来源排定顺序。条目先交给第一个来源;如果契约不接受这个答案,就由下一个来源来试。最后一个来源之后,条目交给人。
  3. 请求是引擎要人去做的事。每个请求都记录它为何发出(例如校准、认证、核验、抽查)、它的条目被抽中的概率,以及这个人能否看到机器的答案。校准请求随机抽取,并且始终是盲态的。
  4. 契约在随机样本上拿机器标签与人工标签对照检验。这份样本的一半(dev 划分)用来选定接受规则,另一半(cert 划分)用来检验它。契约的状态为 met、insufficient(还需要更多标签,并给出所需数量的估计)、infeasible、violated 或 stale。
  5. 定案为每个条目给出最终标签。这个标签要么是在已满足的契约下被接受的机器标签,要么是某个人的标签,要么待定。
  6. 证书记录每份契约的结果、带有模型和提示词版本的级联、每种用途各用了多少条人工标签、模型花费,以及调用日志的摘要。

保证背后的规则

已满足的契约是关于人工标注的那份随机样本的统计陈述,它之所以成立,靠的是这份样本的抽取方式和使用方式。引擎执行五条规则:

  • 盲态请求不显示任何机器答案。 当某人持有一个校准、认证或抽查请求时,服务器会扣下该条目的所有机器答案。预标注、内联评审、AI 助手(返回 403)和 AI 帮助按钮全部关闭。看过机器答案之后给出的标签,不能独立地检验那个答案。
  • 选定和检验使用不同的标签。 阈值在 dev 标签上选定,在 cert 标签上检验。在 cert 标签上的每一次新检验都使用更严格的水平,所以反复认证直到检验通过并不会抬高置信度。
  • 只有人能认证。 机器标注者可以参与推断最终标签,但永远不会进入契约用来检验的那些标签。
  • 任何改动都会让证书过时。 更改来源、提示词、阈值或方案,会把所有受影响的契约标为 stale,并把它们已接受的标签移到 pending_recert,直到契约再次被检验。人工标签会保留。
  • 机器预测不占标注者名额。 引擎的预测不计入每个条目的标注者上限。

引擎不会检查人工标签是否正确。每份契约衡量的都是机器与标注样本的那些人之间的一致程度,所以用不可靠的人检验的契约,证明的是与不可靠的人的一致。请同时用质量控制、重叠标注(humans.overlap)和 no_worse_than_human 契约来检查标注的人。

第一项研究

Potato 在 examples/labeling-engine/ 下附带三个示例研究,分别针对文本、图像和智能体轨迹。下表列出每个示例使用的来源和契约:

示例来源契约
text-certified-sentiment/Laya(决策模型)、一个 Ollama LLM10% 的选择性风险,PPI 流行率
image-objects-and-people/YOLOv8n 检测器、一个 Ollama 视觉模型边界框(IoU)上和“有人”标签上的选择性风险
agent-trace-judge/一个带标签顺序互换的 LLM 评审选择性风险、不差于人类、PPI 任务成功率

文本示例用四条命令就能跑起来。第一条用级联为每个条目打标签并抽取第一份盲态样本,第二条把这份样本提供给人来标注,等人标完样本后,最后两条检验契约并打印证书:

bash
potato label run examples/labeling-engine/text-certified-sentiment/config.yaml
potato start examples/labeling-engine/text-certified-sentiment/config.yaml -p 8000
potato label certify examples/labeling-engine/text-certified-sentiment/config.yaml
potato label certificate examples/labeling-engine/text-certified-sentiment/config.yaml --format md

要在你自己的研究里加入引擎,就在一份已有 data_files 和一个名为 sentiment 的标注方案的配置里加上下面这些键。这份契约要求被接受的机器标签中至多 10% 是错的,置信度为 90%,budgets.human_labels 则限定引擎最多能发出多少个人工请求:

yaml
assignment_strategy: engine
 
labeling_engine:
  enabled: true
  sources:
    - id: gemma
      kind: llm
      endpoint_type: vllm
      model: google/gemma-4-12B-it-qat-w4a16-ct
      base_url: http://localhost:8001/v1
      confidence: {method: logprob}
  contracts:
    - id: accuracy
      kind: selective_risk
      schema: sentiment
      error: 0.1
      confidence: 0.9
  budgets:
    human_labels: 400

这个来源根据 token 的对数概率给出置信度(method: logprob),每个条目只需一次调用,而且通常是各种置信度方法中校准得最好的。配置列出了每一个键,契约说明了每种契约检验什么。

标注页面上的请求

设置 assignment_strategy: engine 后,标注者拿到的是引擎的请求,优先级最高的先发。顺序是:仲裁、认证、校准、为分布型契约追加的评分者、没有任何机器能标注的条目、核验,最后是抽查。校准请求按固定的随机顺序发放,dev 和 cert 请求交错出现。一个人会一次拿到某个条目上所有未关闭的请求,每个方案一个,同一条目的同一方案永远不会给他两个请求。

条目上方有一条简短说明,指出这是哪类请求;在有多个问题的页面上,它还会点明是哪个问题:

  • 盲态。 说明写着 "Label this one yourself. Suggestions are off for this item." 这个人保存之后,条目对他仍保持盲态,重新加载和后退时都一样。
  • 核验。 机器的答案已经填好,说明会提示:对就保留,不对就修改。页面会记录预填的答案,所以你可以衡量人们接受它的频率。在这个人动手之前什么都不会保存,所以开着不管的页面不会替他作答。页面无法预填答案的方案(时间片段、3D 物体、智能体轨迹)改为以盲态提供。
  • 定案。 没有任何机器标签能被接受,所以这个人的答案就是标签。

某人持有却在 runtime.hold_minutes(默认 60)内没有作答的请求,会回到请求池并从他的页面上移除。在引擎没有派给某人的条目上保存的标签,永远不会关闭别人的请求,引擎会把它保留为自发标签(organic label)。当一次新的认证接受了机器标签时,引擎会取消它现在覆盖的那些条目上未关闭的核验和定案请求。某人已经持有的请求仍归他,他的答案会取代机器标签。

进度计数器统计的是一个人还能接的请求数,而不是整个语料。暂时没有事可做时,标注者会看到一个简短的等待页面,规划器发出新请求后就会派给他。当不会再有更多请求时,也就是每个条目都有了标签、人工标签预算已经用完,或这个人自己的上限已经达到时,他的部分会照常结束,进入研究后的页面,在众包平台上则给出完成码。在规划器第一次运行之前,没有人会被判定为已完成。

Pocket Mode 也会提供引擎请求,每次一整批,并且在显示 "All caught up" 之前会先请求更多。Pocket Mode 从不显示机器答案,所以在那里提供的核验请求会被记录为盲态,除非桌面页面已经向这个人显示过答案。在定案和仲裁卡片上,它显示的说明与桌面页面相同。

管理页面

开启引擎后,管理面板会链接到位于 /admin/labeling-engine 的 Labeling engine 页面。页面上的每张图表都有对应的表格视图。页面显示:

  • 每份契约的状态、覆盖率、检视次数,以及还需要多少标签,并附上它所作的完整陈述(未满足的契约陈述的是它的目标,而不是保证);
  • 每份 ppi 契约的区间,旁边是仅凭人工标签得到的区间;
  • 对上次运行失败、或每个答案都出错的来源给出的警告;
  • 最后一层级联的错误率随覆盖率变化的曲线,带有保证的上界和目标;
  • 每一层的可靠性图,把声明的置信度与在人工标签上的正确比例对照画出,附 ECE 和 Brier 分数,标签较少的分箱画得较浅;
  • 对已接受标签的抽查,以错误数对照目标显示,并标明抽查数量是否少到无法判断;
  • 按用途和状态分列的人工请求;
  • 模型调用日志,最新的在前,附 token 数、延迟和成本;以及
  • 运行一次规划器、立即认证和打开证书的按钮。

没有管理员会话时打开这个页面,会转到管理面板的密钥表单。引擎关闭时,页面会说明这一点,并指出开启它的那个键。

延伸阅读

实现细节见源文档。