第 19 章:使用 Harbor 内置 Agent
同一个故障诊断 Task,oracle 能通过,换成 claude-code 后却在模型请求之前失败。团队随即更换模型,错误仍然存在。最后发现,容器没有安装 Agent CLI 所需的系统包,而且 Task 的网络基线禁止了安装阶段访问软件源。模型从未看到指令,所谓“模型失败”其实是 Agent setup 失败。
内置 Agent 的价值,在于 Harbor 已经替你实现了一批安装、Headless 调用、认证注入和轨迹转换适配器;它并不表示任意 Agent 都能搭配任意模型、操作系统、MCP Server 或 Skill。更不能仅凭 --agent 名称,就把两个运行视为公平对照。本章把 Agent 作为一个需要版本化、预检和审计的实验组件。
完成本章后,你应该能够:
- 解释
BaseAgent、BaseInstalledAgent、Factory 与 Trial 生命周期的分工; - 从 Harbor v0.18.0 源码生成准确的内置 Agent 清单;
- 在调用模型前检查安装、认证、模型命名、Headless、操作系统和轨迹能力;
- 固定 Prompt、轮次、超时和工具权限,运行一个可复核的内置 Agent Job;
- 区分配置、安装、认证、Agent 执行和 Verifier 失败,并据此设计公平比较。
19.1 名称背后是一段执行协议
AgentConfig 最终不会直接执行字符串。Trial 先把配置交给 AgentFactory:Factory 解析宿主机环境变量模板,按注册名或 import path 导入类,再把 model_name、kwargs、MCP 和 Skill 等参数传入实例。BaseAgent 只规定四个关键动作:报告名称、报告版本、setup() 和 run();run() 还接收 AgentContext,供实现回填 token、成本和 trajectory 等结果。12
Harbor 文档把集成分为两类:一种通过 BaseEnvironment 操作沙箱,另一种继承 BaseInstalledAgent,把第三方 Agent 安装到任务环境并以 Headless 模式运行。3 本章把后者称为 Installed Agent。不要把“非 Installed”机械理解成“运行在宿主机”:terminus-2、computer-1 等内置执行器仍通过 Harbor 的环境接口工作,只是没有走 BaseInstalledAgent.install() 这一套公共骨架。
Installed Agent 的基本生命周期如下:
解析 Job/Task
│
├─ 创建 Agent 与 Environment
├─ 启动环境、健康检查、上传 Skill
├─ Agent setup:安装 CLI、检测版本
├─ Agent run:渲染 Prompt、注入认证、Headless 执行
├─ 同步 Agent 日志与 trajectory
└─ Verifier:独立判断最终状态
BaseInstalledAgent.setup() 先调用具体实现的 install(),只有未显式指定版本时才尽力执行版本探测;探测异常会被忽略。因此,“结果里出现某个版本”与“安装时真正锁定了该版本”不是同一件事。正式实验应在 kwargs.version 中固定第三方 CLI 版本,并在预检后核对 agent_info.version。4
这里还有一个常被忽略的网络边界。Agent Environment 用 Task 的 [environment] 网络策略作为启动基线;只有进入 agent.run() 时,Harbor 才会按 Agent phase 策略临时切换网络。extra_allowed_hosts 的模型字段也明确限定为 agent.run()。由此可以推断:在线安装发生在 setup 阶段,它使用环境基线,而不是 --allow-agent-host 增补后的 Agent phase 策略。一个基线为 none 的 Task 即使允许模型 API 域名,也可能无法下载 Agent CLI。解决办法是把 Agent 预装进镜像,或为 setup 保留必要网络;不要把软件源域名误加到只作用于 run() 的参数上。5
19.2 v0.18.0 的内置 Agent 清单
本书不从网页宣传语复制清单,而是读取固定提交中 AgentFactory._AGENT_MAP。该映射在 v0.18.0 恰好包含 32 个名称。下面按基类和 ATIF(Agent Trajectory Interchange Format)能力分组;组内每个名称都是可传给 Factory 的精确字符串。6
| 组别 | 数量 | 精确名称 |
|---|---|---|
| 非 Installed、支持 ATIF | 2 | terminus-2、computer-1 |
| 非 Installed、不声明 ATIF | 3 | oracle、nop、dspy-rlm |
| Installed、支持 ATIF | 24 | acp、claude-code、copilot-cli、cline-cli、codex、cursor-cli、gemini-cli、antigravity-cli、rovodev-cli、goose、hermes、kimi-cli、mini-swe-agent、nemo-agent、swe-agent、opencode、mimo、openclaw、openhands、openhands-sdk、qwen-coder、devin、trae-agent、eve |
| Installed、不声明 ATIF | 3 | aider、langgraph、pi |
acp 是通用运行器;acp:<id>@<version> 是运行时解析的 Registry 简写,不是额外的固定内置类。省略 ACP 版本会在 setup 阶段访问 Registry 的分支来解析最新条目,这不适合要求离线复现的实验。7
注意:v0.18.0 的
AgentName枚举还包含terminus和terminus-1,CLI 帮助的 metavar 也从整个枚举生成;但 Factory 映射没有这两个名称。传入后会在创建阶段得到 unknown agent 错误。这个版本里应以 Factory 映射为可创建清单,而不是只看帮助中的候选词。8
ATIF 标志也只回答“该适配器声明能够产出 Harbor 标准轨迹”,不保证每次运行一定留下有效轨迹。CLI 崩溃、日志同步失败或转换器遇到未知事件格式,都可能让 trajectory 缺失。反过来,SUPPORTS_ATIF=False 不意味着 Agent 无日志,只表示不能把其私有日志当成标准 ATIF 使用。
操作系统边界更严格:v0.18.0 的预检只允许 oracle 和 nop 运行 Windows Task,其余 Factory 内置 Agent 均为 SUPPORTS_WINDOWS=False,并在 setup 前拒绝。9
可以在固定源码树中运行下面的无网络探针,重新生成清单和能力位:
cd /private/tmp/harbor-framework-v0.18.0
uv run --frozen python - <<'PY'
from harbor.agents.factory import AgentFactory
from harbor.agents.installed.base import BaseInstalledAgent
rows = []
for name in AgentFactory._AGENT_MAP:
cls = AgentFactory.get_agent_class(name)
rows.append((
name.value,
issubclass(cls, BaseInstalledAgent),
cls.SUPPORTS_ATIF,
cls.SUPPORTS_WINDOWS,
))
assert len(rows) == 32
assert {r[0] for r in rows} == {n.value for n in AgentFactory._AGENT_MAP}
for row in rows:
print(*row, sep="\t")
PY
这个探针只导入和检查类,不安装第三方二进制,也不调用模型。它适合放进版本升级检查:当映射、能力位或导入依赖变化时,先审查差异,再更新兼容矩阵。
19.3 先做兼容性预检
内置只表示“Harbor 有适配器”。在决定运行前,至少回答以下问题:
- Factory 能否创建该名称,还是只有枚举或文档提到它?
- Task 是 Linux 还是 Windows;Agent 是否声明支持?
- Agent setup 需要什么包管理器、网络和容器用户?二进制能否固定版本?
- wrapper 接受怎样的
model_name,会不会删除 Provider 前缀? - 认证从 API Key、OAuth 文件还是云凭据链取得?
- Headless 命令如何处理确认提示和标准输入?
- 工具、MCP、Skill 和网络能力是否真的由该实现支持?
- 是否产出 ATIF;失败后还能取得哪些原生日志?
下表只比较本章查过源码的三个代表性 CLI Agent,不应外推到其他 29 个名称:
| 项目 | claude-code | codex | gemini-cli |
|---|---|---|---|
| 模型处理 | 显式模型推荐写 provider/model;官方 Anthropic 路径会去掉第一个前缀,自定义 Base URL 保留全名 | 必须非空;运行时取最后一个 / 后的部分 | 必须含 /;运行时同样取最后一段 |
| 常用认证 | ANTHROPIC_API_KEY;也有显式强制 OAuth 与 Bedrock 分支 | 默认 OPENAI_API_KEY;可显式选择 auth.json | Gemini API Key、Vertex 环境变量或显式 OAuth 凭据文件 |
| Headless 入口 | claude --print --output-format=stream-json | codex exec --json | gemini --prompt ... |
| 默认自动化权限 | wrapper 的 permission_mode 默认 bypassPermissions | wrapper 固定传入跳过确认与内部沙箱参数 | wrapper 固定传入 --yolo |
| ATIF | 是 | 是 | 是 |
这些差异解释了为什么“同一个模型名”仍可能不兼容。比如 Codex 和 Gemini wrapper 都只把最后一段传给 CLI;带多层路径的模型标识可能失去中间部分。Claude Code 还根据官方 API、自定义 Base URL 或 Bedrock 选择不同的模型传递规则。三个 wrapper 的认证优先级和凭据文件注入方式也不同。101112
Harbor 的 Headless 参数与上游 CLI 的非交互能力相呼应:Claude Code 官方参考把 --print 定义为非交互输出,并提供 --max-turns、工具权限和 permission mode;Gemini CLI 官方文档把 --prompt 与 --yolo 列为 Headless 选项。1314 但 Harbor 固定的是自己的 wrapper 行为,而不是上游 CLI 永久不变的接口。第三方版本升级后,必须重跑安装与命令构造测试。
警告:
bypassPermissions、Codex 的 dangerous bypass 和 Gemini 的--yolo都是高自治设置。它们消除 Headless 卡在人工确认处的问题,却不能代替容器用户、网络策略、资源限制和独立 Verifier。尤其不要挂载 Docker socket、云平台管理凭据或宿主机目录后,再把“运行在容器里”当成完整隔离。
19.3.1 认证文件不是普通配置文件
API Key 路径最简单:在 AgentConfig.env 中使用 ${HOST_VAR} 模板,让 Factory 在创建 Agent 时解析,再由 Trial 只在 setup/run 的命令作用域内合并。不要把模型凭据放进 Task 的 [environment.env]:后者属于任务环境本身,会扩大能读到凭据的进程范围,也会混淆“任务输入”和“Agent 认证”两种不同职责。
文件型认证更需要逐实现核对。Codex wrapper 默认使用 OPENAI_API_KEY,只有显式设置 CODEX_AUTH_JSON_PATH 或 CODEX_FORCE_AUTH_JSON 才上传 auth.json;Gemini wrapper 的 OAuth 也必须通过路径或 force 变量显式启用,上传后会调整属主、复制为 0600,结束时再尽力删除。Claude Code 在 API Key 与 OAuth token 同时存在时默认优先 Key,除非显式强制 OAuth。111210
“尽力删除”不能证明密钥从镜像层、Provider 快照、进程环境、崩溃转储和下载日志中彻底消失。高保证场景应使用短期凭据、最小权限账户、一次性沙箱和运行后吊销,并验证所选 Environment Provider 的快照与日志策略。订阅凭据能否用于自动评测还受相应服务条款约束;Harbor 的技术适配不等同于授权。
安装链也是供应链边界。以 Claude Code 为例,wrapper 能固定目标版本,但在非 Alpine 路径会下载并执行上游 bootstrap 脚本。版本 pin 可以阻止无意升级,却不等于对安装脚本和所有传递产物做内容哈希验证。对可审计的基准,应在受控构建流程中预装 Agent,锁定基础镜像 digest 和包完整性,正式 Trial 只验证 --version,不临时执行远程安装脚本。15
19.4 Prompt、轮次和超时是三组不同控制器
Installed Agent 可以通过 prompt_template_path 在宿主侧渲染 Jinja2 模板。模板必须引用 {{ instruction }};渲染使用 StrictUndefined,出现未定义变量会失败,而不是悄悄留空。16 这非常适合把评测协议与 Task 原始 instruction 分离。创建 prompts/incident-agent.j2:
你正在封闭的评测环境中处理系统故障。
规则:
- 先收集证据,再修改文件;
- 不猜测服务状态,使用容器内可用命令验证;
- 不访问外部互联网;
- 完成后留下简短的诊断与验证记录。
原始任务如下:
{{ instruction }}
Prompt 模板不是隐藏答案,也不应包含某个 Task 的目标文件内容。公平比较时固定模板字节并记录 SHA-256;如果要比较两个 Prompt,就把 Prompt 明确列为实验变量,不能再把差异归因给 Agent。
轮次是 Agent 自己理解的循环次数。例如 v0.18.0 的 Claude Code wrapper 把 max_turns 映射成 --max-turns,还暴露思考、预算、fallback model、工具和 permission mode 等 Agent 专属参数。kwargs 不是跨 Agent 的统一标准;把 Claude 的 max_turns=12 原样传给另一个实现,可能被忽略,也可能在构造时失败。17
超时则由 Harbor 包围整个阶段:
- setup 默认上限为 360 秒,可用
override_setup_timeout_sec或 multiplier 调整; - Agent 执行基线来自 Task 的
[agent].timeout_sec,Job 的override_timeout_sec可替换它; - Job 的
agent_timeout_multiplier只缩放 Agent 执行,agent_setup_timeout_multiplier单独缩放安装; max_timeout_sec是运行配置的封顶值,不是轮数。
如果 Task 没有 Agent timeout,单步 Trial 的 Agent 执行 timeout 可以是 None。生产评测不要只设 max_turns 而省略 Harbor timeout:CLI 可能卡在网络、子进程或未知提示上,未必消耗新的模型轮次。18
工具权限同样有三层:Agent CLI 的工具策略、Task 容器的 OS 权限、Harbor 的网络与 Artifact 边界。Claude Code 的 allowed_tools 表示无需询问即可使用的工具,不应误读成安全白名单;严格禁止项要使用 disallowed_tools,外网仍应由 Harbor 网络策略阻断。即使禁止 WebFetch,Bash 仍可能调用 curl,所以工具名过滤不能替代 egress 控制。13
19.5 一个可核验的 Claude Code Job
下面把前几章的本地 Dataset 接入内置 claude-code。示例锁定 Harbor v0.18.0,并把第三方 Claude Code CLI 固定为 2.1.204;该包版本在 2026-07-16 已从 npm Registry 核验存在。19 模型标识沿用 v0.18.0 随附教程中的 anthropic/claude-sonnet-4-5。运行前仍应确认你的账户有权访问该模型。20
从书稿配套项目根目录创建 configs/ch19-claude.yaml:
job_name: ch19-claude-controlled
jobs_dir: jobs
n_attempts: 1
n_concurrent_trials: 1
timeout_multiplier: 1.0
environment:
type: docker
force_build: false
delete: true
agents:
- name: claude-code
model_name: anthropic/claude-sonnet-4-5
n_concurrent: 1
override_timeout_sec: 900
override_setup_timeout_sec: 600
kwargs:
version: "2.1.204"
prompt_template_path: prompts/incident-agent.j2
max_turns: 12
max_budget_usd: "2.00"
disallowed_tools: WebFetch
permission_mode: bypassPermissions
env:
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY}"
datasets:
- path: datasets/system-config-benchmark
task_names:
- diagnose-python-service
YAML 中没有真实 Key。Factory 创建 Agent 时才把完整匹配的 ${ANTHROPIC_API_KEY} 从宿主环境解析出来;缺失且没有默认值时会直接报错。Agent 配置序列化会把敏感值模板化或脱敏,Agent env 的作用域只包围 setup/run,不延伸到 Verifier、构建和 Artifact 命令。21
警告:Agent 进程在其作用域内仍然能读取凭据。
BaseInstalledAgent._exec()还会把每次调用的env放进 DEBUG 日志记录的附加字段。不要在共享 CI 日志中开启--debug,不要上传未经审查的 Agent 日志,也不要把真实 Key 写成 YAML 字面量。22
19.5.1 无模型、无 Docker 的静态预检
在已经安装并激活 Harbor v0.18.0 的 Python 环境中,先验证 Job、Factory、Prompt 和 CLI flags,不安装任何东西:
ANTHROPIC_API_KEY=preflight-placeholder python - <<'PY'
import os
from pathlib import Path
import yaml
from harbor.agents.factory import AgentFactory
from harbor.models.job.config import JobConfig
raw = yaml.safe_load(Path("configs/ch19-claude.yaml").read_text())
job = JobConfig.model_validate(raw)
assert job.n_concurrent_trials == 1
assert len(job.agents) == 1
agent = AgentFactory.create_agent_from_config(
job.agents[0], logs_dir=Path("/tmp/ch19-agent-logs")
)
assert agent.name() == "claude-code"
assert agent.version() == "2.1.204"
assert agent.to_agent_info().model_info.provider == "anthropic"
assert agent.to_agent_info().model_info.name == "claude-sonnet-4-5"
assert "--max-turns 12" in agent.build_cli_flags()
assert "--disallowedTools WebFetch" in agent.build_cli_flags()
rendered = agent.render_instruction("诊断服务并提交修复。")
assert "诊断服务并提交修复。" in rendered
assert "{{ instruction }}" not in rendered
print(agent.name(), agent.version())
print(agent.build_cli_flags())
PY
preflight-placeholder 只用于验证模板解析,不能发起真实请求。预期的确定性输出是 Agent 名称、固定版本以及构造出的 flags;此时不会验证包管理器、上游下载地址、模型权限或账户额度。
19.5.2 只验证安装
确认 Dataset 路径和 Docker 可用后,先执行:
export ANTHROPIC_API_KEY='<YOUR-KEY>'
harbor run \
--config configs/ch19-claude.yaml \
--install-only \
--job-name ch19-claude-install-check \
--yes
--install-only 仍会启动每个选中 Task 的环境并执行 Agent setup,但跳过 agent.run() 和 Verifier,并自动禁用验证。这里必须覆盖为独立的 job_name:Harbor 会把 install_only=true 写入保存配置,同名 Job 之后改成完整运行会因新旧 JobConfig 不相等而被拒绝。安装预检能发现操作系统、包管理器、setup 网络、用户权限和第三方版本问题,却不能证明认证有效、模型可用或 Agent 能完成任务。23
检查 jobs/ch19-claude-install-check/ 下的 Trial:
result.json有agent_setup的起止时间;agent_info.name为claude-code;agent_info.version为2.1.204;- 没有把“无 Reward”误判为 Task 失败,因为本次本来就没有运行 Verifier;
exception_info为空,否则先修 setup,不进入付费实验。
若 Task 的环境镜像本身已经包含匹配版本,Claude Code wrapper 会先执行版本检查并跳过重装;版本不匹配才进入安装路径。这样可以把 setup 网络依赖从正式评测中移除。15
19.5.3 运行一次低并发验证
安装预检通过后,再执行完整 Job:
harbor run --config configs/ch19-claude.yaml --yes
这一步会产生真实模型费用,且结果不应预先写进书稿。验收时同时检查:
config.json与 lock 中的 Agent、模型、Prompt 来源和 Task 身份符合预注册计划;- Trial 的
agent_info保留 Agent 版本与完整provider/model; agent_setup、agent_execution、Verifier 三段时间能够分开;agent/trajectory.json通过 ATIF 校验;- Reward 来自 Verifier,而不是从 Agent 最终文字猜测;
exception_info、Agent 原生日志与 Reward 没有互相矛盾。
Prompt 也应纳入版本材料:
shasum -a 256 prompts/incident-agent.j2
python -m harbor.utils.trajectory_validator \
jobs/ch19-claude-controlled/<trial>/agent/trajectory.json
19.6 怎样比较两个 Agent 才算公平
公平不等于强行让所有 Agent 的配置字段看起来相同。不同 CLI 的工具系统、默认 Prompt、上下文管理和权限语义本来就是 Agent 的一部分。你需要固定的是实验问题,并清楚标出哪些差异属于处理变量。
如果问题是“Agent A 与 Agent B 在同一模型上的脚手架差异”,则必须先证明两个 wrapper 都能无损表达同一个模型和认证路径。做不到时,结论只能写成“Agent+Model 系统比较”,不能声称 Agent 因果效应。建议在开跑前冻结下列矩阵:
| 维度 | 必须记录的值 | 不一致时的处理 |
|---|---|---|
| Harbor | v0.18.0 与 commit | 禁止合并结果 |
| Agent | Factory 名、wrapper 路径、CLI 精确版本 | 视为 Agent 处理变量 |
| Model | 完整 Provider、模型 ID、端点与认证路径 | 不同则报告系统比较 |
| Task | Dataset ref/digest、Task checksum、容器镜像 | 不同则重跑 |
| Prompt | 模板 SHA-256、附加指令顺序 | 不同则单列实验臂 |
| 自治预算 | Agent 原生轮次、Harbor timeout、金额上限 | 解释不可完全等价之处 |
| 能力面 | 用户、工具、MCP、Skill、网络、资源 | 记录有效能力,不只记录参数名 |
| 采样 | 尝试次数、并发、重试策略、时间窗口 | 同批交错运行并保留全部 Trial |
Harbor 的 n_concurrent 是每个 Agent 的 run() 并发上限,并受 n_concurrent_trials 总上限约束。它适合把 Provider 限流不同的 Agent 放进共享并发池,但限流参数本身会影响等待和失败率,应写入实验计划。24
Agent 版本也不能依赖“安装时最新”。若某个适配器不支持真正的版本固定,就预装带 digest 的环境镜像,并把镜像、实际 --version 输出和 wrapper commit 一起记录。安装时间应作为 setup 指标单独报告;能力比较至少同时给出 Agent execution 时间和端到端时间,不能把首次下载依赖的冷启动全部算成模型推理速度。
19.6.1 把有效能力写进实验清单
仅保存 Harbor 命令还不够。某个 Agent 的 allowed_tools=Read 可能表示“Read 无需确认”,另一个 Agent 的相似字段却可能表示“只允许 Read”;名称相同、语义未必相同。预注册材料应同时包含原始配置和归一化后的有效能力说明,例如:
filesystem: /app 可读写;其余只读或不可见
process: 可执行普通用户命令;无 sudo;无 Docker socket
network: 仅模型 API 与任务内服务;禁止公共 Web
tools: Read/Edit/Bash;WebFetch 禁止;原生确认已 Headless 化
mcp: 无
skills: incident-response@<content-sha256>
timeout: setup=600s;run=900s;native max_turns=12
budget: native max_budget_usd=2.00;账户侧另有限额
其中“可执行普通用户命令”必须由 Task 的 agent.user、容器 capability 和实际探针证明,不能由 Prompt 宣称。模型预算也有两个边界:CLI 的本地金额上限依赖上游计费信息,账户或网关限额由 Provider 执行;两者都不能替代 Harbor 的墙钟超时。把这份归一化清单随 Job lock 保存,审计者才能判断两个 Agent 面对的动作空间是否可比。
同批运行还应交错不同实验臂。若先把 Agent A 全部跑完,再隔数小时运行 Agent B,Provider 负载、限流、镜像缓存和任务服务状态都会与 Agent 处理变量纠缠。Harbor 会把 Agent 放在 Trial 组合的内层以便分散模型 Provider,但你仍需保存 Trial 时间、重试和基础设施异常,并在报告中给出全部计划分母,而不是只比较成功返回的样本。25
19.7 失败分类与排查顺序
内置 Agent 的失败最好按最先失效的边界分类:
| 阶段 | 典型证据 | 先检查什么 |
|---|---|---|
| 配置/创建 | unknown agent、缺环境变量、非法 enum 或 kwarg | Factory 映射、JobConfig、Agent 构造静态探针 |
| Environment | 镜像构建、健康检查或 OS 不兼容异常 | Task OS、Provider、镜像和资源 |
| Agent setup | 包管理器、DNS、权限、安装超时、版本不符 | 环境基线网络、容器用户、固定版本、setup 日志 |
| 认证/模型 | 401/403、模型不存在、凭据文件路径错误 | wrapper 的认证优先级与模型拆分规则 |
| Agent run | 非零退出、API rate limit、网络错误、Agent timeout | 原生日志、trajectory、Harbor phase 时间 |
| Verifier | Reward 缺失或测试异常 | Verifier 日志与候选最终状态 |
BaseInstalledAgent 会从非零命令的 stdout/stderr 匹配 rate limit、usage limit、API 5xx、overloaded、连接关闭、DNS、TLS 和连接失败等模式;没有匹配才回退为普通 NonZeroAgentExitCodeError。这是重试与归因的有用线索,不是完整根因证明:第三方 CLI 改写错误文本后,分类可能退化。26
单步 Trial 对 Agent timeout 或非零退出会记录异常、同步已有输出,然后仍继续运行 Verifier。于是一个 Trial 可以同时有 exception_info 和部分 Reward;不要用“有 Reward”反推 Agent 正常结束,也不要把所有异常后的零分都归因给模型。27
一个有效的排查顺序是:
- 重跑静态预检,排除名称、配置和 Prompt 错误;
- 用同一个 Task 执行
--install-only,排除环境和安装错误; - 查看
result.json中最早失败阶段及exception_info; - 查 Agent 原生日志,确认认证、模型与 Headless 命令是否真正启动;
- 校验 trajectory,但不把缺失 trajectory 自动等同于 Agent 沉默;
- 最后才解释 Verifier Reward,并把重试、超时和基础设施失败保留在总分母审计中。
19.8 本章小结
- Harbor 的内置 Agent 是版本化 wrapper,不是对任意模型和平台的兼容承诺。
- v0.18.0 的 Factory 映射有 32 个可创建名称;
terminus与terminus-1只是遗留枚举项。 - setup 使用环境网络基线,Agent phase allowlist 不会自动解决在线安装。
- Prompt、Agent 原生轮次、Harbor timeout 和工具权限必须分别固定与记录。
- 三个代表性 CLI wrapper 都采用高自治 Headless 参数,真正的安全边界仍在用户、容器、网络、资源和 Verifier。
- 先静态预检,再
--install-only,最后才进行模型调用,能避免把安装与认证错误算成能力失败。 - 无法让两个 Agent 使用同一模型和能力面时,应报告 Agent+Model 系统比较。
19.9 练习
- 运行本章 Factory 探针,把 32 个名称保存为排序后的 JSON;再断言
AgentName.values()与 Factory key 的差集恰好是terminus、terminus-1。 - 为
codex编写一份只做静态构造的 Job 配置,验证缺少model_name会在run()前成为明确风险;比较 API Key 与auth.json两条认证路径,不上传真实凭据。 - 把贯穿项目 Task 的
[environment]基线改为none,保留 Agent phase 的模型域名 allowlist,解释为什么在线install()仍失败;再通过预装 Agent 的镜像消除该依赖。 - 设计
claude-code与另一个 wrapper 的兼容矩阵。若不能共享完全相同的模型和认证端点,重写研究问题,使结论不再声称纯 Agent 因果差异。 - 构造一个 Agent 非零退出但工作区已有部分修复的教学 Task,验证 Verifier 仍可运行;报告时把异常、部分 Reward 和最终失败原因分开。