用强化学习训练代码模型正成为共识。但真正做过的人都知道——模型是最容易的部分,围绕模型的一切才是时间黑洞。
你需要真实环境:正确的工具链、系统库、固定依赖、GPU 驱动、rollout 间重置状态的能力。你需要选个 coding harness:Claude Code?Aider?OpenHands?还是自己搭?你需要初始化点:从哪个 commit 开始、起始 prompt 是什么、Agent 先看哪些文件?你还需要一个真正可信的奖励:跑测试、给 diff 打分、上 judge,或以上全部。
每个决定都是个兔子洞。而大多数新 benchmark 或 RL 方案都在从零重建这一切。这篇文章讲为什么这不可持续,以及答案的形状为什么越来越像 Harbor。
共识:代码是 RL 的最佳领域
过去 18 个月代码 LLM 的模式很明显:别再假装预训练够了,用能编译运行的信号做训练。每个前沿实验室都在用某种可验证奖励的 RL(RLVR)做后训练,而代码是最干净的领域——pytest 不会撒谎。
各家的动作:
- Meta 用基于规则的奖励(diff 与 ground-truth PR patch 的相似度)在数百万合并 pull request 上训练了 Llama3-SWE-RL-70B,SWE-bench Verified 41%,当时 sub-100B 模型最佳
- OpenAI Codex 是 o3 的专门版本,"迭代运行测试直到通过"。o3 在 SWE-bench Verified 上从 o1 的 48.9% 跳到 71.7%
- DeepSeek-R1 证明纯 RL + 可验证奖励就能出推理能力,无需 SFT warm-up。用 GRPO,显式使用 LeetCode 的编译器反馈作为信号
- Moonshot Kimi K2 引入"类 Gym 可扩展框架"在多样 coding 场景上扩展 RL,SWE-bench Verified 65.8%,仅用一个 bash/editor harness
- Qwen3-Coder-Next 直言:"大规模合成可验证编码任务 + 可执行环境"是核心训练突破,不是模型架构
- Prime Intellect 的 100B+ MoE 在数千个社区贡献环境中大规模 RL 训练
- Anthropic Claude 4.x 以代码能力著称, reportedly 正在加大 RL 环境投入
共识已形成:代码 uniquely 适合 RL,因为奖励可验证。运行代码,检查结果。不需要奖励模型,不需要人工标注偏好,不会漂移。
没人告诉你的陷阱
一旦你承诺用可验证奖励做 RL,训练质量完全取决于你能启动多少环境。而环境很难。
Hugging Face 说得直白:
当前环境生态系统碎片化。实现往往与特定训练栈紧耦合,难以适配、复用或共享……没有强大的开源替代方案,开源模型可能落后,用户只能依赖能力由不可访问工具塑造的闭源模型。
Prime Intellect 推出 1000+ 开源 RL 环境时也持同样观点:扩展 RL 的路径不是更大的模型,而是更多、更便宜、更多样的环境。
MiniMax 的 Forge 框架每天吞吐数百万样本跑 RL 训练。这不是模型问题,是基础设施问题。
每个编码环境都需要三样东西:
- 冻结状态或快照 — 特定 commit、代码库、数据集,或任务可以开始的任何固定位置,依赖已固定
- 运行方式 — 带正确 Python/Node/Go 工具链、系统库、所需 GPU 驱动的 Docker 镜像
- 评分方式 — 测试、diff 对比、judge 模型、自定义验证器
每个 benchmark 团队都在从零重建这套栈。SWE-bench 有自己的 harness,R2E 有自己的,Magicoder 有自己的。结果就是 HF 所说的"碎片化":Agent 无法在 benchmark 间迁移,数据集无法组合,每个实验室都花数月做不想拥有的 plumbing。
Harbor:四个文件的统一抽象
Harbor 是 Terminal-Bench 团队推出的编码环境框架,由 Anton Baht 和 Alex Strick 创建。他们对问题的阐述是最清晰的:
在容器中评估被证明既慢又难以扩展……通过训练和优化方法改进 Agent 的能力有限……Agent 框架和 benchmark 间的碎片化要求每个部署都有专门解决方案。
Harbor 诞生于 Terminal-Bench 自己的痛点。作者的发布说明指出了具体修复:指令用 markdown 而非嵌套 YAML,任务配置是类型化的(Pydantic),环境定义是强制且可插拔的,solution 可以是多文件的,奖励由任务产生而非 harness 解析。
最后一点很关键。这是 Harbor 如何在不改变框架本身的情况下,为非二元奖励、judge 分数、多标准评估打开大门。
Harbor 的答案是一个最小化、有观点的标准。一个任务就是一个目录,一个目录有四个文件,任何能在容器里运行的 Agent 都能跑任何任务。 接口小到一下午就能学会,结构又足够严谨,可以在上面搭建严肃的训练基础设施。
四个文件,各答一个问题
hello-world/
├── instruction.md # Agent 该做什么,用英文写
├── task.toml # 类型化配置:超时、资源、元数据
├── environment/
│ └── Dockerfile # (或多容器用 docker-compose.yaml)
├── solution/
│ └── solve.py # 可选的 oracle 解法
└── tests/
└── test.sh # 验证器:把奖励写到 /logs/verifier/
environment/Dockerfile回答:怎么运行?instruction.md回答:Agent 该做什么?tests/test.sh回答:怎么知道成功了?task.toml回答:谁建的、为什么建、有什么限制?
task.toml 是真正的类型化 schema,不是自由格式配置。包含 CPU/内存/GPU、网络白名单、暴露给 Agent 的 MCP 服务器、容器健康检查、验证器 API key 等章节。
最简单的验证器就是一个写数字的 bash 脚本。多指标奖励则写 reward.json,Harbor 负责聚合。奖励就是已知位置上的数字,这种统一性就是全部 trick。
多步任务
对于一次搞不定的任务,Harbor 支持多步工作流。用 steps/<step-name>/ 目录替换 instruction.md 和 tests/,在 task.toml 中声明。每步奖励通过 MEAN 或 FINAL 策略聚合,可选 min_reward 阈值在步骤失败时提前终止 trial。
Agent 适配:USB-C 时刻
Harbor 开箱自带 26 个 Agent 适配器:Claude Code、Codex CLI、OpenHands、Gemini CLI、Aider、Goose、Cursor CLI、Cline CLI、Copilot CLI、OpenCode、Qwen Coder、Kimi CLI、Mini-SWE-Agent、SWE-Agent、Trae Agent(字节)、Rovodev(Atlassian)、NeMo Agent(NVIDIA),加上 Harbor 自己的参考 Agent 和一个跑 solution/solve.sh 做 sanity check 的 oracle 适配器。
但 Harbor 最被低估的做法是把任务和 Agent harness 解耦。自定义 harness 的契约极小:继承 BaseAgent,实现 setup() 和 run(),用 --agent-import-path your.module:YourAgent 运行。这就是整个 API。任何能在容器里安装二进制的地方,就有 Harbor harness。你手搓的 bash + 编辑器脚手架、自定义多 Agent 装置、某人的研究原型,都一样。
反过来同样重要:你写的任何任务都能用任何 Agent 跑。用一个 harness 训练模型,用另一个评估,用第三个部署。任务不知道也不关心。这就是 Agent harness 的 USB-C。
奖励契约:薄到可以任意扩展
奖励契约(/logs/verifier/reward.{txt,json} 中的数字)故意设计得很薄。任何你能在容器里计算的东西,都能写成奖励。Harbor 为此提供一流支持:
- 测试执行奖励:跑 pytest/cargo/jest,写 1.0 或 0.0
- Diff 相似度:Agent diff 与 oracle 的序列相似度,部分修复给部分分数(SWE-RL 配方)
- LLM-as-judge:验证器调用 judge 模型,返回 0 到 1 的分数。API key 通过 task.toml 的
[verifier.env]块干净传递,同一任务可被 Claude、GPT-5 等评分 - 步骤级奖励:多步任务 emit 每步 verifier_results,按 MEAN 或 FINAL 聚合
- Reward Kit:独立包,20+ 内置原语(file_exists、command_succeeds 等)加 TOML 定义的 LLM judge 和 agent-as-judge rubric。Agent judge 在 overlayfs 隔离的 workspace 副本中运行,互不污染。聚合支持加权平均、全通过、任通过、阈值
重点不是 Harbor 内置了每种奖励类型。重点是奖励契约如此之薄,你可以在不碰框架的情况下实现任何奖励,而框架为常见情况提供 batteries-included 的工具。这就是正确的抽象层级。
ATIF:统一 trace 格式 = 训练数据
Harbor 还做了一件事:让每个 Agent 的输出看起来一样。这个格式叫 ATIF(Agent Trace Interchange Format),维护为 RFC-0001(当前 v1.7)。
无论你跑的是 Claude Code、OpenHands、Codex、Mini-SWE-Agent、Gemini CLI 还是自家脚手架,Harbor 的适配器都把 trace 转换成统一的 JSON 形状。每步记录包含 source、model_name、message、reasoning_content、tool_calls、observation,以及带 token 数、缓存 token、美元成本的 metrics 块。根级元数据覆盖 session ID、Agent 身份和最终聚合指标。
为什么重要?因为 trace 一旦统一,就是训练数据。ATIF 作者明确做了这件事:
- v1.3 增加 completion_token_ids,"支持无需重新 tokenization 的 RL 训练"
- v1.4 增加 prompt_token_ids,同样原因
- v1.5 增加 tool_definitions,用于 SFT pipeline
你可以把这个版本历史倒着读:Harbor 在公开摸索 RL pipeline 对 trace 格式的真实需求。结果是一个本身就是一流训练输入的 JSON spec。Harbor 有专门的 SFT 和 RL 工作流文档,并提供一个 PyTorch dataset 适配器,rollout 接口直接返回 Rollout(reward=..., token_ids=..., mask_ids=...)。
这就是闭环。同一任务 spec → 同一执行沙箱 → 同一奖励信号 → 同一 trace 格式 → 可训练。你可以在五个不同 Agent harness 上并行跑数千个 rollout,倒进一个桶,直接喂进后训练。无需重塑。无需胶水代码。没人把四件事都做对了。
最小端到端循环
# 安装
uv tool install harbor
# 用 Claude Code 跑真实 benchmark,4 个并行容器
export ANTHROPIC_API_KEY=<YOUR-KEY>
harbor run \
--dataset terminal-bench@2.0 \
--agent claude-code \
--model anthropic/claude-opus-4-1 \
--n-concurrent 4
# 或用 oracle 本地跑单个任务,确认验证器正常
uv run harbor run --agent oracle --path ./tasks/hello-world
# Mean: 1.000 ✓
想上 Modal 或 Daytona?加 --env modal 或 --env daytona,瞬间千个并行容器上云。Harbor 在单一 flag 后支持 10+ 沙箱后端:Local Docker、Daytona、Modal、E2B、Runloop、Apple Container、GKE、Tensorlake、Islo、Singularity。同一任务 spec。同一奖励信号。同一 trace 输出。
事后用 harbor view 检查一切——本地 web UI,渲染 trajectory、每标准奖励分解、收集的 artifact。
不想从零写任务?Harbor 已内置 15+ 数据集:SWE-Bench 家族、Aider Polyglot、LiveCodeBench、GAIA、BFCL、MedAgentBench、ML-Dev-Bench 等。每个主要 coding/agent benchmark,统一到同一个 harbor run 流程。
总结
未来一年前沿代码模型工作将取决于谁能最快搭建最多环境、验证保真度最高。瓶颈是共享基础设施,我们没时间继续重复建设。
Harbor 是最简单的不输版本:四个文件、任意 Agent、10+ 沙箱、统一可训练 trace。如果你曾经两次重建同样的 eval 脚手架,这就是拿起它的理由。