Self-Harness: Harnesses That Improve Themselves
- 原文:本地 PDF
- 在线版本:arXiv
- 项目仓库:qzzqzzb/Self-Harness
- 本地代码:prjs/Self-Harness
- 版本:v1,2026-06-08
- 阅读状态:阅读中
一句话理解
Self-Harness 固定模型参数,让目标模型根据自身执行轨迹中反复出现的失败机制,提出对当前 Harness 的小幅修改,并且只有修改通过 held-in 与 held-out 回归测试后才予以保留。
它改进的是模型外部的执行协议,不是模型权重。
理解大纲
1. 论文要解决的问题
Agent 的行为由两部分共同决定:
$$
\text{Agent behavior}
=
\text{base model}
+
\text{harness}
$$
论文中的 Harness 是模型外部的非参数脚手架,包括:
- System prompt 和动态指令。
- 工具、工具适配器和工具使用策略。
- Memory 与 state management。
- Verification rules。
- Runtime policy、失败恢复与 orchestration。
- Subagent、skill 和 middleware 等结构。
不同模型具有不同的工具使用习惯、错误模式和指令敏感性,因此同一套 Harness 不一定适合所有模型。论文提出的问题是:
不依赖人工工程师或更强的外部 Agent,目标模型能否参与改进自己正在使用的 Harness?
2. 三种 Harness 改进范式
论文区分:
- Human Harness Engineering:人工观察失败并修改 Harness。
- Meta-Harness:更强的外部 Agent 优化目标 Agent 的 Harness。
- Self-Harness:目标模型根据自身行为证据,提出对自身 Harness 的修改。
Self-Harness 的边界是:模型 $M$、Evaluator $E$、任务协议和工具集合保持固定,只允许修改预先声明的 Harness 表面。
3. 基本数学对象
- $M$:固定语言模型。
- $h_t$:第 $t$ 轮使用的 Harness。
- $x_i$:一个任务实例。
- $\tau_i$:执行轨迹,包括消息、工具调用和 verifier 结果。
- $y_i$:Agent 的最终输出。
- $E$:固定 Evaluator。
- $z_i=E(x_i,\tau_i,y_i)$:任务结果,例如 pass 或 fail。
- $r_i=(x_i,\tau_i,y_i,z_i)$:一次完整运行记录。
- $D_{\mathrm{in}}$:向弱点分析阶段暴露执行轨迹的 held-in 集合。
- $D_{\mathrm{ho}}$:不向 proposer 暴露轨迹、只用于晋升门禁的 held-out 集合。
运行关系可以写成:
$$
(\tau_i,y_i)=\operatorname{Run}(M,h_t,x_i)
$$
$$
z_i=E(x_i,\tau_i,y_i)
$$
被持续更新的是:
$$
h_0\rightarrow h_1\rightarrow\cdots\rightarrow h_T
$$
模型参数始终不变。
4. 第一阶段:Weakness Mining
首先在 $D_{\mathrm{in}}$ 上运行当前 Harness $h_t$,形成:
$$
R_t={r_i}{i=1}^{|D{\mathrm{in}}|}
$$
只保留失败记录:
$$
F_t={r_i\in R_t\mid z_i=\operatorname{fail}}
$$
对每条失败记录构造失败签名:
$$
\phi(r_i)=(c_i,q_i,m_i)
$$
- $c_i$:Verifier 最终拒绝的直接原因。
- $q_i$:相关 Agent 行为在失败中的因果地位。
- $m_i$:轨迹暴露出的可复用行为机制。
采用完全相同的签名聚类:
$$
C_{\phi}
=
{r_i\in F_t\mid\phi(r_i)=\phi}
$$
每个 cluster 记录规模、代表任务、共同轨迹症状、Verifier 证据和推断出的 Agent 机制。最后形成 Evidence Bundle:
$$
B_t=\operatorname{BuildEvidenceBundle}(R_t)
$$
重点不是把所有 timeout 归为一类,而是区分造成 timeout 的不同机制,例如无限探索、重复失败命令或没有及时创建交付文件。
5. 第二阶段:Harness Proposal
论文让同一个固定模型 $M$ 在当前 Harness $h_t$ 下切换到 proposer 角色。它获得:
- 当前 Harness 的可编辑表面。
- $B_t$ 中的失败模式。
- 应当保留的成功行为。
- 过去已经尝试过的修改摘要。
模型并行产生 $K$ 个候选:
$$
\mathcal P_t
=
{(\Delta_j,a_j)}_{j=1}^{K}
$$
- $\Delta_j$:Harness 修改算子。
- $a_j$:Audit record,说明目标失败、修改表面、预期行为和回归风险。
- $h_t^{(j)}=\Delta_j(h_t)$:应用修改后的候选 Harness。
提案原则是:
- 不同候选之间保持多样性。
- 单个候选内部保持最小修改。
- 修改必须对应有证据且可由 Harness 解决的失败机制。
- 不允许借机重写整个控制架构。
6. 第三阶段:Proposal Validation
定义 Harness $h$ 在两个 split 上通过的任务数:
$$
P_{\mathrm{in}}(h),
\qquad
P_{\mathrm{ho}}(h)
$$
候选相对当前 Harness 的变化为:
$$
\Delta_{\mathrm{in}}^{(j)}
=
P_{\mathrm{in}}(h_t^{(j)})-P_{\mathrm{in}}(h_t)
$$
$$
\Delta_{\mathrm{ho}}^{(j)}
=
P_{\mathrm{ho}}(h_t^{(j)})-P_{\mathrm{ho}}(h_t)
$$
接受条件是:
$$
\Delta_{\mathrm{in}}^{(j)}\ge 0,
\qquad
\Delta_{\mathrm{ho}}^{(j)}\ge 0,
\qquad
\max\left(
\Delta_{\mathrm{in}}^{(j)},
\Delta_{\mathrm{ho}}^{(j)}
\right)>0
$$
含义是:
- 至少一个 split 变好。
- 另一个 split 不能变差。
- 只提高总分但牺牲某个 split 的候选也要拒绝。
若没有候选通过:
$$
h_{t+1}=h_t
$$
若多个兼容候选通过,则合并 accepted edits,形成 $h_{t+1}$。
7. Algorithm 1 的状态转移
一轮循环可以概括成:
$$
h_t
\xrightarrow{\operatorname{Evaluate}}
R_t
\xrightarrow{\operatorname{Mine}}
B_t
\xrightarrow{\operatorname{Propose}}
{h_t^{(j)}}{j=1}^{K}
\xrightarrow{\operatorname{Validate}}
h{t+1}
$$
完整算法执行 $T$ 轮,最终返回:
$$
h_T
$$
这不是任意自我改写,而是 evidence-driven、validation-gated 的有界状态迁移。
8. 实验设置
- Benchmark:Terminal-Bench-2.0。
- 原基准包含 89 个任务,论文使用固定的 64 个任务子集。
- 排除依赖不稳定外网资源以及初始 Harness 不支持的多模态任务。
- 每个任务在全新容器环境中启动。
- 每个候选 Harness 通常重复运行两次。
- 初始 Harness:极简 DeepAgent 配置,只有短 system prompt、文件和 shell 工具以及声明好的可编辑接口。
- 模型:MiniMax M2.5、Qwen3.5-35B-A3B、GLM-5。
9. 主要结果
| 模型 | Held-in Pass | Held-out Pass |
|---|---|---|
| MiniMax M2.5 | 43.0% → 50.0% | 40.5% → 61.9% |
| Qwen3.5-35B-A3B | 15.1% → 36.0% | 23.8% → 38.1% |
| GLM-5 | 47.7% → 57.0% | 42.9% → 57.1% |
论文报告最大绝对提升为 21.4 个百分点,最大相对提升为 138%。
10. 学到的修改具有模型特异性
MiniMax M2.5:
- 更早创建任务要求的输出文件。
- 正确形成结构化工具内容。
- 长时间工具调用后主动重定向执行。
Qwen3.5:
- 预检依赖和 import。
- 避免重复执行完全相同的失败命令。
- 打断只探索、不实现的循环。
- 工具错误后优先恢复 Verifier 所需文件。
GLM-5:
- 让 PATH 和已安装工具跨 shell session 持久化。
- 约束大型外部下载或计算。
- 更快从探索转向实现、测试和产物检查。
三者的共同主题是提高任务要求产物的可靠交付,但具体干预方式不同。
11. 与 STOP、MCE 的区别
- STOP:用 Meta-Utility 评价候选 Improver,让 Improver 的代码跨轮改写自身。
- MCE:外层进化 Context Engineering Skill,内层根据 Skill 优化 Context function。
- Self-Harness:固定同一个目标模型,从自己的失败轨迹中提出对 declared harness surfaces 的修改,再通过回归测试决定是否晋升。
Self-Harness 的突出特点不是搜索范围更大,而是修改有证据、范围受限、结果可审计并有非退化门禁。
12. 论文能支持的结论
论文支持的是:
在固定 Verifier、有限任务集和有界 Harness 编辑空间内,同一个模型可以根据自身失败证据,参与搜索更适合自己的执行协议。
论文没有证明:
- 模型可以开放式、无限地改进自身。
- 模型能力或参数发生了改进。
- Self-Harness 能泛化到所有 Agent 环境。
- 每一个 accepted edit 都具有跨 Benchmark 的普适性。
13. 值得继续追问的问题
- Held-out split 每轮都参与 promotion gate,因此更接近验证集;论文没有第三个完全不参与选择的最终测试集。
- Weakness Mining 中的因果归因和 failure signature 具体怎样实现,是否自身也依赖较强的判断能力?
- Algorithm 1 只显式验证各个候选,再把 compatible edits 合并;合并后的组合没有同轮回归门,而且 compatible 没有形式化定义,交互效应如何控制?
- 为什么使用通过任务数,而不是置信区间或显著性检验?每个候选两次重复是否足够?
- 没有与人工优化、Meta-Harness、随机搜索等优化器直接比较,收益中有多少来自 Self-Harness 特有设计?
- Failure clustering、并行提案、最小修改约束和 held-out gate 各自贡献多少?论文缺少组件消融。
- 64 个 Terminal-Bench 任务上学到的规则,会不会把 Benchmark 特有模式写进 Harness?
- v1 没有披露 proposal width $K$、明确的轮数 $T$ 配置、split 的任务数与清单、随机种子、置信区间以及完整搜索成本。
- Proposal 的 diverse/minimal 只是文字约束,没有候选距离或 edit-size 指标;该约束如何稳定执行?
- arXiv v1 和论文正文没有反链代码;团队公开投稿文章将
qzzqzzb/Self-Harness列为项目地址,但仓库本身没有声明 official,且缺少依赖锁文件和完整复现说明。
阅读问答
Q1:先怎么理解整篇论文?
先抓住三个层次:
- 优化对象是 Harness $h$,不是模型 $M$。
- 优化信号来自聚类后的失败轨迹,而不是 proposer 对修改的主观判断。
- 修改只有同时满足“至少一个 split 变好、另一个不退化”的回归门禁才进入下一版 Harness。
后续问题继续追加在本节。
Q2:Harness 是什么?是否可以理解成包含 Memory、Skill 和规约的 Agent 构建方式?
这个理解基本正确。更精确地说,Harness 是固定模型外部、负责把模型组织成可运行 Agent 的非参数执行脚手架:
$$
\text{Agent system}
=
\text{Model }M
+
\text{Harness }h
+
\text{Environment}
$$
对于任务 $x$:
$$
(\tau,y)=\operatorname{Run}(M,h,x)
$$
Harness $h$ 决定模型怎样从任务产生整条轨迹 $\tau$ 和结果 $y$,包括:
- 模型每次调用前收到哪些 system prompt、规约和动态 Context。
- 暴露哪些工具、API、Skill、Subagent 以及权限。
- Memory 如何保存、检索、加载和压缩。
- 多轮调用如何编排,何时重试、分解、停止或切换策略。
- 工具错误、超时和缺失产物怎样恢复。
- 结果如何验证,结束前必须执行哪些检查。
- Token、工具调用次数和运行时间等预算如何控制。
因此 Memory、Skill 和规约通常都是 Harness 的组成部分,但 Harness 比它们更大:它还包括把这些组件组合起来并在运行时执行的代码、配置和控制逻辑。
需要区分:
- Model:参数化的预测能力,权重属于模型,不属于 Harness。
- Context:某一次模型调用实际看到的内容,是 Harness 运行后产生的输入之一。
- Skill:可按需加载的能力说明、知识和操作流程,是 Harness 可以管理的一类组件。
- Memory:跨步骤或跨任务保存与取回信息的机制,也是 Harness 的一个子系统。
- Harness:管理上述组件并控制整条 Agent 执行轨迹的运行层。
- Agent architecture:更宽泛的设计概念;Harness 是其中真正落地并驱动模型运行的可执行部分。
论文 Figure 3 的初始 Harness 具体声明了 system prompt、memory sources、subagents、skills、bootstrap/execution/verification/failure-recovery instructions 和 runtime-control policy。Self-Harness 修改的正是这些声明好的表面,而不是模型权重。
Q3:对于单个 Agent,也存在 Harness 吗?
存在。Harness 不以多 Agent 为前提。对于一个最小的工具型 Agent,仍然需要运行代码完成:
$$
\text{任务输入}
\rightarrow
\text{构造模型 Context}
\rightarrow
\text{调用模型}
\rightarrow
\text{解析 Tool Call}
\rightarrow
\text{执行工具并回填观察}
\rightarrow
\text{继续或停止}
$$
负责上述循环的代码、Prompt、工具 schema、历史管理、错误处理和停止条件,就是该单 Agent 的 Harness。Subagent 或多 Agent orchestration 只是 Harness 可选的扩展能力。
需要区分:
- 只有一次输入输出的裸模型调用,可以不称为 Agent,其外围驱动也可能非常薄。
- 一旦系统让模型持续观察、调用工具、更新状态并决定下一步,就已经存在某种 Harness,即使它只有几十行代码。
- 多 Agent 系统是在 Harness 中进一步加入 Agent 创建、任务分配、通信和结果聚合机制。
论文使用的初始 DeepAgent 就是单 Agent Harness:它只有短 system prompt、默认文件和 shell 工具,subagents=[]、skills=[],但仍然具有 Agent 执行循环。因而“没有 Subagent”不等于“没有 Harness”。
在工程实现中,Harness 经常被封装在名为 Agent 的类或框架内部,所以代码表面上看不见独立的 Harness 对象;这是实现封装,不代表概念上的运行层不存在。
Q4:Agent 是否就是 Model、Harness 和 Environment 在某个模块上的子集?
接近,但更严格的边界是:
$$
\text{Agent }A=\operatorname{Instantiate}(M,h)
$$
$$
\text{Agent–Environment System}=A+\operatorname{Environment}
$$
Environment 通常不是 Agent 本体的一部分,而是 Agent 观察和作用的外部对象。交互循环是:
$$
o_t
\xrightarrow{A=(M,h)}
a_t
\xrightarrow{\operatorname{Environment}}
(s_{t+1},o_{t+1})
$$
- Model $M$ 提供推理与生成能力。
- Harness $h$ 把历史和观察组织成模型输入,把模型输出翻译成 Action,并控制工具循环、状态、验证和停止。
- Environment 保存外部状态,接收 Action,并返回新的 Observation。
工具需要按边界拆开理解:工具的 schema、调用策略、权限和 adapter 通常属于 Harness;Shell、文件系统、数据库或远程服务的真实状态通常属于 Environment。
如果讨论特定业务模块或任务域 $d$,可以写成:
$$
A_d
=
\operatorname{Instantiate}
\left(M,h_d,\operatorname{toolScope}_d,\operatorname{permissionScope}_d\right)
$$
$A_d$ 更适合称为通用 Agent 系统在领域 $d$ 中的配置实例或运行切片,而不是集合论意义上的“子集”。它复用同一个模型,但具有该领域自己的 Prompt、Memory、Skill、工具范围和权限。
在 Self-Harness 论文中,可以理解为:
$$
A_t=(M,h_t)
$$
Terminal-Bench 容器是 Environment。每轮保持 $M$、Environment、Evaluator 和任务协议不变,只把 $h_t$ 更新为 $h_{t+1}$;因此模型没变,但 Agent 的运行行为发生了变化。
为避免歧义,前文“Agent system = Model + Harness + Environment”应理解为完整的 Agent–Environment 运行系统,而不是严格的 Agent 本体定义。
Q5:是否可以把除 Model 以外的所有部分都理解为 Harness?
可以作为第一层近似:
$$
\text{Agent}\approx\text{Model}+\text{Harness}
$$
但不能把完整系统里所有非模型组件都归入 Harness。更准确的判定标准是:
某个非参数组件如果负责控制固定模型怎样观察、记忆、行动、验证、恢复或停止,它通常属于 Harness;如果它是 Agent 操作的外部对象、任务来源或裁判,则不属于 Harness。
| 组件 | 是否通常属于 Harness | 原因 |
|---|---|---|
| System prompt、规约 | 是 | 控制模型行为 |
| Context 构造与历史压缩 | 是 | 决定模型看到什么 |
| Memory 检索与写入机制 | 是 | 控制信息怎样跨步骤保存 |
| Skill loader | 是 | 决定何时加载能力说明 |
| Tool schema、adapter、调用策略 | 是 | 决定模型可执行哪些 Action |
| 重试、超时、预算、停止规则 | 是 | 控制执行循环 |
| Verification 与失败恢复逻辑 | 是 | 控制 Agent 怎样自检和纠错 |
| 文件系统、数据库、外部 API 的真实状态 | 否 | 属于 Environment |
| 用户给出的任务实例 | 否 | 属于 Task input |
| Benchmark Verifier / Evaluator | 通常否 | 是外部裁判 |
| 模型权重与网络结构 | 否 | 属于 Model |
Tool 需要拆成两部分:工具的 schema、权限和调用 glue code 属于 Harness;工具实际操作的服务和状态属于 Environment。
Self-Harness 论文的优化对象还更窄:它不是修改所有非模型代码,而只修改 Harness 中预先声明的 editable surfaces。Environment、Evaluator、任务划分、模型参数以及 Benchmark 协议都固定。
Q6:Trajectory 一般怎样记录?
Trajectory 是一次 Agent episode 中按因果和时间顺序发生的可观察事件序列:
$$
\tau
=
(o_0,a_0,o_1,a_1,\ldots,o_T,y)
$$
- $o_t$:Agent 在第 $t$ 步得到的 Observation。
- $a_t$:Agent 在第 $t$ 步执行的 Action,例如文本回复或 Tool Call。
- $y$:最终输出。
LLM Agent 中通常需要记录:
- Task start:任务 ID、输入、环境版本和 Harness 版本。
- Model request:模型名称、可见 messages、工具 schema 和采样参数。
- Model response:可见文本、Tool Call、token usage 和 finish reason。
- Tool execution:tool name、call ID、参数、开始/结束时间和权限信息。
- Tool result:stdout/stderr、exit code、返回值、耗时、超时或截断状态。
- State event:Memory 读写、Context 压缩、Skill 加载和 Subagent 创建。
- Error/recovery:异常、重试、策略切换和预算变化。
- Finalization:最终答案、产生的 artifacts 和停止原因。
- Evaluation:Verifier 结果、score 和失败原因。
工程上通常使用 JSONL 或 tracing span 记录,每个事件具有统一 envelope,例如:
{
"trace_id": "tr-42",
"span_id": "sp-7",
"parent_span_id": "sp-3",
"seq": 12,
"timestamp": "2026-07-23T15:20:00Z",
"event_type": "tool.result",
"actor": "agent",
"payload": {
"call_id": "call-9",
"tool": "shell",
"exit_code": 0,
"duration_ms": 184
}
}
trace_id 关联整次任务,span_id 和 parent_span_id 表示调用关系,seq 保留逻辑顺序。单 Agent 串行运行时可以看成列表;存在并行工具或 Subagent 时,整体更接近一棵树或 DAG。
通常不会把所有大文件或超长工具输出直接塞入 trace,而是记录 artifact URI、摘要、hash 和截断标记。还应记录模型、Prompt、Harness 和 Environment 版本,才能复现同一运行。
安全上需要对 API key、Token、Cookie、个人信息和业务敏感字段进行脱敏。Trajectory 记录的是系统可观察事件,不应假设能够取得或保存模型隐藏的内部 Chain-of-Thought。
Self-Harness 中一次运行记录为:
$$
r_i=(x_i,\tau_i,y_i,z_i)
$$
其中 $x_i$ 是任务,$\tau_i$ 记录 messages、Tool Calls 和 Verifier evidence,$y_i$ 是最终输出,$z_i$ 是 pass/fail。论文随后从失败记录中提取 failure signature,用于 Weakness Mining。
Q7:论文是否有 GitHub?本地能否运行?
找到高可信论文项目仓库:
https://github.com/qzzqzzb/Self-Harness
本地以 Git submodule 固定到:
prjs/Self-Harness
commit 2720dbb3f52283684f4b85a1065d642df1779dd8
官方性需要保守表述:仓库标题、arXiv ID、论文图片、实验结果和目录结构均与论文一致,论文团队的公开投稿文章也把它列为项目地址;但 arXiv v1、论文正文与作者主页没有反向链接,仓库 README 也没有使用 official 字样。
2026-07-24 使用 Python 3.12.13 完成最小运行验证:
- 5,823 行 Python 源码全部通过
compileall。 - Acceptance、Proposer、Materializer、Harbor Eval、Workflow 五个 CLI 均能正常解析
--help。 - 用两条相同 failure signature 的合成失败记录执行 Weakness Mining,正确聚成一个大小为 2 的 cluster。
- 构造两个 Proposal route,成功生成 3,064 字符的 proposer prompt。
- 用合成结果执行 Acceptance Gate:train pass rate 增加
0.25,held-out 不变,结果为accepted: improved train with no split drops。
完整 Terminal-Bench-2.0 实验尚不能按仓库直接复现,原因是:
- 仓库没有
requirements.txt、pyproject.toml、lockfile 或版本化安装说明。 - 当前环境缺少
deepagents和harbor。 - 示例配置依赖仓库外部的 eval project、Docker/Harbor 任务环境和模型服务。
- 论文中的本地 Qwen3.5-35B-A3B 配置使用四张 NVIDIA H200。
因此当前结论是:仓库核心的 diagnosis、proposal construction 和 acceptance 逻辑能够本地执行;论文的完整 64-case 模型实验需要额外重建环境,不能把 smoke test 等同于论文结果复现。