跳到主要内容

第 29 章:完成生产级 Agent Benchmark

发布评审已经排到周五。Task 都能生成,Oracle 在开发者机器上跑通过,团队还保存了一张 Viewer 截图。可是评审者继续问:正式 Dataset 究竟是哪一个 digest?错误答案和投机答案是否仍会被拒绝?云端少掉的两个 Trial 去了哪里?Judge 的零分是报告质量差,还是裁判超时?训练团队导出的成功轨迹是否混入最终评测任务?没有人能从截图回答这些问题。

这不是“差最后一次运行”,而是缺少一条从源码到发布物的证据链。本章把全书的“系统配置与故障诊断 Agent Benchmark”收束为发布候选:冻结 Harbor v0.18.0 与提交 527d50deb63a5d279e8c20593c18a2cbc7f61f9e,审计 Task、Verifier、Oracle、能力覆盖与难度,分层执行本地 smoke 和云端完整评测,校准模型裁判,发布 Dataset 与报告,再为 SFT 和后续 RL 建立独立门禁。1

读完本章,你应当能够:

  • 为一个 Benchmark 建立可追溯的发布候选,而不是把“能生成”写成“已发布”;
  • 让缺失或非有限 Reward、基础设施异常、Judge 无效、成本缺失、重复 Trial 和 digest 漂移失败关闭;
  • 分开陈述 Oracle 可解、smoke 通过、完整评测完成、Dataset 已发布和训练收益已证明;
  • 用人工校准与对抗 fixture 验收 Judge,而不是只看平均分;
  • 把同一套质量门复用于代码修复与知识工作 Benchmark。

29.1 六个结论,六份证据

生产评测最常见的措辞错误,是把不同阶段压成一个“成功”。本章使用六个状态,后一个状态不能倒推出前一个状态之外的任何结论。

状态最小证据能说什么仍不能说什么
Task 已生成目录完整、schema 解析、包摘要构造流程产生了候选 TaskTask 可解、Verifier 正确
Oracle 可解固定 digest、干净环境、Oracle Trial 与 Reward标准解在该环境和评分器下通过普通 Agent 能完成、Task 无捷径
smoke 通过小规模本地 Job、负例与失败日志关键执行链能启动、分类与归档完整能力、云端兼容性、稳定排名
完整评测完成预注册矩阵的全部 Trial、逐项结果与成本可以按既定口径分析这一批运行Dataset 已发布、结果可外推到所有场景
Dataset 已发布Registry 回执、固定 tag/digest、下载回读指定内容可由消费者解析Benchmark 有效、训练会有收益
训练收益已证明独立训练协议、隔离评测集、重复与不确定性在该训练实验和评测协议下观察到差异Harbor 自动完成了训练、差异具有普遍因果性

Harbor v0.18.0 的 TrialResult 可以同时保存 Task checksum、Agent/Model 身份、Reward、异常、各阶段时间以及可选 token/cost;Job 汇总只对存在的成本求和。2 因此 cost_usd=null 表示未知,不是零;有 exception_info 又残留 Reward 的 Trial 也不能自动当作有效成功。Dataset 发布更是另一条调用链:harbor publish 上传 Task 与 Dataset,在发布 Dataset 前还会自动同步本地 digest。3 评测结果不会因为 Dataset 上传成功而自动变得完整。

注意:本章的门禁是组织级发布策略,不是 Harbor 内置的单一 release 命令。Harbor 提供包摘要、锁文件、结果模型、发布与轨迹导出;团队仍需定义质量门、失败政策和签字流程。

29.2 冻结发布候选

最终项目不再叫 latest,而是形成一个不可原地覆盖的发布候选:

system-diagnosis-benchmark/
├── benchmark/
│ ├── dataset.toml
│ ├── metric.py
│ └── <各 Task 目录>
├── configs/
│ ├── local-smoke.json
│ └── cloud-full.json
├── release/
│ ├── candidate.json
│ ├── capability-matrix.csv
│ ├── judge-calibration.json
│ ├── audit-report.json
│ └── publication-receipt.json
├── jobs/
├── sft/
├── reports/
└── release_gate.py

先同步,再审计,最后发布:

cd /path/to/system-diagnosis-benchmark
harbor --version
harbor sync benchmark
python release_gate.py release/candidate.json --stage prepublish
harbor publish benchmark --tag v1.0.0 --private

harbor sync 会重新计算本地 Task 与 Dataset 级文件的摘要,并写回 dataset.toml;不带 --upgrade 时,Registry-only Task 不会被悄悄更新到 latest4 这条命令是有状态操作,所以应先审查它的差异,再生成 candidate.jsonharbor publish 还会再次执行同步;若那次报告任何变化,应中止并重建候选,而不是接受“发布时顺便修正”的内容。

在 v0.18.0 中,Task package digest 按排序后的相对路径和每个文件的 SHA-256 计算;默认忽略规则与 .gitignore 会影响进入摘要的文件集合。5 Dataset manifest 强制 Task digest 使用 sha256: 加 64 位小写十六进制,并把排序后的 Task digest 与 Dataset 级文件的 path:digest 组合后再算内容哈希。6 这带来三个直接结论:

  1. Task 文件变化应产生新 Task digest;
  2. metric.py 等 Dataset 级文件若列在 [[files]] 中,其变化会进入 Dataset 内容身份;
  3. description、作者、能力标签和外部报告不等于内容质量证明,也不应拿 Dataset hash 充当签名、安全审计或许可证批准。

正式版本号 v1.0.0 是维护者对兼容性和发布语义的声明;digest 是内容身份。两者应同时出现:人类用版本号讨论变更,机器用 digest 拒绝漂移。v0.18.0 发布时总会附加 latest tag,所以消费者的正式 Job 仍应把精确 digest 写入配置,或至少先把版本 tag 解析成 digest 并归档回执。7

29.3 做最后一次全量审计

全量审计不是“再跑一次 Oracle”,而是逐 Task 检查四个面:目标、可解性、评分边界和代表性。

29.3.1 Task、Verifier 与攻击样本

每个 Task 至少有以下发布记录:

  • task_name 与 package digest;
  • 一个主能力、必要的交叉能力和来源组;
  • instruction 的输入、允许输出、禁止副作用和终止条件;
  • Oracle 在全新环境中执行的证据;
  • 明显错误答案必须得到零分的 fixture;
  • 至少一个投机答案 fixture,例如预写 Reward、修改测试、读取 Solution、伪造服务状态或在 Artifact 中夹带 Judge 注入;
  • Verifier digest、Reward schema 版本、合法范围、缺失政策和各维度方向;
  • 镜像、依赖、网络、凭据、Artifact 与保留策略。

Oracle 通过只证明“这一份 Solution 能通过这一份 Verifier”。它不能排除另一条投机路径。反过来,错误答案被拒绝也不能证明所有合法实现都会通过。因此发布候选必须同时保存正向 Oracle、明显负例和面向当前威胁模型的 gaming fixture;修改 Task、Solution、Verifier 或 Reward schema 后三类都重跑。

Harbor 的 package 摘要会收集 Task 配置、instruction、README、environment、tests、solution 和 multi-step steps 等路径,再应用忽略规则。5 这有利于绑定评分实现,但也意味着“只改隐藏测试”仍是新 Task 内容,旧结果不能继续挂在新 digest 下。若为了修正文案而声称不影响语义,也应发布新 digest,并在变更日志中写出兼容性判断;不要原地改包后继续引用旧 Job。

29.3.2 能力覆盖与经验难度

能力矩阵的行是预注册能力,列是 Task,而不是一串自由标签。贯穿项目至少覆盖:日志证据关联、Python 修复、Compose/服务拓扑、配置安全、多步骤事故处理和复盘表达。每个 Task 只指定一个主能力,以免覆盖数重复;交叉能力可用于诊断,但不能相加后充当总 Task 数。

难度也不能由作者的 easyhard 标签决定。用固定 baseline panel、相同预算和相同协议运行后,保存每个 baseline 在每个 Task 上的 s/n、Reward 分布、基础设施失败与不确定性。Oracle 稳定通过而所有 baseline 都失败,可能代表高难度,也可能代表 instruction、环境或 Verifier 存在问题,必须人工复查。能力覆盖是 Dataset 的代表性证据,经验难度是特定 baseline panel 下的观测;两者都不等于对真实世界总体的无条件外推。NIST AI RMF Playbook 把测量、验证以及所测构念是否成立放入持续的风险管理活动,而不是一次性上线盖章。8

29.3.3 Dataset 文档也是发布物

发布包的 README 或 Dataset Card 应写清动机、组成、来源与许可证、预期用途、非预期用途、能力/难度分布、已知偏差、评分协议、成本口径、维护者和退役方式。Datasheets for Datasets 原始工作提出记录数据集的动机、组成、收集过程与建议用途;Hugging Face 的官方 Dataset Card 文档也要求为内容、用途、限制、来源和伦理考虑提供上下文。910

这份文档不能只复制排行榜。至少同时发布:计划与实际分母、每个 Task 的 Task digest、完整 Agent/Model 身份、Harbor 版本与提交、Judge 校准版本、缺失值政策、协议偏离、原始结果位置、分析代码摘要和生成报告的命令。若许可证只允许分发转换代码而不允许分发原始数据,发布 Adapter、校验清单和获取说明,不要把缓存内容上传进 Dataset。

29.4 分层运行:从本地 smoke 到完整评测

发布候选使用四层运行,每层有不同停止条件。

29.4.1 静态与 Oracle 层

静态层验证 schema、目录、digest、依赖锁、凭据扫描、Artifact 白名单与许可证清单,不调用模型。Oracle 层在全新环境中逐 Task 运行;任何异常、缺 Reward、非有限 Reward、错误主键或低于预注册阈值都阻断后续批量运行。若云端 Provider 是正式协议的一部分,还应在单并发云环境中重跑 Oracle;本地可解不能证明云端的镜像、网络和 Artifact 路径相容。

29.4.2 本地 smoke 层

smoke 的目标是检查执行链,而不是估计能力。它应覆盖至少一个零分候选、一个正确候选、一个 Judge 路径、一个 trajectory 和一个受控基础设施故障;规模小、并发低,结果明确标为 smoke。只要每个计划 Trial 都能被归类、证据完整且故障注入落入预期类别,smoke 就完成。普通 Agent 得零可以是合法观测;缺失结果、未知异常或 Judge 错误被伪装成质量零则不是。

29.4.3 云端完整评测层

完整评测使用事前冻结的 Agent×Model×Task×attempt 矩阵、固定 digest、并发、超时、网络、重试、停止规则和预算。Job 根 result.jsontrial_results 列表不能当完整账本;v0.18.0 最终写根结果时排除逐 Trial 列表,证据位于各 Trial 子目录。11 因此发布脚本从全部逐 Trial result.json 重建分母,并与 JobResult.n_total_trialslock.json 中的 Trial locks 和预注册清单交叉核对。

完整评测必须失败关闭以下情况:

  • 计划 Trial 少一项、多一项或 trial_id 重复;
  • Trial 的 Task checksum 与候选 manifest 不同;
  • Reward 缺失、类型错误、布尔值冒充数值、NaN 或无穷;
  • 出现未处置的 Environment、Agent、Verifier、Artifact 或 Provider 异常;
  • Judge 明细含 error/warning,却被聚合成合法质量零;
  • 模型成本、沙箱成本或计费覆盖缺失;
  • trajectory 缺失、无效、未脱敏,或无法回到对应 Trial;
  • 实际重试、并发、Agent/Model 版本或 Provider 与预注册协议不同。

这里“失败关闭”指不能发布为完整且可比较的正式评测,不是删除失败 Trial。保留原 Job、异常和成本,用新状态 incomplete 发布内部事故报告。修复基础设施后使用新 Job ID 重跑预注册矩阵,并保存旧新关联;不要只补跑对某个系统有利的格子。

29.5 一个可执行的发布门禁

下面的 release_gate.py 只使用 Python 3.12 标准库。它不启动 Harbor、Docker、模型或云资源,而是验证前述系统生成的发布证据。--self-test 使用两个 Task、四个完整评测 Trial 的合成 fixture;其中 Reward、成本、时长和 Judge 校准数字都为教学性构造,不是任何真实 Agent、Model 或 Provider 的实测结果。

from __future__ import annotations

import argparse
import copy
import hashlib
import json
import math
import re
import sys
from pathlib import Path
from typing import Any


HARBOR_VERSION = "0.18.0"
HARBOR_COMMIT = "527d50deb63a5d279e8c20593c18a2cbc7f61f9e"
DIGEST = re.compile(r"^sha256:[0-9a-f]{64}$")


class GateError(ValueError):
pass


def require(condition: bool, message: str) -> None:
if not condition:
raise GateError(message)


def strict_pairs(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
result: dict[str, Any] = {}
for key, value in pairs:
require(key not in result, f"duplicate JSON key: {key}")
result[key] = value
return result


def load_json(path: Path) -> dict[str, Any]:
def reject_constant(value: str) -> None:
raise GateError(f"non-finite JSON constant: {value}")

data = json.loads(
path.read_text(),
object_pairs_hook=strict_pairs,
parse_constant=reject_constant,
)
require(isinstance(data, dict), "release evidence must be an object")
return data


def finite_number(value: Any, label: str, *, minimum: float | None = None) -> float:
require(not isinstance(value, bool) and isinstance(value, (int, float)),
f"{label} must be numeric and not boolean")
result = float(value)
require(math.isfinite(result), f"{label} must be finite")
if minimum is not None:
require(result >= minimum, f"{label} must be >= {minimum}")
return result


def dataset_hash(tasks: list[dict[str, str]], files: list[dict[str, str]]) -> str:
task_parts = sorted(item["digest"].removeprefix("sha256:") for item in tasks)
base = ",".join(task_parts)
if files:
file_parts = sorted(
f'{item["path"]}:{item["digest"].removeprefix("sha256:")}'
for item in files
)
base += ";" + ",".join(file_parts)
return "sha256:" + hashlib.sha256(base.encode()).hexdigest()


def unique_rows(rows: list[dict[str, Any]], key: str, label: str) -> None:
values = [row.get(key) for row in rows]
require(all(isinstance(value, str) and value for value in values),
f"{label} has empty {key}")
require(len(values) == len(set(values)), f"{label} has duplicate {key}")


def check_release(data: dict[str, Any], stage: str) -> dict[str, Any]:
release = data["release"]
require(release["harbor_version"] == HARBOR_VERSION, "Harbor version drift")
require(release["harbor_commit"] == HARBOR_COMMIT, "Harbor commit drift")
if stage == "prepublish":
require(release["status"] == "candidate", "release status must be candidate")
elif stage == "postpublish":
require(release["status"] == "released", "release status must be released")
else:
require(release["status"] in {"candidate", "released"},
"release status must be candidate or released")

dataset = data["dataset"]
require(dataset["version"] == "v1.0.0", "unexpected formal version")
tasks = dataset["tasks"]
files = dataset.get("files", [])
require(tasks and isinstance(tasks, list), "dataset has no tasks")
unique_rows(tasks, "name", "dataset tasks")
for item in tasks + files:
require(DIGEST.fullmatch(item["digest"]) is not None,
f"invalid digest: {item}")
expected_digest = dataset_hash(tasks, files)
require(dataset["digest"] == expected_digest, "dataset digest drift")
task_digests = {item["name"]: item["digest"] for item in tasks}

required_capabilities = set(data["coverage"]["required_capabilities"])
covered: set[str] = set()
for item in tasks:
require(item["primary_capability"] in required_capabilities,
f'unknown primary capability: {item["name"]}')
covered.add(item["primary_capability"])
require(covered == required_capabilities,
f"capability gap: {sorted(required_capabilities - covered)}")

audits = data["task_audits"]
unique_rows(audits, "name", "task audits")
require({row["name"] for row in audits} == set(task_digests),
"task audit set differs from dataset")
for row in audits:
name = row["name"]
require(row["digest"] == task_digests[name], f"task digest drift: {name}")
for field in ("verifier_digest", "reward_schema_digest",
"difficulty_evidence_digest"):
require(DIGEST.fullmatch(row[field]) is not None,
f"invalid {field}: {name}")
require(row["license_reviewed"] is True, f"license not reviewed: {name}")
require(row["generated"] is True, f"task not generated: {name}")
require(finite_number(row["oracle_reward"], f"{name}.oracle_reward") == 1.0,
f"Oracle failed: {name}")
require(finite_number(row["wrong_reward"], f"{name}.wrong_reward") == 0.0,
f"wrong answer accepted: {name}")
require(finite_number(row["gaming_reward"], f"{name}.gaming_reward") == 0.0,
f"gaming answer accepted: {name}")

smoke = data["smoke"]
require(smoke["dataset_digest"] == expected_digest, "smoke digest drift")
smoke_trials = smoke["trials"]
require(type(smoke["planned_trials"]) is int and smoke["planned_trials"] > 0,
"smoke planned_trials must be a positive integer")
require(len(smoke_trials) == smoke["planned_trials"], "smoke count mismatch")
unique_rows(smoke_trials, "trial_id", "smoke trials")
require({row["task_name"] for row in smoke_trials} == set(task_digests),
"smoke does not cover every task")
for row in smoke_trials:
require(row["task_digest"] == task_digests[row["task_name"]],
f'smoke task drift: {row["trial_id"]}')
require(row["classified"] is True, f'unclassified smoke: {row["trial_id"]}')
finite_number(row["reward"], f'{row["trial_id"]}.reward')

full = data["full_eval"]
require(full["status"] == "complete", "full eval is incomplete")
require(full["dataset_digest"] == expected_digest, "full eval digest drift")
require(full["billing_reconciled"] is True, "billing is not reconciled")
full_trials = full["trials"]
require(type(full["planned_trials"]) is int and full["planned_trials"] > 0,
"full eval planned_trials must be a positive integer")
require(len(full_trials) == full["planned_trials"], "full eval count mismatch")
unique_rows(full_trials, "trial_id", "full eval trials")
unique_rows(full_trials, "cell_id", "full eval cells")
require(len(full["planned_cells"]) == full["planned_trials"],
"planned cell count mismatch")
require(set(full["planned_cells"]) == {row["cell_id"] for row in full_trials},
"executed cells differ from preregistered cells")
for row in full_trials:
trial_id = row["trial_id"]
require(row["task_name"] in task_digests, f"unknown task: {trial_id}")
require(row["task_digest"] == task_digests[row["task_name"]],
f"full eval task drift: {trial_id}")
require(row["infrastructure_error"] is None,
f"infrastructure failure: {trial_id}")
require(isinstance(row["agent_model"], str) and "/" in row["agent_model"],
f"incomplete Agent/Model identity: {trial_id}")
reward = finite_number(row["reward"], f"{trial_id}.reward", minimum=0.0)
require(reward <= 1.0, f"{trial_id}.reward must be <= 1")
finite_number(row["cost_usd"], f"{trial_id}.cost_usd", minimum=0.0)
finite_number(row["sandbox_cost_usd"],
f"{trial_id}.sandbox_cost_usd", minimum=0.0)
finite_number(row["latency_sec"], f"{trial_id}.latency_sec", minimum=0.0)
require(type(row["judge_required"]) is bool,
f"judge_required must be boolean: {trial_id}")
if row["judge_required"]:
require(row["judge_valid"] is True, f"invalid Judge result: {trial_id}")
else:
require(row["judge_valid"] is None,
f"unexpected Judge result on gated candidate: {trial_id}")
require(DIGEST.fullmatch(row["trajectory_digest"]) is not None,
f"invalid trajectory digest: {trial_id}")
require(row["trajectory_valid"] is True,
f"invalid trajectory: {trial_id}")
require(row["trajectory_redacted"] is True,
f"unredacted trajectory: {trial_id}")
require(row["artifacts_valid"] is True,
f"invalid artifacts: {trial_id}")

judge = data["judge_calibration"]
require(judge["approved"] is True, "Judge calibration not approved")
require(judge["rubric_digest"] == full["rubric_digest"], "Judge rubric drift")
require(type(judge["required_human_gold_count"]) is int
and judge["required_human_gold_count"] > 0,
"required human Gold count must be a positive integer")
require(type(judge["human_gold_count"]) is int
and judge["human_gold_count"] >= 0,
"human Gold count must be a non-negative integer")
require(judge["human_gold_count"] >= judge["required_human_gold_count"],
"insufficient human calibration coverage")
false_accept_rate = finite_number(
judge["false_accept_rate"], "false_accept_rate", minimum=0.0)
max_false_accept_rate = finite_number(
judge["max_false_accept_rate"], "max_false_accept_rate", minimum=0.0)
require(false_accept_rate <= 1.0 and max_false_accept_rate <= 1.0,
"Judge rates must be <= 1")
require(false_accept_rate <= max_false_accept_rate,
"Judge false-accept gate failed")
require(judge["adversarial_regressions_passed"] is True,
"Judge adversarial regression failed")

if stage == "sft":
sft = data["sft"]
require(sft["status"] == "approved", "SFT export not approved")
require(sft["source_dataset_digest"] == expected_digest, "SFT source drift")
require(type(sft["rows"]) is int and sft["rows"] > 0
and type(sft["secrets_found"]) is int and sft["secrets_found"] == 0,
"SFT rows or secret scan failed")
require(sft["split_group_overlap"] is False, "SFT split leakage")
require(sft["human_sample_reviewed"] is True, "SFT human review missing")
final_status = "SFT_APPROVED"
elif stage == "rl":
rl = data["rl"]
require(rl["status"] == "experiment_ready", "RL boundary not recorded")
require(rl["training_claim"] == "none", "unverified training claim")
require(rl["source_dataset_digest"] == expected_digest,
"RL source Dataset drift")
for field in ("training_manifest_digest", "independent_eval_digest",
"split_policy_digest"):
require(DIGEST.fullmatch(rl[field]) is not None,
f"invalid RL {field}")
require(rl["independent_eval_digest"] != expected_digest,
"RL evaluation is not independent")
require(type(rl["group_overlap_count"]) is int
and rl["group_overlap_count"] == 0,
"RL train/eval source groups overlap")
require(rl["independent_eval_manifest_reviewed"] is True,
"RL independent eval manifest not reviewed")
final_status = "RL_EXPERIMENT_READY"
elif stage == "prepublish":
publication = data["publication"]
require(publication["status"] == "pending", "already published or bad state")
final_status = "READY_TO_PUBLISH"
else:
publication = data["publication"]
require(publication["status"] == "published", "publication receipt missing")
require(publication["tag"] == dataset["version"], "published tag drift")
require(publication["digest"] == expected_digest, "published digest drift")
require(publication["readback_verified"] is True, "registry readback missing")
final_status = "PUBLISHED_AND_VERIFIED"

return {
"status": final_status,
"dataset_digest": expected_digest,
"task_count": len(tasks),
"full_trial_count": len(full_trials),
"note": "synthetic only" if data.get("synthetic_fixture") else "real evidence",
}


def fixture() -> dict[str, Any]:
one, two, metric = "1" * 64, "2" * 64, "3" * 64
tasks = [
{"name": "llmkb/log-diagnosis", "digest": f"sha256:{one}",
"primary_capability": "diagnosis"},
{"name": "llmkb/python-repair", "digest": f"sha256:{two}",
"primary_capability": "repair"},
]
files = [{"path": "metric.py", "digest": f"sha256:{metric}"}]
digest = dataset_hash(tasks, files)
audits = [
{"name": item["name"], "digest": item["digest"], "generated": True,
"verifier_digest": "sha256:" + "7" * 64,
"reward_schema_digest": "sha256:" + "8" * 64,
"difficulty_evidence_digest": "sha256:" + "9" * 64,
"license_reviewed": True,
"oracle_reward": 1.0, "wrong_reward": 0.0, "gaming_reward": 0.0}
for item in tasks
]
smoke = [
{"trial_id": f"smoke-{index}", "task_name": item["name"],
"task_digest": item["digest"], "classified": True,
"reward": float(index % 2)}
for index, item in enumerate(tasks)
]
full_trials = []
for attempt in range(2):
for item in tasks:
trial_id = f'{item["name"].split("/")[-1]}-{attempt}'
reward = float(attempt)
full_trials.append({
"trial_id": trial_id,
"cell_id": f'{item["name"]}|synthetic-agent/model|{attempt}',
"agent_model": "synthetic-agent@0/provider/model",
"task_name": item["name"],
"task_digest": item["digest"], "reward": reward,
"cost_usd": 0.01, "sandbox_cost_usd": 0.02,
"latency_sec": 1.0,
"infrastructure_error": None, "judge_required": reward == 1.0,
"judge_valid": True if reward == 1.0 else None,
"trajectory_digest": "sha256:" + "4" * 64,
"trajectory_valid": True, "trajectory_redacted": True,
"artifacts_valid": True,
})
rubric = "sha256:" + "5" * 64
return {
"synthetic_fixture": True,
"release": {"status": "candidate", "harbor_version": HARBOR_VERSION,
"harbor_commit": HARBOR_COMMIT},
"dataset": {"name": "llmkb/system-diagnosis", "version": "v1.0.0",
"digest": digest, "tasks": tasks, "files": files},
"coverage": {"required_capabilities": ["diagnosis", "repair"]},
"task_audits": audits,
"smoke": {"dataset_digest": digest, "planned_trials": 2, "trials": smoke},
"full_eval": {"status": "complete", "dataset_digest": digest,
"planned_trials": 4,
"planned_cells": [row["cell_id"] for row in full_trials],
"billing_reconciled": True,
"rubric_digest": rubric,
"trials": full_trials},
"judge_calibration": {
"approved": True, "rubric_digest": rubric,
"required_human_gold_count": 4, "human_gold_count": 4,
"false_accept_rate": 0.0, "max_false_accept_rate": 0.0,
"adversarial_regressions_passed": True,
},
"sft": {"status": "approved", "source_dataset_digest": digest, "rows": 2,
"secrets_found": 0, "split_group_overlap": False,
"human_sample_reviewed": True},
"rl": {"status": "experiment_ready", "training_claim": "none",
"source_dataset_digest": digest,
"training_manifest_digest": "sha256:" + "a" * 64,
"independent_eval_digest": "sha256:" + "6" * 64,
"split_policy_digest": "sha256:" + "b" * 64,
"group_overlap_count": 0,
"independent_eval_manifest_reviewed": True},
"publication": {"status": "pending"},
}


def self_test() -> None:
good = fixture()
assert check_release(good, "prepublish")["status"] == "READY_TO_PUBLISH"
assert check_release(good, "sft")["status"] == "SFT_APPROVED"
assert check_release(good, "rl")["status"] == "RL_EXPERIMENT_READY"
mutations = {
"version_drift": ("prepublish", lambda x: x["release"].update(
harbor_version="0.19.0")),
"dataset_drift": ("prepublish", lambda x: x["dataset"].update(
digest="sha256:" + "0" * 64)),
"oracle_fail": ("prepublish", lambda x: x["task_audits"][0].update(
oracle_reward=0.0)),
"gaming_pass": ("prepublish", lambda x: x["task_audits"][0].update(
gaming_reward=1.0)),
"missing_trial": ("prepublish", lambda x: x["full_eval"]["trials"].pop()),
"duplicate_trial": ("prepublish", lambda x: x["full_eval"]["trials"][1].update(
trial_id=x["full_eval"]["trials"][0]["trial_id"])),
"infrastructure": ("prepublish", lambda x: x["full_eval"]["trials"][0].update(
infrastructure_error="SyntheticProviderError")),
"judge_invalid": ("prepublish", lambda x: x["full_eval"]["trials"][2].update(
judge_valid=False)),
"cost_missing": ("prepublish", lambda x: x["full_eval"]["trials"][0].update(
cost_usd=None)),
"sft_overlap": ("sft", lambda x: x["sft"].update(split_group_overlap=True)),
"rl_overlap": ("rl", lambda x: x["rl"].update(group_overlap_count=1)),
"judge_boolean_count": ("prepublish", lambda x: x["judge_calibration"].update(
required_human_gold_count=True, human_gold_count=True)),
}
rejected = 0
for name, (stage, mutate) in mutations.items():
broken = copy.deepcopy(good)
mutate(broken)
try:
check_release(broken, stage)
except (GateError, KeyError, TypeError):
rejected += 1
else:
raise AssertionError(f"mutation was accepted: {name}")
print(f"SELF_TEST_OK rejected={rejected} synthetic=true")


def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("evidence", nargs="?", type=Path)
parser.add_argument("--stage", choices=("prepublish", "postpublish", "sft", "rl"),
default="prepublish")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args()
try:
if args.self_test:
self_test()
else:
require(args.evidence is not None, "evidence path required")
print(json.dumps(check_release(load_json(args.evidence), args.stage),
ensure_ascii=False, indent=2, allow_nan=False))
except (GateError, KeyError, TypeError, json.JSONDecodeError) as error:
print(f"RELEASE_BLOCKED: {error}", file=sys.stderr)
return 1
return 0


if __name__ == "__main__":
raise SystemExit(main())

把代码保存到项目根目录后运行:

python release_gate.py --self-test

本章实际提取并执行这段脚本,预期输出是:

SELF_TEST_OK rejected=12 synthetic=true

自测只证明门禁能接受一个内部一致的合成候选,并拒绝十二种受控变异;它不证明真实 Task 已构建、Oracle 已运行、云端完整评测已完成或 Dataset 已发布。真实 candidate.json 必须由锁文件、逐 Trial 结果、Provider 账单、Judge 校准与人工签字生成,不能复制 fixture() 中的数字。

prepublish/postpublishsftrl 是三个独立审批轴:Benchmark 可以在没有训练计划时发布;SFT 也不能因 Benchmark 已发布而跳过数据治理。脚本复用同一来源证据,但分别输出 READY_TO_PUBLISHSFT_APPROVEDRL_EXPERIMENT_READY

29.6 校准 Judge,再解释开放质量

确定性 correctness 是硬门,Judge 是独立测量轴。最终校准沿用第 12 章的流程,但发布时必须把流程产物化:冻结 rubric、Judge model 精确标识、Reward Kit 版本、输入文件清单、trajectory 格式化、mode、重复政策和升级规则;盲化抽取清晰通过、清晰失败、边界、冗长变体、顺序变体、注入文本与证据缺失样本;至少两名领域评审独立标注,先解决人工分歧,再在未用于改 rubric 的保留集验收 Judge。

不要为所有项目发明一个“80% 一致率”的通用标准。错误代价决定门槛:危险运维建议被错误接受,通常比一份合格报告被送去人工复核更严重。candidate.json 因此保存项目预先批准的 required_human_gold_countmax_false_accept_rate,门禁只比较“实际是否达到本项目承诺”,不把合成 fixture 的 4 和 0 当作推荐值。

MT-Bench/Chatbot Arena 的原始研究专门分析了模型裁判的 position、verbosity、self-enhancement 与推理能力限制。12 这些研究不能直接告诉本项目会错多少,却说明应把换序、等事实不同长度、隐藏模型身份和对抗注入变成回归 fixture。高重复一致性也不是正确性的充分条件;一个裁判可以稳定偏爱冗长文本。报告必须并列给出人工—人工、Judge—人工、Judge 自身重复以及对抗变体四类结果。

Harbor v0.18.0 Reward Kit 的 Judge timeout 会在 Score 中留下零值与 error,而不是自动把整个 Trial 标成“未评分”。13 最终分析必须先看 reward-details.json 的 error、warnings 和原始输出,再决定质量维度是否有效。门禁中的 judge_valid 应由这个解析过程生成,不能简单写成 quality >= 0;否则裁判超时产生的零分会被误认为候选质量差。

29.7 生成报告,而不是只生成排名

正式报告先说明身份和分母,再说明比较结果。下面的 YAML 是空模板null 表示尚未填入真实运行结果:

release:
dataset: llmkb/system-diagnosis
version: v1.0.0
digest: null
harbor: {version: 0.18.0, commit: 527d50deb63a5d279e8c20593c18a2cbc7f61f9e}
protocol:
planned_trials: null
completed_trials: null
attempts_per_cell: null
retry_policy: null
deviations: []
quality:
primary_success: {successes: null, denominator: null, interval: null}
mean_reward: {value: null, valid_n: null, missing_n: null}
dimensions: []
judge:
calibration_version: null
human_gold_n: null
false_accepts: null
invalid_or_missing_trial_n: null
cost:
agent_model_usd: {known_total: null, covered_trials: null, missing_trials: null}
sandbox_usd: {provider_total: null, covered_trials: null}
storage_and_network_usd: null
speed:
trial_latency_sec: {median: null, p90: null, valid_n: null}
agent_latency_sec: {median: null, p90: null, valid_n: null}
failures:
infrastructure: null
agent_or_candidate: null
verifier: null
judge: null
unknown: null
evidence:
job_locks: []
trial_results: []
trajectories: {valid: null, invalid: null, missing: null}
artifacts: {ok: null, failed: null}
provider_bills: []
limits: []

质量、成本和速度的有效样本数必须分别给出。主成功率保留事前计划分母,因此基础设施失败不会从模型比较中静默消失;失败表同时将它们与候选错误分开,避免把平台事故解释成 Agent 能力。维度均值按该维度的有效 n 计算,缺 Judge 不补零。模型成本来自 Agent context 时仍需与 Provider 账单核对;沙箱、存储、网络和人工校准成本另列。端到端 Trial 时长、Agent 执行时长和 Job 墙钟时间也不能互换。

轨迹报告至少列有效、无效、缺失和被脱敏拒绝的数量,再按高 Reward、边界 Reward、基础设施失败和 Judge 分歧分层抽检。trajectory 是行为证据,不是真值:缺少某次文件访问记录不能证明 Agent 没有访问;反过来,轨迹里声称“修复成功”也不能替代 Verifier。发布的高层结论都应能沿 report row → trial_id → result/lock/trajectory/artifact → task_digest 回溯。

29.8 发布、回读与证据封存

预发布门通过后,先发布为 private,记录 CLI 输出中的 Dataset 名、内容 hash、revision、Task/File 数、状态和 tags。v0.18.0 的发布器把 latest 与显式 tags 一起提交,并返回服务端内容 hash;--public 还可能提升关联 Task 的可见性,因此公开不是一个无害的显示开关。37

发布回读使用一个空缓存目录:

rm -rf /tmp/system-diagnosis-v1-readback
harbor dataset download llmkb/system-diagnosis@v1.0.0 \
--output-dir /tmp/system-diagnosis-v1-readback --overwrite

dataset download 接受 name@version;package client 会把该引用解析成精确 Dataset 内容 hash、逐 Task digest 与 Dataset 级文件,并下载这些内容。14 CLI 不会替团队生成完整的发布验证报告。回读门应使用候选 manifest 与 Registry 元数据重新计算 Task/Dataset 摘要,并用正式 Job 配置中的精确 digest 运行一个 Registry smoke。只有 tag 解析到候选 digest、Task 数与摘要相同、最小 Oracle/负例仍通过,才把 publication.statuspending 改为 published,填写 publication-receipt.json,再运行:

python release_gate.py release/candidate.json --stage postpublish

期待真实证据输出 PUBLISHED_AND_VERIFIED,而不是自测的 synthetic only。随后才决定是否把 Dataset 改为 public。公开前再次检查许可证、README、测试中的隐藏数据、Solution 可见性、轨迹与 Artifact 脱敏以及删除请求流程。

运行 postpublish 门之前,还要把 release.statuscandidate 改为 released,并填写 publication.status=published、tag、digest 与 readback_verified=true;这次状态变化必须与 Registry 回执属于同一次受审操作。

警告:不要把凭据、Provider 原始环境变量、未脱敏 trajectory 或包含客户数据的 Artifact 放进发布回执。回执保存标识符、摘要、状态和受控证据位置,不复制秘密本身。

封存包至少包括:dataset.toml、Task/package digest 清单、Harbor 与 Python 版本、完整依赖锁、Job config/lock、全部逐 Trial 结果、失败台账、分析代码、Judge 校准、账单覆盖说明、报告、发布回执和已知限制。原始含敏感信息的证据进入访问受控存储;公开包保存脱敏派生物及其来源关系。摘要能检测内容变化,不能提供访问控制。

29.9 从正式 Trial 导出 SFT 数据

Benchmark 发布与 SFT 导出是两条并行审批链。Harbor v0.18.0 的隐藏 traces export 命令会递归发现 Trial、按 all|last 选择 episode,可按 success/failure 过滤,并可把支持 ATIF 的 Agent 轨迹转成 Hugging Face Dataset--push 会直接上传。1516 在治理完成前不要使用 --push。先在隔离暂存区运行发现:

harbor traces export --path jobs/system-diagnosis-full-v1 \
--recursive --episodes all --filter success --no-subagents --verbose

这里的 success 在导出器中采用主结果大于零的过滤语义,不等于本章的“可进入训练”政策。17 后续治理脚本仍要拒绝异常、缺失或非有限 Reward,按组织阈值筛选,检查 ATIF episode/continuation,脱敏,按 Task/来源组去重与切分,确认训练、开发和最终评测组不重叠,并做人工抽检。输出另存不可变 manifest:源 Job、Task/Dataset digest、过滤代码 digest、行数、删除原因、字段 schema、许可证、split group 和删除/重建流程。

导出成功只表示得到了符合转换契约的行。它不表示对话质量足够、版权与隐私已批准、SFT 已执行,更不表示训练后的 Agent 会提升。门禁中的 sft.status=approved 是数据治理批准;训练收益仍需独立训练实验和不与训练组重叠的评测。

治理 manifest 填完后单独运行 python release_gate.py release/candidate.json --stage sft;这个结果不改变 publication.status

29.10 后续 RL:只发布实验边界

本书锁定版本中,Harbor 的职责是构建 Task/Trial/Job、运行 Environment/Agent/Verifier 并产出 Reward 与可选 rollout 细节;优化器、checkpoint、tokenizer/renderer、advantage、loss、分布式状态和训练重放属于外部训练系统。Job.create(config) 是 v0.18.0 的真实创建入口,Job 会从 attempt×Task×Agent 展开 Trial。18 第 24 章已经构建了拒绝缺 token、缺 logprob、非有限 Reward、异常和错误 split 的最小 Adapter;那是 PPO/重要性比率场景的教学契约,不是 Harbor 对所有 RL 算法的统一要求。

因此最终发布只把 RL 标为 experiment_ready

  • train/development/final-eval 按 Task 或来源组隔离;
  • rollout 绑定 Task digest、Reward schema、policy checkpoint、tokenizer/renderer 与采样参数;
  • 训练反复接触的 Verifier 不作为唯一最终评测器;
  • 基础设施失败不变成合法零 Reward,retry 不冒充额外采样;
  • 独立评测使用另一份 manifest/digest,并保留重复与不确定性;
  • training_claim 保持 none,直到真实训练、对照和独立评测完成。

“独立评测”不能只靠两个 manifest 的摘要不同来证明:一个 Task 增减就会改变摘要,而来源组仍可能重叠。RL 审批证据还要绑定源 Dataset、训练 manifest、独立评测 manifest 和 split policy 的摘要,计算来源组交集为零,并由维护者复核独立评测清单;门禁中的 group_overlap_countindependent_eval_manifest_reviewed 就是为此保留的失败关闭字段。

若后续实验观察到提升,报告要同时给训练预算、策略版本、种子/重复、每 Task 分布、失败类型、置信区间和负面结果。Reward 上升可能来自策略改进,也可能来自更会利用当前 Verifier;必须在未暴露的任务变体和独立评分边界上复验。

训练前先运行 python release_gate.py release/candidate.json --stage rlRL_EXPERIMENT_READY 只批准数据与隔离边界,不批准任何收益措辞。

29.11 持续维护、回滚与退役

生产 Benchmark 是被维护的测量系统,不是一次发布后不变的压缩包。

事件必做动作不允许的捷径
instruction 拼写修复新 Task digest、影响分析、三类 fixture 重跑原地改包继续引用旧结果
Verifier 漏洞撤销受影响结论、发布新 Reward schema/Dataset 版本、重评只改分数表
Judge model/rubric 变化新校准版本、保留集与对抗回归沿用旧一致性数字
Harbor 升级新分支/锁文件、兼容矩阵、Oracle/负例/full regressionmain 文档当成 v0.18.0
Provider/模型退役冻结旧结果、记录不可重放边界、定义替代协议用近似模型覆盖旧身份
数据删除或许可变化定位受影响 digest、停止再分发、发布删除/替代说明只从 README 删除名称

回滚不是把 latest 移回旧标签,而是在生产消费者配置中恢复前一个已验证 digest,并保留故障版本及其撤销说明。旧结果只有在 Task、Verifier、Reward schema 和分析口径均兼容时才可比较;否则并列呈现,不拼接趋势线。

退役时停止新正式运行和发布,保存最终版本、原因、替代项、结果可用边界与保留期。若法律、许可证或安全事件要求删除内容,摘要仍可用于定位受影响发布,但不能成为继续分发的理由。维护者应定期执行:Registry 回读、Oracle/负例/gaming 回归、Judge 锚点重放、依赖和凭据扫描、成本漂移、Task 区分度与能力缺口审查。

29.12 扩展案例一:代码修复 Agent Benchmark

代码修复案例不需要重新发明流水线,只需把领域契约映射到同一质量门。

任务映射:每个 Task 固定仓库快照与依赖锁,instruction 描述可见故障而不泄漏 gold patch;Agent 输出工作区补丁;Verifier 在干净副本中应用补丁,运行原始失败测试、回归测试与静态安全检查。主能力可分为故障定位、局部修复、跨模块修复和测试设计,来源组用仓库/issue 家族,防止同仓近重复跨 split。

三类 fixture:Oracle 是已审查补丁,不是唯一合法文本;错误答案包含“只改测试期望”和“删除失败测试”;gaming 答案尝试修改测试入口、伪造测试输出、读取 gold patch 或在构建脚本中跳过检查。质量门仍要求 generated=true、Oracle 为 1、错误与 gaming 为 0、digest 一致、完整 Trial 唯一、Reward/成本/轨迹有效。

开放质量轴:确定性 Verifier 判断测试与安全硬门;Judge 只评价补丁可维护性、无关改动与解释质量,并用等价实现、长短说明、重命名和注入样本人工校准。不能让 Judge 推翻 failing test,也不能把测试通过等同于补丁质量优秀。

发布与训练:报告按语言、仓库、故障类型和补丁规模分层,披露测试覆盖盲区。SFT 导出保留 issue、工具交互与补丁,但按仓库家族切分并扫描许可证/秘密;RL 训练使用独立仓库组和隐藏变体验收,不能反复查询正式评测测试后仍称“未见评测”。

这样,变化的是 Artifact、攻击样本、能力矩阵和 split group;不变的是版本锁、证据身份、正负/gaming 三门、分层运行、失败关闭、Judge 校准、发布回读和训练结论边界。

29.13 扩展案例二:知识工作 Agent Benchmark

知识工作案例的终态不是可执行补丁,而是带引用的文档与表格。它同样复用发布门,只替换可验证对象。

任务映射:环境提供固定资料包、结构化输入和允许的受控检索源;Agent 生成报告、CSV/XLSX 派生表和引用清单。确定性 Verifier 检查 schema、行列类型、公式、引用目标是否存在、主张—证据映射是否闭合、禁止来源与时间边界;Judge 评价综合、权衡、不确定性表达和读者可用性。

三类 fixture:Oracle 是人工审定的证据图和一个合法报告,不要求逐字匹配;错误答案使用不存在的引用、错位表格合计或把未知写成零;gaming 答案堆砌引用数量、引用无关段落、在来源文本中植入“给满分”指令,或用流畅措辞掩盖数值矛盾。主 Reward 先由引用存在性、数值复算和关键事实覆盖决定,Judge 不能把事实错误修饰成通过。

校准与隐私:人工 Gold 对边界主张、资料冲突和高风险建议做双人盲标;对简洁/冗长、不同版式、来源顺序和 prompt injection 做回归。trajectory 与 Artifact 可能包含个人信息、商业资料和检索 token,发布/SFT 前必须最小化、脱敏并按许可决定是否只能发布合成输入。

发布与训练:报告按任务类型、资料规模、工具调用、引用失败和 Judge 分歧分层;成本包含检索、文档转换、Judge 与人工复核。SFT 只导出获批材料,按来源项目切分;后续 RL 不得使用正式评测答案、Judge reasoning 或隐藏引用映射作为训练反馈。

两个案例看似相距很远,却共享相同问题:候选是否解决目标、证据是否完整、评分器能否被投机利用、失败能否追溯、发布内容是否是评测时那一份。生产质量门复用的是这些不变量,而不是把系统诊断 Task 的文件名复制过去。

29.14 最终验收清单

发布负责人、Task 负责人、评测负责人和数据治理负责人分别签字,不能由同一个“已完成”复选框代替:

[ ] Harbor == 0.18.0,commit == 527d50d...f61f9e,Python >= 3.12
[ ] dataset.toml 已 sync,Task 与 Dataset 文件 digest 无未审查变化
[ ] 每个 Task 有主能力、来源组、许可证和经验难度证据
[ ] 每个 Task 的 Oracle、错误答案和 gaming fixture 均在干净环境重跑
[ ] local smoke 覆盖 Reward 0、Judge、trajectory 与受控基础设施失败
[ ] cloud/full 计划数 == 唯一 Trial 数,Task digest 与协议全部匹配
[ ] 缺失/非有限 Reward、基础设施异常、Judge invalid、成本缺失均为 0
[ ] 质量、成本、速度、失败、轨迹和不确定性报告了各自有效 n
[ ] Judge 的人工 Gold、保留集、重复与对抗回归达到事前门槛
[ ] private publish 回执完整,tag/digest 回读与 Registry smoke 通过
[ ] Dataset Card/README 写明组成、用途、限制、许可证与维护/退役策略
[ ] SFT 已脱敏、去重、按来源组切分、抽检,且训练收益声明仍为空
[ ] RL 只标 experiment-ready,独立评测 digest 与训练 Dataset 隔离
[ ] 回滚 digest、事故响应、删除请求、升级兼容矩阵与退役责任人明确

有一项不能证明,就把它写成未执行边界,并阻断相应结论。可以发布“内部预览但未做云端完整评测”,不能发布“生产级完整评测”再把缺项藏进脚注。

29.15 本章小结

  • 生产级 Benchmark 是证据链,不是一次高 Reward Job;生成、可解、smoke、完整评测、发布和训练收益必须分别声明。
  • Task digest 与 Dataset digest固定内容身份,但不能代替能力覆盖、许可证、安全或统计有效性。
  • 发布门必须拒绝缺失/非有限 Reward、异常、Judge 无效、成本缺失、重复 Trial 和任何 Task/digest 漂移。
  • 完整报告同时给出质量、成本、速度、失败、轨迹、分母、不确定性和协议偏离,不以排行榜代替审计。
  • SFT 与 RL 都从正式 Trial 受控派生,却各有独立治理、split 和验证门;导出或接入不等于训练收益。
  • 代码修复与知识工作案例复用相同质量不变量,只替换领域 Artifact、攻击样本、能力矩阵和分组策略。
  • 维护、回滚与退役是 Benchmark 生命周期的一部分;任何评分语义或运行基线变化都要新版本和复测。

29.16 练习

  1. release_gate.py 的合成 fixture 写成 JSON,再分别注入 NaN、重复 JSON key、Task checksum 漂移和 Judge timeout。确认严格解析或门禁返回非零,并解释每个失败属于哪一层结论。
  2. 为贯穿项目补全六项能力矩阵。给每个 Task 指定一个主能力和来源组,设计 baseline panel 与难度复核规则;不要用作者标签代替观测。
  3. 设计一次真实但小规模的 Judge 校准计划:给出人工样本的分层、错误代价、保留集、对抗变体、预注册门槛和升级规则。结果字段保持空白,直到实际完成标注。
  4. 选择代码修复或知识工作案例,为一个 Task 写出 Oracle、明显错误和两个 gaming fixture,并说明确定性 Verifier 与 Judge 各自有权判断什么。
  5. 演练一次回滚:假设 v1.0.1 的 Verifier 发现假阳性,列出停止发布、定位受影响 Job、恢复消费者 digest、重评、报告撤销和发布 v1.0.2 的证据步骤。

参考资料

Footnotes

  1. Harbor Framework Team,pyproject.toml 与版本标签,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/pyproject.toml#L1-L9https://github.com/harbor-framework/harbor/tree/527d50deb63a5d279e8c20593c18a2cbc7f61f9e,访问于 2026-07-16。

  2. Harbor Framework Team,TrialResult、token/cost 聚合与 JobStats,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/trial/result.py#L69-L129https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/job/result.py#L28-L42https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/job/result.py#L129-L169,访问于 2026-07-16。

  3. Harbor Framework Team,harbor publish 参数、Dataset 自动 sync 与发布结果,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/publish.py#L99-L128https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/publish.py#L317-L397,访问于 2026-07-16。 2

  4. Harbor Framework Team,harbor sync 的本地摘要更新、可选 Registry upgrade 与写回,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/sync.py#L21-L125https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/sync.py#L128-L249,访问于 2026-07-16。

  5. Harbor Framework Team,Task 文件收集与内容摘要算法,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/publisher/packager.py#L35-L90,访问于 2026-07-16。 2

  6. Harbor Framework Team,DatasetTaskRef/DatasetFileRef 的 digest 约束及 DatasetManifest.compute_content_hash(),Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/dataset/manifest.py#L24-L107https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/dataset/manifest.py#L240-L267,访问于 2026-07-16。

  7. Harbor Framework Team,Dataset 发布时的文件、tag、Task digest 与回执,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/publisher/publisher.py#L369-L440,访问于 2026-07-16。 2

  8. National Institute of Standards and Technology,NIST AI RMF Playbook,Measure 与持续风险管理建议,https://airc.nist.gov/airmf-resources/playbook/,访问于 2026-07-16。

  9. Timnit Gebru 等,Datasheets for Datasets,Communications of the ACM 64(12),2021,https://arxiv.org/abs/1803.09010,访问于 2026-07-16。

  10. Hugging Face,Dataset CardsUploading datasetshttps://huggingface.co/docs/hub/datasets-cardshttps://huggingface.co/docs/hub/datasets-adding,访问于 2026-07-16。

  11. Harbor Framework Team,Job 结果写盘排除 trial_results 与 Job 最终聚合,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L472-L480https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L808-L857,访问于 2026-07-16。

  12. Lianmin Zheng 等,Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena,NeurIPS 2023 Datasets and Benchmarks Track,https://proceedings.neurips.cc/paper_files/paper/2023/file/91f18a1287b398d378ef22505bf41832-Paper-Datasets_and_Benchmarks.pdf,访问于 2026-07-16。

  13. Harbor Framework Team,Reward Kit Score 错误字段与 Judge timeout 路径,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/packages/rewardkit/src/rewardkit/models.py#L111-L139https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/packages/rewardkit/src/rewardkit/judges.py#L285-L304,访问于 2026-07-16。

  14. Harbor Framework Team,harbor dataset downloadname@version、输出与 export/cache 选项,以及 package Dataset 的版本/文件解析和下载,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/datasets.py#L155-L257https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/registry/client/package.py#L20-L93https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/registry/client/base.py#L83-L110,访问于 2026-07-16。

  15. Harbor Framework Team,harbor traces export 的路径、episode、过滤与 push 选项,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/traces.py#L11-L115,访问于 2026-07-16。

  16. Harbor Framework Team,export_traces() 的输入、返回对象、ATIF Agent 门禁与 Hub 上传,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/traces_utils.py#L1117-L1194https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/traces_utils.py#L1230-L1249https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/traces_utils.py#L1387-L1423,访问于 2026-07-16。

  17. Harbor Framework Team,SFT 导出 success/failure 判定,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/traces_utils.py#L1251-L1263https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/traces_utils.py#L1426-L1449,访问于 2026-07-16。

  18. Harbor Framework Team,Job.create() 与 Trial 展开,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L51-L134https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L347-L387,访问于 2026-07-16。