跳到主要内容

第 3 章:安装 Harbor 并完成第一次评测

一位工程师已经看见 harbor --help,便认为安装结束了。真正运行第一个 Job 时,命令却在创建 Trial 之前退出:Docker is not installed or not on PATH. 这类失败很容易被误判为“任务坏了”,其实 Agent、Verifier 乃至任务镜像都还没有开始运行。

本章把安装定义为一条可验收的链:固定 Harbor v0.18.0,确认 Python 与 Docker 前置条件,分别解析注册 Dataset 和本地 Dataset,用 Oracle 完成一次不调用模型的冒烟评测,读取 Job 输出,再启动 Viewer。最后才换成真实 Agent。全章只使用提交 527d50deb63a5d279e8c20593c18a2cbc7f61f9e 对应的 v0.18.0 命令。该版本在项目元数据中声明 Python >=3.12,并注册 harborhrhb 三个入口;本书统一使用可读性最好的 harbor1

读完本章,读者应当能够:

  • 用 uv 在独立工具环境中安装并固定 Harbor v0.18.0;
  • 区分“CLI 可执行”“Docker 可用”和“Job 成功”三种状态;
  • 解释注册 Dataset、Dataset 本地目录与单个 Task 路径的不同入口;
  • 用 Oracle 验证最小任务,并从 result.json 与 Verifier 日志验收结果;
  • 在明确凭据、成本和非确定性之后运行一个真实 Agent;
  • 用 Viewer 浏览 Job,并按阶段定位常见安装与运行失败。

3.1 把“安装成功”写成五个检查点

Harbor 的本地默认执行环境是 Docker。于是,一个能打印版本号的 Python 命令并不能证明评测系统已就绪。更有用的检查顺序是:

检查点要证明什么失败时先检查
uv能创建隔离的工具环境并选择 PythonPATH、网络、证书与代理
PythonHarbor 使用的解释器满足 v0.18.0 要求uv 的 --python 选择,而非只看系统 python3
Harbor CLI安装的是 0.18.0,命令来自该版本包版本、旧入口冲突、工具 bin 目录
DockerCLI 能连接正在运行的 daemon,Compose V2 支持 up --waitDocker Desktop/Engine、Compose plugin、当前 context 与权限
Job 闭环Task 能构建、Agent 能运行、Verifier 能写 RewardTrial 的异常、Agent/Verifier 日志与网络

这个顺序很重要。Harbor v0.18.0 的 Docker preflight 先在 PATH 中寻找 docker,再调用 docker info;前者不存在时报告未安装,后者失败或超时时报告 daemon 未运行。2 这两类 preflight 错误出现在 Job 创建之前,不会生成一个“Reward 为 0”的 Trial。不过,preflight 不检查 Compose;完整 Docker Environment 会用 docker compose 执行 builddownup --detach --wait3 因而 Compose plugin 缺失或版本不支持 --wait 时,前置检查可以通过,失败却会发生在已经创建 Trial 之后。

还要区分“准备动作”和“评测动作”。安装 Harbor、检出 Task、查看帮助和执行 --print-config 都不会证明 Task 可运行;Docker preflight 只证明当前 CLI 能连到 daemon;镜像构建成功也只证明环境可创建。真正的闭环要依次经过以下阶段:

解析 Job 配置
→ Docker preflight
→ 定位/下载 Task
→ 构建并启动 Environment
→ Agent.setup / Agent.run
→ Verifier 执行测试并读取 Reward
→ 写 Trial result.json
→ 聚合并写 Job result.json

因此,排障时应记录“最后一个有证据的阶段”。例如,只有 --print-config 的 JSON,结论只能是 CLI 参数有效;有镜像构建日志但没有 Trial result.json,应检查环境启动与编排;有 result.jsonexception_info 非空,说明 Harbor 已把失败持久化;只有 Verifier 明确生成 Reward,才可以讨论任务得分。这种阶段化表述可以防止把基础设施失败计成 Agent 的 0 分,也可以防止把解析成功包装成一次评测。

本章使用以下稳定路径:

~/harbor-lab/
├── harbor-v0.18.0/ # 精确标签源码,只用于本章示例 Task
└── jobs/
├── first-oracle/
└── first-real-agent/

jobs 是输出,不要放进 Harbor 源码目录;这样重装工具或重新检出源码时不会混入实验结果。

3.2 用 uv 安装精确版本

先确认 uv,再让 uv 管理 Python

若机器尚未安装 uv,使用 Astral 官方安装说明选择适合操作系统的方法。官方提供 macOS/Linux 独立安装脚本,也允许先查看脚本内容;在受管机器上应优先遵循组织的软件分发策略。uv 能下载指定 Python,并为 uv tool install 创建长期存在的隔离环境。4

下面的检查可在任意目录运行。前置条件是 uv 已在 PATH 中且允许下载 Python;预期看到 uv 版本,并能定位或下载 CPython 3.13。失败通常表现为 command not found、TLS/代理错误或目标平台没有可用发行包。验收标准是两条命令均以 0 退出,而不是系统 python3 --version 恰好满足要求。

uv --version
uv python install 3.13
uv python find 3.13

这里选择 3.13 是本章的可复现安装策略,并不把 Harbor 的声明偷改成“只支持 3.13”:v0.18.0 的正式下限仍是 3.12。显式指定次版本可以避免 uv 在未来选择一个刚发布、而传递依赖尚未提供兼容 wheel 的更高版本。uv 的工具环境支持用 --python 请求具体解释器;工具的可执行文件会链接到工具 bin 目录。5

安装并锁定 Harbor

下面的命令也可在任意目录运行。前置条件是 PyPI 可访问且 uv 能找到 Python 3.13;它会写入 uv 的工具目录,不会修改当前项目的虚拟环境。预期安装三个入口,harbor --version 输出 0.18.0。若 shell 找不到 harbor,先按 uv 的提示执行 uv tool update-shell,再打开新 shell;若已有同名但非 uv 管理的入口,先用 command -v harbor 查明来源,不要盲目 --force 覆盖。两次版本输出一致才算验收。

uv tool install --python 3.13 "harbor==0.18.0"
uv tool list
harbor --version

版本固定有两层含义。"harbor==0.18.0" 固定发布包;harbor --version 验证实际调用的入口,而不是相信安装日志。以后升级必须作为一次显式实验,不要在同一组 Benchmark 中途执行无版本约束的升级。

不过,这条命令固定的是 Harbor 顶层版本,不是把未来所有传递依赖都冻结成 2026-07-15 的解析结果。长期复现实验除记录 harbor --version 外,还应保存 Job 的 config.jsonlock.json 和原始输出,并记录安装日期与平台;若组织需要逐包复现,应在自己的部署流程中保存经过验证的 wheel/镜像或锁定安装快照。本章不自行修改 Harbor 的依赖约束,因为那会产生一个不再等同于官方 v0.18.0 的私有发行环境。

团队机器还应把这三项写进实验记录:操作系统与架构、实际 Python 次版本、Harbor 入口的绝对路径。这样同事遇到不同结果时,能先比较运行基线,而不是仅交换一条无法解释环境差异的命令。

注意:本章在 2026-07-15 的隔离验证中,省略 --python 3.13 后,uv 自动选择了 Python 3.14;当时解析到的 litellm==1.92.0 需要构建 Rust 扩展,而其 PyO3 最高支持 3.13。实际失败节选为:configured Python interpreter version (3.14) is newer than PyO3's maximum supported version (3.13)。加上 --python 3.13 后,82 个包安装完成,harbor --version 返回 0.18.06 这是特定日期的传递依赖兼容故障,不是 Harbor 元数据声明了 Python 3.14 支持上限。

取得精确的本地示例

安装包提供 CLI,但第一次本地评测还需要 Task。下面从 ~/harbor-lab 运行;前置条件是 Git 与 GitHub 网络可用,且目标目录不存在。预期检出 v0.18.0,两个校验命令分别打印固定提交和标签。失败表现包括目录已存在、网络中断或标签不匹配。只有提交与标签同时匹配才验收,不能仅凭目录名判断版本。

mkdir -p ~/harbor-lab
cd ~/harbor-lab
git clone --branch v0.18.0 --depth 1 \
https://github.com/harbor-framework/harbor.git harbor-v0.18.0
cd harbor-v0.18.0
git rev-parse HEAD
git describe --tags --exact-match HEAD

预期的提交是:

527d50deb63a5d279e8c20593c18a2cbc7f61f9e
v0.18.0

3.3 Docker 与 CLI 的独立验收

macOS 和 Windows 通常安装 Docker Desktop,Linux 可按发行版安装 Docker Engine 与 Compose plugin;只下载 macOS 的 Docker CLI 二进制并不会提供运行容器所需的 daemon。Docker 官方把 docker info 定义为显示系统范围的 client/server 信息,适合检查 CLI 是否真的连到了 daemon。7

下面可在任意目录运行。前置条件是 Docker 已安装并启动,当前用户能访问 daemon,Compose V2 plugin 可用,首次拉取镜像时网络可用。docker info 应同时给出 server 信息,docker compose version 应返回 V2 版本,up 帮助应包含 Harbor 会调用的 --waithello-world 容器应打印确认信息后退出。docker: command not found 表示 CLI 不在 PATHCannot connect to the Docker daemon 表示 daemon、context 或权限有问题;docker: 'compose' is not a docker command 或帮助中没有 --wait 表示 Compose 前置仍不满足。四项均成功才验收。

docker info
docker compose version
docker compose up --help | grep -F -- '--wait'
docker run --rm hello-world

接着在任意目录检查 v0.18.0 的 CLI。前置条件是前一节安装完成;预期帮助中有 runviewdatasetjob,并且 run 的 Dataset 面板包含 --path/-p--dataset/-d--task/-t。若帮助展示不同选项或版本不是 0.18.0,说明命中了别的安装。验收方式是同时记录版本和帮助,而不是从在线 main 文档抄命令。

harbor --version
harbor --help
harbor run --help
harbor dataset --help
harbor view --help

v0.18.0 把单数 datasetjobtask 作为主要命令组;复数形式仍是隐藏的兼容别名。正文统一使用单数形式。runharbor job start 的别名,二者启动同一种 Job。8

3.4 从 Dataset 到第一次 Oracle Job

注册 Dataset 与本地 Dataset 不是同一个地址空间

v0.18.0 的 run 可从注册表包、Git 仓库或本地目录解析 Dataset。对本章最重要的是前两种写法:-d 表示注册 Dataset 的名称与版本/引用,-p 表示本地 Task 或 Dataset 目录。若 -p 指向一个有效 Task,CLI 直接创建 Task 配置;否则把该目录视为 Dataset,并枚举其有效 Task 子目录。9

目的v0.18.0 写法本章用途
浏览 Registryharbor dataset list默认输出 Harbor Hub Dataset 地址
查看旧式表格 Registryharbor dataset list --legacy需要网络,会列出 Dataset 表
解析注册 Datasetharbor run -d "name@version" ...适合发布后的共享入口
运行本地 Datasetharbor run -p path/to/tasks ...枚举目录下的 Task,可用 -i 过滤
运行单个本地 Taskharbor run -p path/to/task ...最短、最容易排障的首次闭环

先在 ~/harbor-lab/harbor-v0.18.0 运行下列只读/配置检查。前置条件是精确源码已检出;这四条都不下载远程 Task,第一条只打印 Hub 地址,第二条实际读取标签自带的 registry.json。两个 --print-config 只应分别显示注册 Dataset 的名称、版本与 Registry 路径,以及本地 Dataset 的路径、hello-world 过滤条件与数量上限;它们不会枚举出“只含 hello-world”的实际 Task 列表。第二条可发现 registry.json 路径或内容错误;后两条的验收仅是 JSON 正确记录了预期来源与过滤条件,且没有创建 Job。

cd ~/harbor-lab/harbor-v0.18.0
harbor dataset list
harbor dataset list --registry-path ./registry.json --legacy
harbor run -d "hello-world@1.0" --registry-path ./registry.json \
-a oracle --print-config
harbor run -p examples/tasks -a oracle \
-i hello-world -l 1 --print-config

--print-configJob.create() 之前返回,只证明 CLI/Pydantic 构造出了 JobConfig;它不读取注册 Dataset、不枚举本地 Dataset、不验证过滤器命中,也不下载 Task 或构建镜像。即使把 -i hello-world 拼错,配置打印仍可能以 0 退出。9 标签内旧式 hello-world@1.0 条目把 Git commit 写为 HEAD,所以本章不用它做可复现的完整评测,而是运行已经由 Git 标签固定的本地 Task。10

本地 Dataset 的过滤发生在目录中有效 Task 被识别之后。-i hello-world 是包含过滤器,-l 1 是过滤后的数量上限;它们不是下载命令,也不会把不合法子目录变成 Task。若过滤器拼错,真正进入 Dataset 解析的运行阶段应报告没有匹配项,而 --print-config 本身不会发现。第一次接触陌生 Dataset 时,先用 --print-config 审查配置意图,再把 -n 保持为 1,并限制 Task 数;前者减少参数错误,后两者控制并发、下载范围与潜在模型费用。

先读最小 Task,再运行 Oracle

examples/tasks/hello-world 的任务要求在 /app 工作目录创建 hello.txt;镜像来自 ubuntu:24.04,Oracle 的 solve.sh 写入 Hello, world!,Verifier 的测试检查文件存在且内容相等,最后把 1 或 0 写到 /logs/verifier/reward.txt。测试脚本还会执行 apt-get、下载 uv 并取得固定 pytest 依赖,因此完整 Trial 即使不调用模型,也仍需要容器网络。11

Oracle 不是一个“知道正确答案的模型”。v0.18.0 的 OracleAgent 不需要模型名,setup() 为空;运行时把 Task 的 solution/ 上传到环境,赋予脚本执行权限,执行并保存 oracle.txt,随后仍由正常 Verifier 评分。12 它回答的是“参考 Solution 能否在这个环境中通过这个 Verifier”,不能证明真实 Agent 能理解任务,更不能证明任务没有答案泄漏或评分漏洞。

下面从 ~/harbor-lab/harbor-v0.18.0 运行。前置条件是 Harbor 0.18.0、可用 Docker daemon、支持 up --wait 的 Compose V2、足够的镜像空间,以及访问 Ubuntu 包仓库和 Astral/PyPI 的网络。预期创建一个 Trial,最终终端汇总 Reward 为 1,并把结果写入 ~/harbor-lab/jobs/first-oracle/result.json。若命令立即报告 Docker 未安装/daemon 未运行,说明还没进入 Trial;若 preflight 通过后才报告 docker compose 错误或已生成 Trial 后失败,则查看环境构建、oracle.txt、Verifier 的 test-stdout.txt(合并 stdout/stderr)和 Reward 文件。只有 Job 无异常且 Reward 为 1 才验收。

cd ~/harbor-lab/harbor-v0.18.0
harbor run \
-p examples/tasks/hello-world \
-a oracle \
-n 1 \
--job-name first-oracle \
--jobs-dir ~/harbor-lab/jobs

这条路径没有模型 API 调用,因此没有模型 token 费用;仍会消耗本机 CPU、内存、磁盘和下载流量。不要把“无模型费用”简写为“零成本”。官方 v0.18.0 Task 教程也把 harbor run -p <task> -a oracle 作为 Solution 冒烟路径。13

不靠终端颜色验收 Job

完整运行后,目录应近似如下。具体 Trial 子目录名由 Harbor 生成,不要在脚本中硬编码:

~/harbor-lab/jobs/first-oracle/
├── config.json
├── lock.json
├── job.log
├── result.json
└── <trial-name>/
├── config.json
├── lock.json
├── result.json
├── trial.log
├── agent/
│ └── oracle.txt
├── artifacts/
└── verifier/
├── ctrf.json
├── reward.txt
└── test-stdout.txt

Job 和 Trial 都写 config.jsonresult.json;Trial 还把 Agent、Verifier 与 Artifact 分目录保存,artifacts/ 在没有采集内容时可能为空。默认 Verifier 把测试的 stdout 与 stderr 合并写入 test-stdout.txtTrialPaths 虽定义了 test-stderr.txt 路径,默认执行链并不生成该文件。14 Reward 属于 Trial 的 verifier_result.rewards,Job 的统计只是聚合视图。15

四类文件回答不同问题。config.json 回答“请求运行什么”,lock.json 回答“运行时解析到了什么输入”,trial.log 和阶段目录回答“执行时发生了什么”,result.json 回答“Harbor 最终结构化记录了什么”。不要只保留终端截图:Rich 表格适合人眼浏览,却不适合作为后续脚本的唯一输入。也不要只看 Job 汇总;若一个 Job 有多个 Trial,Job 级完成数不能告诉你具体哪个 Task 得 0、哪个 Trial 抛异常。

判断首次闭环时,至少核对四个条件:Job 只计划了一个 Trial;完成数为 1;错误数为 0;该 Trial 的主 Reward 为 1。若完成数为 1 但错误数也是 1,说明失败被正常持久化,不代表闭环成功。若错误数为 0 但 Reward 缺失,则需要检查 Verifier 是否被禁用、测试脚本是否产生评分文件,不能把缺失值补成 0。

下面可在任意目录运行。前置条件是 first-oracle 已完整结束且系统有 python3;它只解析 JSON,不调用 Harbor。预期打印任务名和 {'reward': 1}。文件不存在说明 Job 没有进入持久化阶段;断言失败则按异常与 Verifier 日志继续排查。三项断言都成立才验收。

python3 - <<'PY'
import json
from pathlib import Path

path = Path.home() / "harbor-lab/jobs/first-oracle/result.json"
job = json.loads(path.read_text())
assert job["stats"]["n_completed_trials"] == 1
assert job["stats"]["n_errored_trials"] == 0
trial = job["trial_results"][0]
assert trial["exception_info"] is None
assert trial["verifier_result"]["rewards"]["reward"] == 1
print(trial["task_name"], trial["verifier_result"]["rewards"])
PY

3.5 用 Viewer 检查证据

Viewer 接收一个包含 Job 子目录或 Task 定义的文件夹;默认自动识别,也可用 --jobs/--tasks 强制模式。v0.18.0 默认绑定 127.0.0.1,在 8080-8089 中找可用端口,并打印最终 URL。发布 wheel 内含构建后的静态 Viewer,不需要 Bun;从源码运行时若静态资源缺失,默认生产模式会尝试用 Bun 构建,构建失败则退化为 API-only,--dev 模式也明确要求 Bun。16

下面可在任意目录运行。前置条件是 ~/harbor-lab/jobs 下至少有一个带 config.json 的 Job。预期看到 Starting Harbor Viewer 和本地 URL;目录不存在或端口范围全被占用时命令会退出。未强制模式时,没有可识别子目录也会退出;本例使用 --jobs 跳过自动检测,所以空目录仍可能启动服务,但没有 Job 可供验收。打开 first-oracle 后,确认 Trial 无异常、Reward 为 1,并查看 oracle.txt 与合并后的 Verifier 输出;Oracle 通常没有真实 Agent 的多轮 trajectory,不要把缺少 trajectory 误判为 Viewer 损坏。

harbor view ~/harbor-lab/jobs --jobs

Viewer 是本地 HTTP 服务,终端保持占用是正常状态,按 Ctrl-C 停止。本章隔离安装的 v0.18.0 发布包已实际用 --tasks --port 18081 启动,根页面与 /docs 均返回 HTTP 200;这验证的是 Viewer 服务,不代替 Job 内容验收。6

3.6 换成真实 Agent:凭据与成本先行

Oracle 通过后,才值得把变量从“环境/Verifier 是否连通”切换到“Agent 是否能完成任务”。本章采用 v0.18.0 教程中出现的 terminus-2 与 Anthropic 模型写法;Terminus-2 要求提供 model_name,并通过 LLM 调用进行多轮终端操作。17

不要把 API Key 写进 Markdown、Git 仓库、Task、命令行字面量或截图。本章把凭据文件放在源码目录之外。下面可在任意目录运行;前置条件是你已从 Provider 安全取得 Key。预期创建仅当前用户可读的文件并由编辑器打开;内容格式为 ANTHROPIC_API_KEY=<YOUR_KEY>,占位符必须替换但不得提交。失败多为目录权限或编辑器配置问题。用 ls -l 确认权限为 -rw------- 才验收。

mkdir -p ~/.config/harbor
chmod 700 ~/.config/harbor
touch ~/.config/harbor/credentials.env
chmod 600 ~/.config/harbor/credentials.env
${EDITOR:-vi} ~/.config/harbor/credentials.env
ls -l ~/.config/harbor/credentials.env

Harbor v0.18.0 的 --env-file 会在解析 Job 前把 dotenv 内容加载到 Harbor 宿主进程;若文件不存在会立即退出。任务自身通过 ${VAR} 请求宿主变量时,CLI 会扫描 [environment.env][verifier.env],Oracle 还会扫描 [solution.env];未由命令覆盖的必需变量缺失时会失败。非 --yes 模式通常会显示变量与注入阶段并请求确认,但显式从 --env-file 读取到的键会被排除在确认列表之外。18

本例的 hello-world 没有声明这些 Task env,Terminus-2 则由宿主进程中的 LiteLLM 读取 ANTHROPIC_API_KEY,所以真实 Agent 命令不会为该 Key 弹出确认。--yes 与否都不能验证 Key 是否有效;安全边界来自手工检查凭据文件路径与权限、Provider/模型和本次 Job 范围,而不是等待一个不会出现的提示。保留非 --yes 模式仍有价值,因为陌生 Task 可能声明其他宿主变量。18

先在 ~/harbor-lab/harbor-v0.18.0 做免费配置检查。前置条件只有凭据文件存在;--print-config 会在真正运行前退出,不连接模型、不启动 Docker,也不验证 Key、模型名或 Provider 网络。预期 JSON 中出现 terminus-2、模型、max_turns、Task 与输出路径。若配置构造失败,先修正命令,不要进入付费运行。JSON 正确且 harbor --version 仍为 0.18.0,只能验收配置意图,不能验收认证或模型可用性。

cd ~/harbor-lab/harbor-v0.18.0
harbor run \
-p examples/tasks/hello-world \
-a terminus-2 \
-m anthropic/claude-haiku-4-5 \
--ak max_turns=8 \
--env-file ~/.config/harbor/credentials.env \
-k 1 \
-n 1 \
--job-name first-real-agent \
--jobs-dir ~/harbor-lab/jobs \
--print-config

删除最后的 --print-config 才会真正运行。运行目录与参数保持不变;额外前置条件是 Docker/Compose、Provider 网络、Key 权限与付费额度可用。-k 1 明确只尝试一次,-n 1 只限制并发,max_turns=8 则限制 Terminus-2 的主交互轮次;它们降低首次冒烟的费用暴露,但不构成固定美元上限,过小的轮次限制也可能让 Agent 未完成任务。预期 Job 完成并生成真实 Agent 日志/trajectory 与 Verifier Reward,但 Reward 不保证为 1。认证错误、限流、模型名不可用、Agent 超时和任务失败应分别保留原始日志。验收标准是 result.json 存在、Trial 基础设施无异常、Verifier 产生 Reward;“Agent 得 0 分”是有效评测结果,不等于安装失败。

cd ~/harbor-lab/harbor-v0.18.0
harbor run \
-p examples/tasks/hello-world \
-a terminus-2 \
-m anthropic/claude-haiku-4-5 \
--ak max_turns=8 \
--env-file ~/.config/harbor/credentials.env \
-k 1 \
-n 1 \
--job-name first-real-agent \
--jobs-dir ~/harbor-lab/jobs

警告:这条命令会产生真实模型费用,Agent 可能发起多轮调用。先用 Oracle 隔离环境问题,再用 --print-config 审查配置意图;不要为了“确认能跑”在未知 Dataset 上提高 -k-n、Task 数或 max_turns。运行前按 Provider 单价和允许的调用/时间写下预算与停止条件。本章没有替读者执行这条付费命令。

运行结束后再次执行 harbor view ~/harbor-lab/jobs --jobs,对比 first-oraclefirst-real-agent。先检查异常和阶段时间,再看 Reward,最后用 trajectory 解释真实 Agent 的动作。一次成功或失败都只是一个 Trial,不能据此宣称模型能力稳定。

3.7 失败模式与排查顺序

失败一:安装选到了过新的 Python

症状是 uv tool install 在构建传递依赖时出现 PyO3/Python 上限错误,而 requires-python 明明写着 >=3.12。先运行 uv python find 3.13,再用 uv tool install --python 3.13 "harbor==0.18.0"。不要通过修改 Harbor 源码或随意放宽依赖来掩盖工具解释器选择。修复后以 harbor --version 验收。

失败二:Docker CLI 与 daemon 被混为一谈

Docker is not installed or not on PATH 对应 shutil.which("docker") 失败;Docker daemon is not running 对应 docker info 失败或超时。前者检查安装和 PATH,后者检查 Docker Desktop/Engine、context、权限与服务状态。不要在这两种情况下调试 solution/solve.sh,它还没有执行。若这两项 preflight 已通过,但随后出现 docker compose 未知或 --wait 不支持,则检查 Compose V2 plugin;此时 Job/Trial 可能已经创建,应保留环境构建日志。

失败三:Oracle 运行了,但 Reward 不是 1

按证据产生顺序查看:

  1. Job result.jsonn_errored_trials 与 Trial exception_info
  2. Trial trial.log,判断环境构建、Agent、Verifier 哪个阶段停止;
  3. agent/oracle.txt,确认 Solution 的命令输出;
  4. verifier/test-stdout.txt,默认 Verifier 已把 stdout 与 stderr 合并到这里;
  5. verifier/reward.txt,区分有效 0 分、缺失文件和不可解析内容。

hello-world 而言,容器网络不可用会影响 apt-get、uv 或 pytest 下载。这是 Verifier 依赖获取失败,不应描述成“Oracle 不会创建文件”。

失败四:真实 Agent 的认证失败

先确认凭据文件存在且权限正确,再确认变量名是 ANTHROPIC_API_KEY、文件没有多余引号或不可见字符、Provider 账户允许所选模型。不要把 Key 打印到终端或粘贴进报告。若 Oracle 已通过而真实 Agent 在第一次模型调用失败,优先查看 Agent/Provider 错误;若模型调用成功但 Reward 为 0,则进入任务行为诊断,不要重装 Harbor。

可以把全部排查压缩成一个决策顺序:先运行 harbor --version 排除错误入口,再运行 docker infodocker compose versiondocker compose up --help 排除容器基础设施;然后用 --print-config 审查配置意图,但不要把它当成路径、Dataset、凭据或模型可用性验证;接着看 Job 是否创建、Trial 是否持久化;最后才进入 Agent 与 Verifier 日志。每一步都应有一个能保存的输出。连续跳过这些检查,最常见的结果是反复重装 Python,却没有启动 Docker,或反复更换模型,却没有发现 Verifier 根本没写 Reward。

3.8 本章小结

  • Harbor v0.18.0 要求 Python 3.12 或更高;本章显式选择 3.13,并用 ==0.18.0 固定工具包。
  • harbor --version 只验收 CLI;docker info 验收 daemon,Compose V2 与 --wait 还需独立检查;Reward 为 1 才验收本章 Oracle Job。
  • -d 表达注册 Dataset,-p 表达本地 Task 或 Dataset;--print-config 只显示配置意图,不解析 Dataset、凭据或模型可用性。
  • Oracle 执行 Task 的参考 Solution,不调用模型;它能验证一条可解路径,却不能证明真实 Agent 能解或 Benchmark 质量充分。
  • Job 的 result.json 给出汇总,Trial 目录保留 Agent、Verifier、Reward 与异常证据;排障应按产生顺序阅读。
  • Viewer 用于浏览证据,不改变结果;真实 Agent 必须在凭据、费用和非确定性边界明确后运行。

3.9 练习

  1. 在不运行容器的情况下,分别对注册 hello-world@1.0 与本地 examples/tasks 执行 --print-config,解释输出中的 datasets 为什么不同。
  2. 暂停 Docker daemon 后运行 Oracle 命令,记录 preflight 错误;恢复 daemon,再用 docker infodocker compose versiondocker compose up --help 证明前置条件完整。不要把失败 Job 与修复后的 Job 使用同一个 --job-name
  3. 完成 first-oracle,用 Python 读取 Job result.json,打印 Trial 名、Reward 与异常类型;再从对应 Trial 目录找出 reward.txtoracle.txt
  4. -p examples/tasks/hello-world 改成 -p examples/tasks -i hello-world -l 1,比较两个 Job 的 Task 来源字段与输出结构,说明单 Task 和本地 Dataset 入口的差别。
  5. 在不执行付费命令的前提下,为另一个真实 Agent 写出 --print-config 检查、所需凭据、成本上限和验收条件;说明为什么 Reward 为 0 不必然是安装失败。

参考资料

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/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/pyproject.toml#L34-L41,访问于 2026-07-15。

  2. Harbor Framework Team,src/harbor/environments/docker/docker.pytests/unit/test_environment_preflight.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/environments/docker/docker.py#L149-L167https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/tests/unit/test_environment_preflight.py#L237-L259,访问于 2026-07-15。

  3. Harbor Framework Team,src/harbor/environments/docker/docker.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/environments/docker/docker.py#L581-L614https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/environments/docker/docker.py#L840-L882,访问于 2026-07-16。

  4. Astral,Installing uvInstalling Pythonhttps://docs.astral.sh/uv/getting-started/installation/https://docs.astral.sh/uv/guides/install-python/,访问于 2026-07-15。

  5. Astral,Tools: Python versions and tool executableshttps://docs.astral.sh/uv/concepts/tools/#python-versionshttps://docs.astral.sh/uv/concepts/tools/#tool-executables,访问于 2026-07-15。

  6. 本章写作 Agent,第 3 章写作与验证报告的“实际验证环境”“精确 PyPI 工具安装”“Oracle 路径”与“Viewer”,2026-07-15;审校后探针复核于 2026-07-16。 2

  7. Docker,Install Docker EngineInstall Docker Desktop on Macdocker system info 参考,https://docs.docker.com/engine/install/https://docs.docker.com/desktop/setup/install/mac-install/https://docs.docker.com/reference/cli/docker/system/info/,访问于 2026-07-15。

  8. Harbor Framework Team,src/harbor/cli/main.pysrc/harbor/cli/jobs.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/main.py#L38-L105https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L320-L362https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L496-L617,访问于 2026-07-15。

  9. Harbor Framework Team,src/harbor/cli/jobs.pysrc/harbor/models/job/config.pysrc/harbor/job.py 与 Dataset 文档,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L863-L925https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L1389-L1480https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/job/config.py#L117-L184https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L121-L134https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/datasets/index.mdx#L10-L44,访问于 2026-07-16。 2

  10. Harbor Framework Team,registry.json 中的 hello-world@1.0 条目,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/registry.json#L23803-L23815,访问于 2026-07-16。

  11. Harbor Framework Team,examples/tasks/hello-world,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/examples/tasks/hello-world/environment/Dockerfilehttps://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/examples/tasks/hello-world/instruction.mdhttps://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/examples/tasks/hello-world/solution/solve.shhttps://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/examples/tasks/hello-world/tests/test.shhttps://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/examples/tasks/hello-world/tests/test_state.py,访问于 2026-07-15。

  12. Harbor Framework Team,src/harbor/agents/oracle.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/agents/oracle.py#L18-L54https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/agents/oracle.py#L80-L151,访问于 2026-07-15。

  13. Harbor Framework Team,Task Tutorial,Harbor v0.18.0 随附文档,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/tasks/task-tutorial.mdx#L216-L253,访问于 2026-07-15。

  14. Harbor Framework Team,src/harbor/verifier/verifier.pysrc/harbor/utils/scripts.pysrc/harbor/models/trial/paths.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/verifier/verifier.py#L175-L202https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/utils/scripts.py#L122-L160https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/trial/paths.py#L238-L270,访问于 2026-07-16。

  15. Harbor Framework Team,Evalssrc/harbor/models/trial/paths.pysrc/harbor/job.py,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/run-jobs/run-evals.mdx#L58-L98https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/models/trial/paths.py#L177-L270https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L395-L413https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L639-L670https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/job.py#L729-L755,访问于 2026-07-16。

  16. Harbor Framework Team,src/harbor/cli/view.pyEvals,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/view.py#L140-L247https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/view.py#L250-L316https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/run-jobs/run-evals.mdx#L82-L106,访问于 2026-07-15。

  17. Harbor Framework Team,Task TutorialTerminus2,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/tasks/task-tutorial.mdx#L234-L253https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/agents/terminus_2/terminus_2.py#L159-L257https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/agents/terminus_2/terminus_2.py#L281-L302,访问于 2026-07-16。

  18. Harbor Framework Team,src/harbor/cli/jobs.pytests/unit/test_job_confirm_env_access.pyRunning Terminal-Bench,Harbor v0.18.0,https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L71-L174https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L764-L783https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L1121-L1125https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/src/harbor/cli/jobs.py#L1555-L1559https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/tests/unit/test_job_confirm_env_access.py#L63-L87https://github.com/harbor-framework/harbor/blob/527d50deb63a5d279e8c20593c18a2cbc7f61f9e/docs/content/docs/tutorials/running-terminal-bench.mdx#L15-L25,访问于 2026-07-16。 2