从0打造编码Agent 阅读 + 实验 ≈ 35 分钟 页内实验 ×3
A9 评测:怎么知道它好不好? 第 4 课

把自己的 agent 接上真实评测,要跑通哪几步?

接上真实评测
本课项目在本机把 miniagent 接上了 Harbor 0.23.0 + Terminal-Bench 2.0。如果一上来就跑自己的 agent,第一次的 5 个 0 分会全记在 agent 头上——可那一次连任务自带的参考解也是 0 / 5,原因是 colima 虚拟机里容器的 DNS 没有上游。正确的顺序是先跑 oracle(只跑参考解,确认环境能起、verifier 能判),5 / 5 之后再用 -a module:Class 接自己的 agent:先用剧本回复排掉适配器的问题,再上真模型,5 个任务 × 3 次。89 个任务镜像没有一个支持 arm64,本机靠 qemu 模拟;另外 10 个任务的 oracle 探测在 3 / 10 时被停掉,两个空结果一个其实已经通过、一个卡在 pytest 收集。
❓

本课一问:前三课用的 T6 数据,是本课项目把自己的 agent 接上 Terminal-Bench 2.0 跑出来的。要跑通哪几步?每一步失败,各说明什么?

这一课先不碰:Terminal-Bench 4.0(有任务需要 GPU,官方用 Modal 这类带 GPU 的云沙箱跑,不适合本机);用 mini-SWE-agent 跑 SWE-bench Lite(大纲选做,本课没做)。

从已有出发

从已有出发 · 累计数据流 点已学环节看它回答什么
每一轮循环都经过

上一课的七个标签里,「环境 / 评分器」一次没命中——因为每个任务都先用参考解确认过环境。A4 的结论在这里换了个样子:隔离边界画在哪,决定了谁来负责拦。在 Harbor 里,任务容器就是边界,所以适配器里的权限是 allow_all、不再套 Seatbelt(miniagent/harbor_agent.py 的文档串写明了这两条是有意的)。

为什么这一课不用贯穿任务。parse_date 的 3 次重复用的是项目自己的 runner(复制任务仓库 → 循环 → harness 验收),不经过 Harbor;要知道「接上一个别人维护的评测」要跑通哪几步,只能看 TB 2.0 这条线。parse_date 本身也满足大纲的教学约束 ⑥(有确定性的验收命令),打包成 Harbor 任务是留给你的练习。

先自己设计:直接用自己的 agent 跑

最省事的做法:装好评测框架,把自己的 agent 挂上去,直接跑。

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案装好评测框架,直接跑自己的 agent
任务第一次 oracle 冒烟的 reward修好 DNS 后
log-summary-date-ranges01
cobol-modernization01
fix-git01
regex-log01
openssl-selfsigned-cert01

改进:两步走,六个真实步骤

项目实测 · 本机 Harbor 0.23.0 + Terminal-Bench 2.0(2026-09-26)
把自己的 agent 接上真实评测:本课项目在本机真实走过的六步(2026-09-26)

命令原样取自项目的 MILESTONES.md 与 scripts/t6_harbor_job.py;结果取自 Harbor 的原始 job 输出(a09-eval.json)。本机有其他任务同时占用,且 amd64 镜像经 qemu 模拟运行,耗时只能粗看;token、轮数、步数可比。

🎯

试三件事:① 在第 2、3 步之间来回点:命令一字没变,结果从 0 / 5 变成 5 / 5——变的只是虚拟机里 dockerd 的 DNS;② 看第 4 步:回复来自剧本、没有调用模型,它检查的是适配器,不是能力;③ 看第 5 步最后一句:每个任务 3 次,Harbor 自己只报了 pass@2。

第 4 步要接的「契约」只有一个类:继承 Harbor 的 BaseAgent,实现 name、version、setup、run。run 拿到任务说明、环境和一个要填的上下文:

Harbor 0.23.0 · agents/base.py:自建 agent 要实现的抽象方法 harbor@v0.23.0:src/harbor/agents/base.py:323-380需联网 Apache-2.0
323 @abstractmethod
324 def name() -> str:
325 """The name of the agent."""
326
327 @abstractmethod
328 def version(self) -> str | None:
329 """The version of the agent."""
330
331 @classmethod
332 def import_path(cls) -> str:
333 """
334 The import path of the agent. Formatted as 'some.import.path:AgentClass'.
335 """
336 return f"{cls.__module__}:{cls.__name__}"
337
338 @abstractmethod
339 async def setup(self, environment: BaseEnvironment) -> None:
340 """
341 Run commands to setup the agent & its tools.
342
343 This is a good place to register the MCP servers in ``self.mcp_servers`` with
344 the agent (e.g. by creating a .mcp.json file) and copy skills from
345 ``self.skills_dir`` to the agent's expected location.
346
347 The user the agent should run as is set on ``environment.default_user`` by
348 the orchestrator before this method is called.
349
350 Args:
351 environment: The environment in which to setup the agent.
352 """
353
354 @abstractmethod
355 async def run(
356 self,
357 instruction: str,
358 environment: BaseEnvironment,
359 context: AgentContext,
360 ) -> None:
361 """
362 Runs the agent in the environment. Be sure to populate the context with the
363 results of the agent execution. Ideally, populate the context as the agent
364 executes in case of a timeout or other error.
365
366 If necessary, register the MCP servers in ``self.mcp_servers`` with
367 the agent (e.g. by creating a .mcp.json file) and copy skills from
368 ``self.skills_dir`` to the agent's expected location.
369
370 The user the agent should run as is set on ``environment.default_user`` by
371 the orchestrator before this method is called. Any call to
372 ``environment.exec`` that does not pass an explicit ``user`` argument will
373 automatically run as that user.
374
375 Args:
376 instruction: The task instruction.
377 environment: The environment in which to complete the task.
378 context: The context to populate with the results of the agent execution.
379 """
380
👆 带下划线的行可以点:点哪行,讲哪行。

命令行上怎么把它接进来,以及 -k 到底是什么意思,Harbor 的 CLI 源码写得很清楚:

Harbor 0.23.0 · cli/jobs.py:-a 接自建 agent,--agent-import-path 已废弃 harbor@v0.23.0:src/harbor/cli/jobs.py:589-613需联网 Apache-2.0
589 agent_name: Annotated[
590 str | None,
591 Option(
592 "-a",
593 "--agent",
594 metavar=_AGENT_METAVAR,
595 help=(
596 "Agent to run, or a custom agent import path "
597 "(module.path:ClassName). Also accepts an ACP registry "
598 "shorthand (e.g. acp:opencode@1.3.9). "
599 "Options: harbor agent schema <name>."
600 ),
601 rich_help_panel="Agent",
602 show_default=False,
603 ),
604 ] = None,
605 agent_import_path: Annotated[
606 str | None,
607 Option(
608 "--agent-import-path",
609 help="Deprecated: pass the import path to --agent instead.",
610 rich_help_panel="Agent",
611 show_default=False,
612 hidden=True,
613 ),
👆 带下划线的行可以点:点哪行,讲哪行。
Harbor 0.23.0 · cli/jobs.py:-k 是每个任务的重复次数 harbor@v0.23.0:src/harbor/cli/jobs.py:454-465需联网 Apache-2.0
454 n_attempts: Annotated[
455 int | None,
456 Option(
457 "-k",
458 "--n-attempts",
459 help=f"Number of attempts per trial (default: {
460 JobConfig.model_fields['n_attempts'].default
461 })",
462 rich_help_panel="Job Settings",
463 show_default=False,
464 ),
465 ] = None,
👆 带下划线的行可以点:点哪行,讲哪行。

极小真数字:一个 trial 的时间花在哪

oracle 冒烟 · log-summary-date-ranges 这一个 trial(第二次,5 / 5 那一轮)
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
换成本课 agent 之后,5 个任务的 job 各要 252–1128 秒(每个 job = 一个任务 × 3 次,-n 1 串行),合计约 54 分钟。k 从 3 加到 5,这笔时间按比例涨。

arm64 上还能跑哪些任务

本机只证明了 5 个任务在模拟下能跑通。另外 10 个任务的 oracle 探测,job 在 3 / 10 时被停掉:

项目实测 · oracle-arm64-probe(Harbor 原始输出,两个空结果逐个查过原因)
arm64 上能跑哪些 TB 2.0 任务?oracle 在 10 个任务上的探测(job 在 3 / 10 时被停掉)
任务TB 作者估专家耗时结果参考解阶段verifier 阶段原因与证据
pytorch-model-cli 30 分钟 被取消 593 秒 350 秒 参考解在 qemu 下跑了 593 秒,verifier 装完 torch 等依赖后在 pytest 收集阶段被停掉,结果未知。日志里有 qemu 的痕迹(jemalloc 提示、uv 安装脚本报 unknown platform bitness),但都没有让它失败。
证据行(3)
<jemalloc>: (This is the expected behaviour if you are running under QEMU)
ERROR: unknown platform bitness
collecting ...
largest-eigenval 60 分钟 通过(reward 1) 61 秒 42 秒 qemu 模拟下参考解与 verifier 都跑通了。
证据行(1)
============================== 27 passed in 5.61s ==============================
sqlite-with-gcov 30 分钟 没开始 — — job 被停掉时还没排到。
kv-store-grpc 15 分钟 没开始 — — job 被停掉时还没排到。
build-pmars 90 分钟 没开始 — — job 被停掉时还没排到。
headless-terminal 120 分钟 通过(reward 1) 1 秒 110 秒 qemu 模拟下参考解与 verifier 都跑通了。
证据行(1)
============================== 7 passed in 16.71s ==============================
nginx-request-logging 20 分钟 没开始 — — job 被停掉时还没排到。
git-multibranch 180 分钟 被取消 2 秒 175 秒 job 被停掉时它的 verifier 其实已经写下 reward 1(ctrf 1 / 1 通过),但 Harbor 没来得及记进 result.json,记成了 CancelledError。按 Harbor 的 pass_at_k.py,没有 verifier 结果的 trial 算 0 分。
证据行(4)
<jemalloc>: (This is the expected behaviour if you are running under QEMU)
ERROR: unknown platform bitness
========================= 1 passed in 79.18s (0:01:19) =========================
TEST PASSED
count-dataset-tokens 30 分钟 没开始 — — job 被停掉时还没排到。
qemu-startup 30 分钟 参考解没过(reward 0) 308 秒 40 秒 verifier 在容器里现装 curl 时,3 个 debian-security 包返回 404,curl 与 uvx 都没装上,测试根本没跑起来:这是评分器依赖外网包源造成的,不是参考解错,也没有证据说明是 arm64 模拟造成的(404 发生在下载阶段;是镜像源已下架旧版本还是经本机代理出的问题,没有再查)。
证据行(5)
E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/n/nghttp2/libnghttp2-14_1.43.0-1%2bdeb11u3_amd64.deb  404  Not Found
E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/c/curl/libcurl4_7.74.0-1.3%2bdeb11u16_amd64.deb  404  Not Found
E: Failed to fetch http://deb.debian.org/debian-security/pool/updates/main/c/curl/curl_7.74.0-1.3%2bdeb11u16_amd64.deb  404  Not Found
/tests/test.sh: line 8: curl: command not found
/tests/test.sh: line 19: uvx: command not found

这个 job 在跑到 3 / 10 时被 SIGTERM 停掉(Harbor 的 _handle_sigterm 抛 KeyboardInterrupt,两个正在跑 verifier 的 trial 记为 CancelledError,5 个还没开始)。 统计:完成 3、取消 2、未开始 5,Harbor 记的平均分 0.667(只算完成的 3 个)。时间只能粗看:本机有其他任务同时占用,且 amd64 镜像经 qemu 模拟运行(2 个并发)。

读这张表要分清三件事:通过的 2 个说明模拟可行;参考解没过的 qemu-startup,原因是评分器现装依赖时 3 个包 404,测试根本没跑起来——这是「环境 / 评分器」标签的一个真实样本;被取消的两个不能记成失败:git-multibranch 的 verifier 其实已经写下 reward 1(测试 1 / 1 通过),只是 Harbor 没来得及记;pytorch-model-cli 的参考解在模拟下跑了 593 秒,verifier 卡在 pytest 收集阶段时 job 被停掉,结果未知 。

⚠
常见误解一:「oracle 冒烟通过了,就是评测了自己的 agent。」

oracle 只跑任务自带的参考解。它证明的是「这台机器上,这个任务的环境能起、verifier 能判对」;它什么也没说你的 agent。本课的 oracle 5 / 5,agent 0 / 15。

⚠
常见误解二:「-k 3 就会得到 pass@3。」

-k 只是每个任务跑几次。Harbor 报哪几个 k 由 _eligible_k_values 决定:只报 2 的幂与 5 的倍数,且不超过每个任务最少的次数。本课每个 job 的 result.json 里都只有 {"2": 0.0}。想要 pass@3、pass^3,自己用第 1 课的公式从 (n, c) 算。

⚠
常见误解三:「被取消的 trial 就是失败。」

Harbor 的 pass@k 把没有 verifier 结果的 trial 记 0 分。git-multibranch 这一例,verifier 已经判了通过。统计时把「取消 / 异常」和「0 分」分开数。

证据三问

问本课的回答
① 它解决什么问题?把「环境坏了」与「agent 不行」分开:先证明环境能判对,再让 agent 上场
② 为什么要两步?参考解是已知能过的输入;它都过不了,错就不在 agent
③ 实验上呢?同一条命令,DNS 修好前后 0 / 5 → 5 / 5 ;Harbor 的参数语义直接读源码

演进地图:你在这里

评测的演进:每一步都被上一步的真数字逼出来
  1. 最直觉的做法:一个任务、一次运行、一个布尔值
    解决了最省事:修好了就说「会修」,没修好就说「不会」。
    卡在同一套配置只换 seed:pd-v2-unlimited 的 s1 / s2 / s3 是 ✗ ✓ ✓;同为 seed 1、只多了一个没碰到的轮数上限的 pd-v2-cap20-s1 又是 ✓。只跑一次,结论取决于你碰上了哪一次。
  2. Anthropic《Demystifying evals for AI agents》· Harbor 的 -k 与 pass_at_k.py
    解决了同配置的 7 次运行过了 6 次:p̂ = 0.857,pass@3 = 99.7%,pass^3 = 63.0%;T6 的 3 次重复全过。
    卡在拿全体平均成功率套公式:TB 4.0 官方榜第一行(Codex + GPT-6 Astra,max)pass@1 为 58.18%,公式给 pass@5 = 98.7%,榜单实测 71.2%:每个任务的成功率不一样。而且重复再多次,也分不出分数里哪部分是 harness。
  3. Vals 统一用 Terminus 2 复测 TB 4.0 · SWE-bench 官方 bash-only 榜统一用 mini-SWE-agent
    解决了同一个模型换 harness 的差距摆上桌:Fable 5.1 在 Claude Code 上 57.88%、在 Terminus 2 上 49.49%;GLM-5.3 41.82% → 25.25%。
    卡在分数只告诉你成没成:本课 agent 在 TB 2.0 上 0 / 15,15 次失败各是各的样子,一个数看不出为什么。
  4. Harbor 的 ATIF 轨迹 · Anthropic 工程博客的四类失败 · 本章写明的标签规则
    解决了15 次失败都落到了带步号的标签上:改完 / 跑完不回头查 7 次,撞上输出上限 4 次,明确声称完成 5 次、5 次没过。
    卡在标签分不清是 agent 错还是环境错:第一次 oracle 冒烟 0 / 5,原因是容器里的 DNS;arm64 探测里 qemu-startup 连参考解也拿 0 分(verifier 现装 curl 时 404)。
  5. Harbor v0.23.0:-a oracle 冒烟 → -a module:Class -k
    解决了参考解 5 / 5 通过、环境就绪之后,再跑自家 agent:5 个任务 × 3 次。
    卡在k = 3、单一 8B 本地模型、5 个任务、amd64 镜像靠 qemu 模拟:结论只在这个规模成立。(→ 课程终点:回到 A0,哪些任务值得用 agent?)

数字口径:本课项目 T6(Harbor 0.23.0 + Terminal-Bench 2.0,本机 Qwen3-8B-MLX-4bit,录制于 2026-09-26)与 A1 的同配置运行;TB 4.0 官方榜(更新于 2026-09-21)与 Vals(更新于 9/22/2026),均于 2026-09-27 抓取;由 a09-eval.json 与 a09-public-2026-09-27.json 构建时现算。

一句话

📌
先用参考解确认环境,再上自己的 agent。
🚦

先停在这里:记住顺序——oracle → 剧本冒烟 → 真模型 × k 次 → 读 result.json 与轨迹。
再深一层:项目里的 scripts/harbor_env.sh(隔离的 Docker 配置、关遥测)与 scripts/t6_harbor_job.py(一个任务 × k 次的完整命令),照着能在你自己的机器上复现。

下一个缺口

课程终点:回到 A0——哪些任务值得用 agent? → 实验课:自己的 agent 上 TB 2.0,再回到 A0 复盘

A0 在写第一行 agent 代码之前,问过「这个任务需要 agent 吗」。现在有了真实评测的结果,可以把那个问题再问一遍。

你可能会问