返回博客列表

Harbor 深度解析:任何 Agent × 任何沙箱,把评测变成可复现的软件包

2026-10-07T21:00:00+08:00
HarborTerminal-BenchAgent评测沙箱RLATIF开源

Harbor 深度解析:任何 Agent × 任何沙箱,把评测变成可复现的软件包

评测 Agent 最尴尬的不是分数低,而是别人复现不出来。

Harbor 是 Terminal-Bench 团队做的 Agent 评测与优化框架,仓库描述一句话:"Framework for evaluating and improving agents"。它目前的体量是 5,882 stars、1,940 forks、992 个 open issues,Apache-2.0,Python 3.12+,PyPI 包名就叫 harbor,最新版本 0.24.0(2026-10-05)。

它给自己的定位是一句听起来很狂的话:run any agent with any model on any task in any sandbox in parallel——任何 Agent、任何模型、任何任务、任何沙箱,并且并行跑。而更值得关注的是它的出身:README 第一句写着"Harbor is a framework from the creators of Terminal-Bench",并且 Harbor 就是 Terminal-Bench-2.0 的官方 harness。

这篇文章拆它的设计。我的结论先放这里:Harbor 真正的贡献不是"能跑评测",而是把评测任务变成了有格式、有版本、能流通的软件包,并且给 reward 定了一个文件级契约。

本文提纲

  1. 它是什么:四个"任何"和八个核心概念
  2. 快速上手:三条命令跑起来
  3. Task 是一份目录:像软件包一样管理评测
  4. 42 个 Agent 与本地 4 种、云端 20 多种沙箱
  5. ATIF:为什么统一轨迹格式是评测基础设施的关键
  6. 多步任务与独立验证:评测记忆,也保护边界
  7. Rewardkit:把奖励写成 TOML
  8. 从评测到训练,以及规模化:Cookbook 与 Harbor Hub
  9. 边界与选型:什么时候值得用

它是什么:四个"任何"和八个核心概念

先看官方文档给的核心概念表,这张表基本就是它的数据模型:

概念 定义
Task 一个或多个指令 + 沙箱环境 + 验证器,实现为一个目录(Harbor task format)
Dataset 任务的集合,通常对应一个 benchmark(如 Terminal-Bench、SWE-Bench Verified)
Agent 完成任务的程序;内置适配 + 通过 BaseAgent 自定义
Sandbox 运行任务的隔离环境;内置适配 + 通过 BaseEnvironment 自定义
Verifier 评估 Agent 的工作并产出该任务的 reward
Trial 一个 Agent 对一个任务的一次尝试
Job trial 的集合,可组合数据集、Agent、任务与模型,底层并行执行
Trajectory Agent 与用户的完整对话与动作历史,标准格式是 ATIF

关键区分在 trial 与 job:trial 是"一次尝试",job 是"一批尝试"。很多人评测时混着说"跑一次评测",但在 Harbor 里这两级是分开的——因为可复现性要求你必须能定位到具体哪次 trial。

项目事实先摆清楚:

项 值
仓库 harbor-framework/harbor
Stars / Forks / Issues 5,882 / 1,940 / 992
许可 / 语言 Apache-2.0 / Python 3.12+
创建 / 最近提交 2025-08-04 / 2026-10-07(当天仍在提交)
最新版本 v0.24.0(2026-10-05),PyPI 上 75 个稳定版本 + 每日 dev 版
发布节奏 v0.20.0(7/18)→ v0.21.0(8/10)→ v0.22.0(8/22)→ v0.23.0(9/12)→ v0.24.0(10/5)
学术引用 Zenodo DOI 10.5281/zenodo.20953922

注意 992 个 open issues 这个数字——它既是"社区活跃"的证据,也是"还在快速演进"的提醒,后面选型部分会再提。

快速上手:三条命令跑起来

安装只要一行(Python 3.12+):

uv tool install harbor
# 或者
pip install harbor

官方 quick start 的第一个 job 是跑内置的 hello-world 任务:

OPENAI_API_KEY="" \
harbor run -t hello-world/hello-world \
  -a codex -m openai/gpt-5.6-luna

默认沙箱是 Docker,所以本机要有 Docker;想用云沙箱(Modal、Daytona 等)需要装对应的 extra,比如 uv tool install "harbor[modal]",然后加 --env/-e 参数。

更有说服力的是 README 里的 Terminal-Bench-2.0 例子——这就是 Harbor 作为官方 harness 的实际用法:

# 本地跑(Docker)
export ANTHROPIC_API_KEY=
harbor run --dataset terminal-bench@2.0 \
   --agent claude-code \
   --model anthropic/claude-opus-5-5 \
   --n-concurrent 4

# 同样的评测,换到云端沙箱跑 100 并发
export DAYTONA_API_KEY=
harbor run --dataset terminal-bench@2.0 \
   --agent claude-code \
   --model anthropic/claude-opus-5-5 \
   --n-concurrent 100 \
   --env daytona

同一份数据集、同一个 Agent、同一个模型,只改 --env 和并发数就从本地扩到云上——这大概是 Harbor 最想让人看到的能力。另外 harbor datasets list 可以列出所有支持的第三方 benchmark(如 SWE-Bench、Aider Polyglot)。

跑完看结果、分享结果:

harbor view ./jobs          # 本地 Web 查看器
harbor upload "./jobs/"   # 上传到 Harbor Hub 分享

官方在 quick start 里特意指向 Terminal-Bench 网站 作为"公开结果如何带来完整可审计性"的范例。这句话是理解 Harbor 的钥匙:它的目标不是给你一个跑分脚本,而是让评测结果可以被第三方审计。

Task 是一份目录:像软件包一样管理评测

这是全篇最重要的部分。一个 Harbor task 就是一个目录:

my-task/
├── instruction.md      # 给 Agent 的指令
├── task.toml           # 元数据与配置
├── environment/        # 环境定义
│   ├── Dockerfile      # 或 docker-compose.yaml / Apptainer.def
│   └── ...
├── solution/
│   └── solve.sh        # 参考解
└── tests/
    └── test.sh         # 验证器入口

环境定义可以是任意 spec,只要 task 的消费者(比如 Harbor)支持:常见的是 Dockerfile、多容器的 docker-compose.yaml,以及给超算用的 Apptainer.def。

reward 是一个文件——这是它的核心契约。 验证器脚本 tests/test.sh 在 Agent 跑完后被上传到 /tests/,在任务工作目录里执行,必须写出:

文件 格式
/logs/verifier/reward.json 带标签的数值指标键值对(多维度奖励)
/logs/verifier/reward.txt 单个数字,通常是 1 或 0

两者同时存在时,Harbor 优先读 reward.json。一个最小可用的验证器长这样:

#!/bin/bash
set -euo pipefail

uvx pytest /tests/test_outputs.py

if [ $? -eq 0 ]; then
  echo 1 > /logs/verifier/reward.txt
else
  echo 0 > /logs/verifier/reward.txt
fi

官方建议脚本里用绝对路径,避免 cwd 出乎意料——这是被坑过的团队才会写进文档的建议。

但这个格式设计里真正聪明的是另一句话:Harbor task 对 Harbor 框架没有任何依赖。 它是独立、隔离、可复现的代码单元,可以插进任何支持该格式的框架。官方打了个比方:把 task 当成软件包来对待——自包含、有版本、被维护、随时间演进。

这句话的份量值得展开。Agent 评测的现状是:每个团队的评测逻辑散在脚本、notebook 和 CI 里,换个模型就得重写一遍,分数之间不可比。把 task 变成"目录 + 契约"之后,评测就变成了可以 PR、可以 review、可以打标签发布的资产——这也是后面 Harbor Hub 能成立的前提。

42 个 Agent 与本地 4 种、云端 20 多种沙箱

"Harbor 支持很多 Agent"这件事,光看数量没意义,要看它抽象了什么。它内置了 42 个 Agent 适配,覆盖了当前主流的编码 Agent 与框架:

aider, claude-code, cline-cli, codex, copilot-cli, cursor-cli, devin,
gemini-cli, goose, hermes, junie, kimi-cli, kimi-code, langgraph,
mini-swe-agent, muse-code, openclaw, opencode, openhands, openhands-sdk,
qwen-coder, strands, swe-agent, terminus-2, trae-agent, vibe

这份名单里有一批是我们这几个月写过的项目:claude-code、codex、openhands、strands、hermes、openclaw、muse-code——也就是说,昨天日报里那些"Agent 运行时"和"编码 Agent",在 Harbor 这里统一变成了可横向对比的被测对象。

它还进一步给 Agent 打上了能力标签,这比单纯的适配列表更有信息量:

能力 含义 支持的 Agent 数
ATIF 能产出标准 ATIF 轨迹 33 个(含 claude-code、codex、gemini-cli、openhands、swe-agent 等)
Resume 能在任务步骤之间续接原生会话 15 个(aider、claude-code、codex、copilot-cli、gemini-cli、goose、opencode、qwen-coder 等)

Resume 这一列尤其值得看:它决定了这个 Agent 能不能做"多步任务"评测——因为多步任务的本质就是"让同一个 Agent 带着上一阶段的记忆继续干"。

除了内置的 42 个,还有两条扩展路径:从 ACP Registry(Agent Client Protocol 注册表)安装并运行,或者实现 BaseAgent 接入自己的 Agent。

沙箱侧的选择更多,分成本地与远程两类(官方强调这只是文档分组,不是 API 里的不同类型):

本地运行时:docker(默认)、podman、apple-container、singularity

远程沙箱:ack(阿里云 K8s,走 kubeconfig)、beam、blaxel、cua-cloud、
cwsandbox(CoreWeave)、daytona、e2b、ec2、gke、hf-sandbox、hyperbrowser、
islo、langsmith、modal、novita、opensandbox、openshift(用 oc CLI)、runloop、
skypilot(早期访问)、tensorlake、use-computer、vercel、runta、prime、mosaic、smol machines …

从"本机 Docker 跑 4 并发"到"云上跑 100 并发",中间要改的只有 --env——这就是它把沙箱抽象成 BaseEnvironment 的价值。

还有个更前沿的东西值得单独提:ASP(Agent Sandbox Protocol),目前是 RFC 草案(PR #3023,欢迎评论)。它的口号很直白——"Decouple the brain from the hands!"(把大脑和手解耦):

  • 目标是标准化"Agent harness(大脑:循环、LLM 调用、凭证)"与"工具执行沙箱(手:文件系统、shell)"之间的接口,让任何 harness 驱动任何沙箱,且 harness 里不出现任何厂商 SDK;
  • 传输层首选 SSH,理由是它已经提供了命令执行、文件传输和认证,而每个沙箱都能暴露这些;
  • 实现 ASP 的 Agent 意识不到自己在操作远程机器——因为它所有工具都在沙箱里执行,沙箱是它能观测到的唯一环境;
  • 实现成本被压到两件事:检测 .asp.json,以及把工具的原始 I/O(read/write/exec)从本地路由到配置的传输层。它把 Agent 工具拆成"面向模型的政策层(schema、截断、分页)"和"做原始 I/O 的机制层",ASP 只替换机制层,政策层不变。

如果你在关注"MCP 管工具、A2A 管 Agent 之间"这条线,ASP 补的是第三块拼图:harness 与沙箱之间。

ATIF:为什么统一轨迹格式是评测基础设施的关键

Trajectory(轨迹)是调试 Agent 最有用的东西,但实践中的问题是:每个 Agent 的输出格式都不一样。

Harbor 的解法是定义一个通用格式 ATIF(Agent Trajectory Interchange Format),把 Agent 的完整交互历史记成 JSON:消息、推理、工具调用、观测结果和指标。官方给出的理由是它最本质的那一条:

没有共享格式,每个查看器、数据集和训练管线都要写一个 Agent 专属的解析器。

这就是典型的 N×M 问题——N 个 Agent × M 个消费方。ATIF 把它压成 N + M。

在 Harbor 里,ATIF 轨迹通常命名为 trajectory.json:声明了 capabilities.atif = true 的 Agent 会把它写进 agent 日志目录,下载的 trial 结果里路径为 agent/trajectory.json。它有两个用途:

  1. 渲染轨迹:结果查看器读 agent/trajectory.json,在 Trajectory 标签页里展示每一步;
  2. 加载轨迹:支持的 Agent 可以用一条 ATIF 轨迹给新会话做种子。

官方特别提醒了一句容易被忽略的话:"产出 ATIF"和"加载 ATIF"是两种独立能力——一个 Agent 可能能写 trajectory.json,但并不支持把轨迹加载回去。自定义 Agent 也只有在真的能写出合法 self.logs_dir / "trajectory.json" 时才该声明 AgentCapabilities(atif=True)。

当前格式版本是 ATIF-v1.7,字段设计得很克制:

字段 用途
agent Agent 名称、版本、模型,以及可选的工具定义
steps 按顺序排列的 system、user、agent 交互
session_id 同一次运行内多条轨迹共享的标识(可选)
trajectory_id 文档标识;嵌入的子 Agent 轨迹必需
final_metrics 聚合的 token、成本、步数指标(可选)
subagent_trajectories 内嵌的 ATIF 子轨迹(可选)
extra 自定义根级元数据

subagent_trajectories 和 trajectory_id 这两个字段透露出他们的实际需求:当主 Agent 派生子 Agent 时,轨迹不能断。对做多 Agent 系统的团队来说,这一条比格式本身更重要——完整规范在仓库的 rfcs/0001-trajectory-format.md。

多步任务与独立验证:评测记忆,也保护边界

多步任务(multi-step) 是 Harbor task 格式的第一次重大扩展。它的目的官方说得很明确:把验证穿插到 Agent 运行过程中,衡量 Agent 能否带着上一次会话的成果继续工作——特别适合长周期任务里的早停条件,以及衡量记忆与持续学习能力。

格式上和普通 task 的差别在 steps/ 目录:

task.toml
environment/
tests/
└── helpers.py          # 可选,共享评分工具
steps/
├── step-1/
│   ├── instruction.md  # 必需
│   ├── tests/          # 可选
│   ├── solution/       # 可选
│   └── workdir/
│       └── setup.sh    # 可选
└── step-2/
    └── ...

在根 task.toml 里按执行顺序声明步骤,并且可以配置多步奖励的聚合方式:

multi_step_reward_strategy = "mean"

[agent]
timeout_sec = 600

每个步骤的 test 脚本可以用 tests/helpers.py 里的共享工具;也可以写一个基准 tests/test.sh 作为没有独立脚本的步骤的兜底,步骤自己的 test.sh 会覆盖它。

独立验证环境(separate verifier) 是另一个我特别欣赏的设计。默认情况下验证器和 Agent 跑在同一个容器里,但你可以通过在 task.toml 里设置 environment_mode = "separate"(或直接给 [verifier.environment] 段)让它换到独立容器。收益有三个,官方列得很清楚:

  1. 隔离评分,改善 Agent 与验证器之间的安全边界;
  2. 可以把依赖预装进验证器镜像并提前构建——减少安装抖动、加速验证阶段;
  3. 让 trial 的"重打分"(regrade)成为可能。

第 2 条是被低估的:任何跑过大规模评测的人都知道,最脆弱的环节往往是验证阶段临时 pip install 失败,而不是模型答错。

而 regrade 直接解决了一种很常见的浪费——验证器改了一版,但不想重跑 Agent:

harbor job regrade "jobs/" -p path/to/updated-task -e modal
harbor trial regrade "jobs//" -p path/to/updated-task -e modal

-p 接受一个 task 目录或一批 task 目录,Harbor 按任务名把新旧对应起来;也支持直接用 Harbor Hub 上的 job 或 trial UUID。官方建议只在"验证器变了、且任务用了独立验证环境"时用它。把"Agent 跑一次的成本"和"重新评分的成本"解耦,这是评测系统走向工程化的标志。

Rewardkit:把奖励写成 TOML

tests/test.sh 里写 bash 判断只适合"对/错"这种二元奖励。要评"回答质量""代码可维护性"这类多维标准,Harbor 提供 Rewardkit:

uv tool install harbor-rewardkit
# 需要读图片或 PDF/DOCX/PPTX/XLSX 等文档时
uv tool install harbor-rewardkit[all]

它针对 Agent 的工作区和轨迹定义验证器,并行运行各项 criteria,把分数写成 JSON。criteria 分两类:

  • 程序化(Programmatic):Python 函数,检查文件、执行命令、评估输出;
  • 判官(Judge-based):用可复用的 TOML 配置 LLM 或 Agent 判官。

关键在于它的落地方式极简。在 Harbor 里,把 criteria 文件放进 tests/:

tests/
├── files.py        # 程序化 criteria
├── quality.toml    # 判官配置
└── test.sh

然后 test.sh 只要一行:

#!/bin/bash
uvx --from 'harbor-rewardkit==0.2.*' rewardkit /tests

Rewardkit 会自动发现 /tests 里的 criteria,对 /app 的工作区执行,把结果写进 /logs/verifier/reward.json——正好接上前面那个 reward 文件契约。

两个设计细节值得记:它是自包含的 Python 包(配 Harbor 最强,但单独用也没问题),以及 judge 配置用 TOML 复用——这意味着"什么算好代码"的标准可以版本化、跨任务共享,而不是散落在各个脚本的 prompt 字符串里。

最新的 v0.24.0 还给 Rewardkit 加了 JEV judges、rubric criteria、判官重复采样,以及 Agent/LLM 判官的成本估算。最后一项尤其务实:用 LLM 当判官是要花钱的,评测系统应该告诉你花了多少。

从评测到训练,以及规模化:Cookbook 与 Harbor Hub

Cookbook 是上手 Harbor 最短的路径(harbor-framework/harbor-cookbook),9 个可直接运行的 recipe:

Recipe 做什么
simple-task 最小单容器任务
multi-container Docker Compose 任务,Agent 与本地 REST API 交互
mcp-tools 通过本地 FastMCP server 给 Agent 自定义工具
skills 在 Harbor 任务里打包 skills
multi-reward 多个独立验证器各自给分
simulated-user Agent 通过与模拟用户对话来发现需求
computer-use-ubuntu / computer-use-windows Ubuntu 虚拟桌面与远程 Windows 桌面(Daytona)的计算机使用参考实现
dns-blacklisting 网络层主机名黑名单,支持精确、通配与正则规则

官方给的使用建议也很实在:把最接近你需求的那个 recipe 丢给你的编码 Agent,让它照着改。

而"从评测到训练"才是 Harbor 真正的野心。 因为 task 会产出 reward,同一批数据集既是评测集,也是训练环境。Cookbook 里有两个例子:一个把 Harbor 和 GEPA 结合,在 MedAgentBench 上优化一个 Agent harness;另一个是 Thinking Machines 贡献的集成,通过 Tinker SDK 把 Harbor 任务当作 RL 环境使用。README 里也把 "Generate rollouts for RL optimization" 直接列为四大用途之一。

再往上是 Harbor Hub——把评测变成可协作的基础设施:

能力 说明
上传/分享 harbor upload "<job-path>" 上传 job 结果(含 trial 与轨迹);目录需含 config.json 与 result.json;--upload 可在运行中边跑边传,中断后重跑会跳过已上传的
可见性 新上传默认私有,--public/--private 控制;--org 指定归属组织,--share 分享给其他组织
排行榜 定义列与排名规则、自己算好分数加行、可选把每行链接到背后的 trial;Hub 刻意不根据链接的 trial 自动算分,以保留构建排行榜的灵活性
托管作业 --launch 在云上编排 trial:强制各家 provider 的并发上限、遇到级联失败(如额度用尽)暂停、遇限流退避,并可用 UI/CLI 调试、重试、分享与监控
注册表 自助发布 task 与 dataset,task 是原子单位,dataset 是特定版本下的 task 集合,可私有可公开

还有几个"用起来舒服"的功能,说明团队自己天天在用这套东西:

  • --stream 实时流:运行中就能跟踪轨迹、浏览沙箱文件(v0.24.0 支持 Claude Code 与 Codex,沙箱覆盖 Docker、Daytona、Modal、Tensorlake、Smol Machines);
  • harbor run --diff:和之前的 job 对比,并预览哪些 trial 可以复用、重打分或需要重跑——直接省掉重复的 Agent 调用;
  • Handoff:把完成的 trial 在本地 Agent CLI 里恢复,直接"面试"这个 Agent,问它为什么这么做、为什么失败。官方说这比看长轨迹更方便——这个判断我信,毕竟读 500 步轨迹不如直接问它一句;
  • Simulated user:通过多轮模拟用户对话来评测 Agent,v0.24.0 起 Codex 与 OpenCode 可以作为主 Agent 参与。

边界与选型:什么时候值得用

值得用的场景:

你需要可复现、可审计、能横向对比的评测,而不只是一次性跑分——这是 Harbor 的主场。你要在多个 Agent × 多个模型之间做矩阵实验(42 个内置适配就是为这个准备的)。你要把评测扩到几十上百并发(换 --env 就行)。你要做长周期/多步任务评测记忆与持续学习。或者你打算用同一批任务的 reward 去做 RL 与 harness 优化——这是它最独特的地方。

不必用的场景:

只是想对比两个模型在同一个 prompt 上的回答——在线 playground 或十几行脚本更快,Harbor 的 task 格式对你是纯开销。没有沙箱预算的团队也要想清楚:一个 trial 就是一个沙箱,云端沙箱按量计费,100 并发跑一轮 Terminal-Bench 不是小数目(这也是为什么 --diff 和 regrade 这种"少跑一次"的功能有意义)。另外 992 个 open issues 和 v0.24.0 的两条破坏性变更(RewardKit 按 Python 文件分组 criteria、独立验证器改为优先用自己的镜像)都说明它迭代很快,用之前先锁版本。

最后回到开头那句话。Agent 评测现在最缺的不是更多 benchmark,而是让分数能被信任的工程规范:任务要自包含、奖励要有文件契约、轨迹要有统一格式、验证要能独立复跑、结果要能被第三方审计。Harbor 把这些当成框架要解决的问题,而不指望使用者各自发明——这也是它值得读一遍文档的理由。

参考链接

你在做 Agent 评测时最头疼的是什么——是结果不可复现,还是跑一轮太贵?评论区聊聊你的做法,觉得这份拆解有用就点个赞。


作者: itech001 来源: 公众号:AI人工智能时代(the-ai-era) 网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top

本文首发于 AI人工智能时代,转载请注明出处。

分享给朋友