标注引擎的命令行、REST API、MCP 工具和 SDK
通过 potato label、/api/engine/v1 REST 路由、五个引擎 MCP 工具或 Python 的 Study 类来驱动标注引擎,它们共用同一个 engine.sqlite 文件。
标注服务器、命令行、REST API、MCP 工具和 Python SDK 都通过任务目录里同一个 engine.sqlite 文件,驱动同一个标注引擎。你可以从命令行启动一项研究,用服务器提供人工请求,再在笔记本里完成认证。
同一时间只有一个进程驱动一项研究。运行中的服务器的规划器持有研究的写入锁,在它持有期间,potato label run、potato label certify 和 Study.run() 会拒绝执行并说明原因。这时请改为通过服务器认证,使用 POST /api/engine/v1/certify 或管理页面。之所以要有这把锁,是因为两个驱动方会抽取两份校准样本,并拿对方的标签来认证。持有者退出时锁会释放。同一台机器上被终止的持有者,其锁会被立即接管;另一台机器上的持有者,则在两分钟没有心跳后被接管。只读命令(status、certificate、calls、export)随时都能使用。
命令行
每条引擎命令都接受研究的配置文件:
potato label <command> <config.yaml> [options]这九条命令覆盖了一项研究从第一次模型调用到导出数据集的全过程:
| 命令 | 作用 |
|---|---|
run | 用级联为每个条目打标签,抽取盲态校准样本,认证,定案。--until predicted(默认)运行一轮后停止,--until met 会一直运行,直到每份契约都满足,或者引擎在等待人工。还接受 --max-items N、--budget-usd X(本次运行覆盖 budgets.model_usd)、--max-ticks N(默认 20)和 --json。被终止的运行会从停下的地方继续,不会重复模型调用。当某个来源上次运行失败或它给出的每个答案都是错误,或者没有任何来源能标注契约指定的方案时,以状态码 1 退出,并指出该来源。 |
status | 条目、预测、按用途分列的请求、契约、花费、尚无标签的条目,以及每个出错或运行失败、暂停的来源各占一行。--json。 |
certify | 在新的 cert 标签和新的预测上检验每份契约。如果只有 dev 标签变了,会返回存储的结果并附一条说明;--retest 会在下一次检视时检验 dev 现在选出的规则(参见检视次数)。--json。 |
certificate | 质量证书。--format md(默认)、html 或 json,以及 --out FILE。 |
export | 把带来源记录的标签、证书(JSON、Markdown、HTML)、数据集卡片和调用日志写入 --out DIR(默认 <output_annotation_dir>/labeling_engine)。 |
calls | 以 JSON lines 格式输出模型调用审计日志。--out FILE。 |
distill | 用目前的标签训练一个模型,并把它放在级联的第一位。 |
optimize | 在 dev 标签上为级联的每个子集打分,报告保持覆盖率的最便宜子集。如果没有任何子集能保持覆盖率,它就不推荐任何子集。--prompts N 还会请某个 LLM 层为它的提示词生成 N 个改写版本,并在 dev 条目上为每个版本打分。这些都是模型调用,会记入日志、计入预算,并以各自的来源版本存储,而当前提示词则用它存储的预测来打分。级联和证书都不会被修改。 |
migrate-config | 写出配置的一份副本,其中带有与旧 AI 键等价的 labeling_engine 块。--out FILE。参见迁移到标注引擎。 |
查看进度不消耗任何预算,因为 status、certificate 和管理页面读取的是存储的结果。每一次新的检验,无论来自对新标签运行 certify,还是来自 certify --retest,都会消耗契约的一部分误差预算。
导出写出的文件
potato label export 向输出目录写入四类文件:
| 文件 | 内容 |
|---|---|
labels.jsonl, labels.csv | 每个条目和方案一行,无论是否已有标签,包含 id、schema、label、label_origin(auto、human、adjudicated……)、status(accepted、threshold_legacy 下的 accepted_uncertified、pending、pending_recert)、source、model、source_version、confidence、contract_version 和 request_ids。如果某个机器标签的来源在它被接受后发生了变化,它会显示为 pending_recert,直到下一轮重新认证它。 |
certificate.json, .md, .html | 证书。 |
README.md | 根据证书生成的数据集卡片,带有 Hugging Face 前置元数据。 |
model_calls.jsonl | 每一次模型调用,包含模型、提示词和回复的哈希值、token 数、延迟、成本、缓存命中和遮盖类别。 |
常规导出器(python -m potato.export 和管理端导出)导出的是人的标注,导出格式页面列出了它们。其中,labeling_engine 格式写出的文件与 potato label export 相同,引擎未启用时它会拒绝运行。开启引擎时,CSV、Parquet 和 Hugging Face 导出会多出两列,说明每条标注回答的是引擎的哪个请求。engine_purpose 存放用途,例如 calibration;engine_request 存放 JSON,包含用途、入样概率、可见性、划分和请求 id。用这两列可以把盲态随机样本与核验答案分开。
REST API
所有引擎路由都位于 /api/engine/v1 下,返回 JSON。认证方式是在 X-API-Key 头中提供管理员密钥,或使用管理员会话。读取需要管理面板权限,certify 和 plan 需要分配管理权限,证书需要导出权限。
| 方法和路径 | 返回 |
|---|---|
GET /status | 条目、预测、请求、调用总数、预算,以及每个方案的级联、契约和已定案标签数 |
GET /schemes/<name>/contracts | 该方案上每份契约的最新结果,如果级联变了则标为 stale |
GET /schemes/<name>/risk_coverage | 在 cert 标签上,最后一层每个阈值的接受比例、观测错误率和保证的上界 |
GET /schemes/<name>/reliability | 在校准标签上,每一层的可靠性分箱、ECE 和 Brier 分数 |
GET /schemes/<name>/drift | 每份选择性风险契约的抽查监控 |
GET /schemes/<name>/optimize | 在 dev 标签上打分的更便宜级联报告 |
GET /requests | 按用途和状态分列的请求数,以及请求本身。过滤参数为 purpose、status(重复该参数,或用逗号分隔多个值)、schema 和 limit(最大 1000) |
GET /calls | 调用日志,最新的在前,以及按来源汇总的总数。limit(最大 500)、offset |
GET /certificate | 证书。format=json(默认)、md 或 html,save=1 还会把它存储下来 |
GET /crowd | 规划器最近一次的众包计划,除非开启实际花费,否则是演练 |
POST /certify | 立即检验每份契约。?retest=1(或 {"retest": true})还会检验只有 dev 标签发生变化的规则 |
POST /plan | 立即运行一次规划器 |
研究未开启引擎时,这些路由返回 404。对于无效的参数,例如不是数字的 limit、未知的 purpose 或 status,或者 json、md、html 以外的 format,它们返回 400 和一个 JSON 错误。
例如,下面的请求从运行在 8000 端口的服务器上以 Markdown 格式获取当前证书:
curl -H "X-API-Key: $ADMIN_API_KEY" \
"http://localhost:8000/api/engine/v1/certificate?format=md"MCP 工具
MCP 服务器提供五个引擎工具,权限与 REST 路由相同:
engine_statusengine_requestsengine_run,运行一次规划器engine_certify,接受retestengine_certificate,格式为json、md或html
在引擎关闭时授予这些工具,会产生校验警告。通过 potato mcp connect 调用时,被拒绝的调用(缺少权限、参数错误)会作为工具错误返回,并带上服务器的消息。MCP 服务器文档介绍了如何授予工具和连接客户端。
Python SDK
Study 类用于在 Python 中驱动引擎,例如在笔记本里:
from potato.labeling_engine.sdk import Study
study = Study("examples/labeling-engine/text-certified-sentiment/config.yaml")
study.run() # label, sample, certify, resolve
for req in study.requests(status="open")[:5]:
study.label(req.item_id, req.schema, "positive", user="me")
study.certify()
print(study.certificate(fmt="md"))
study.export("out/")每个方法都对应一条命令或一个路由:
| 方法 | 作用 |
|---|---|
Study(config_path) | 加载配置和条目 |
run(until="predicted", max_ticks=20) | 与 potato label run 相同,并获取写入锁 |
label(item_id, scheme, value, user, request_id=None) | 记录一个人的标签。它会关闭 request_id,否则关闭这个人在该条目上持有的请求,如果都没有,就保留为自发标签,自发标签永远不用于认证。同一个人在同一条目上的第二个标签会更新他的第一个标签 |
status() | 与 GET /status 相同 |
requests(status=None, purpose=None, ...) | 请求台账 |
certify(retest=False) | 与 potato label certify 相同 |
certificate(fmt="json") | json、md 或 html |
export(out_dir) | 与 potato label export 相同 |
示例把每个未关闭的请求都标为 "positive",只是为了演示这些调用。通过 Study.label 记录、但不回答任何请求的标签会被保留为自发标签,而自发标签永远不用于认证,所以一个为引擎没有请求的条目打标签的脚本,添加的是任何契约都不会读取的标签。
延伸阅读
实现细节见源文档。