harness_evolve/notes/ref17_self-harness.md

Self-Harness: Harnesses That Improve Themselves

一句话总结:让一个固定的(不改权重的)LLM Agent,用它自己的执行轨迹挖出自己特有的失败模式,再以"有界、最小"为约束提出针对性的 harness 修改,最后用回归测试(held-in 不降、held-out 不降)当准入门——从而既不靠人类工程师、也不靠更强的外部 Agent,就把自己的 harness 越改越好。


TL;DR 速览

tags: #harness工程 #自我改进 #self-improving-agents #terminal-bench #模型专属优化 #regression-gated

related: [[ref09_meta-harness]](同题对照:外部 vs 自我)· [[ref07_ace-agentic-context-engineering]](Reflexion/ACE 谱系)· [[ref16_stop-self-taught-optimizer]] · [[ref13_adas-automated-design-agentic-systems]] · [[ref23_darwin-godel-machine]] · [[ref11_scientistone]](AI Scientist 谱系)


摘要

LLM Agent 的表现由基座模型和"介导它与环境交互的 harness"共同塑造。因为不同模型行为不同,有效的 harness 设计天然是模型专属的。然而 Agent harness 仍主要由人类专家工程——这条范式随着现代 LLM 越来越多样、迭代越来越快而扩展性很差。我们提出 Self-Harness:一个 LLM Agent 改进它自己运行所依赖的 harness,不依赖人类工程师或更强的外部 Agent。

三个不同家族的模型(MiniMax M2.5、Qwen3.5-35B-A3B、GLM-5)在 Terminal-Bench-2.0 上,held-out pass rate 分别从 40.5%→61.9%、23.8%→38.1%、42.9%→57.1%。定性分析进一步表明:Self-Harness 不是简单加通用指令,而是把模型专属的弱点变成具体、可执行的 harness 改动


1 介绍:harness 是"模型专属"的,人力路线不 scale

论文的出发点很清晰:Agent 不只由基座模型塑造,也由 harness 塑造——同一个基座模型,换个 harness,表现可以差很多。而关键洞察是:不同模型有不同的行为模式、工具使用习惯、错误模式和 prompt 敏感性,所以对模型 A 好用的 harness 对模型 B 可能次优。于是"给每个新模型手工重设计一套模型专属 harness"随模型爆发而变得昂贵、不可持续。

[!TIP] 本文对 harness 的定义(比 ref09 更"系统层") Self-Harness 把 harness 定义为治理"固定语言模型如何被部署成 Agent"的非参数化支架(non-parametric scaffolding),包括:系统 prompt、可用工具、记忆与状态管理机制、验证规则、权限策略、适配器、运行时机制、失败恢复流程等。

关键论点:很多重要的 Agent 失败是这一层的失败,而非"某次模型回答"的失败——例如:没检查产物就报告成功、反复重试无效动作、在长上下文里丢掉"真相来源"、缺少一个恢复动作。这些行为源自"指令 × 观察 × 工具 × 运行时控制"的相互作用,所以改进它们需要改的不只是 prompt 文本。这解释了为什么要在"harness 代码/配置"这一层做优化,而不是只调 prompt。

三种范式(Figure 1):这张图是全文的定位图。

Figure 1: 三种 harness 改进范式

Figure 1 逐格解读: - 左「Human Harness Engineering」:人类工程师拿着工具,手动修改 Agent 的 harness——现状范式,效果好但不 scale。 - 中「Meta-Harness」:一个更强的外部 Agent(图里更大、更"高级"的机器人)指导改进一个更弱的目标 Agent 的 harness。对应 [[ref09_meta-harness]]。 - 右「Self-Harness」:Agent 对着镜子改进自己的运行 harness——本文范式。镜子的隐喻很贴切:提议者就是被评估的那个模型本身。

[!NOTE] 本文与 Meta-Harness 的分工,作者说得很直白:不同于"用更强的外部 Agent 去改进更弱者"的近期做法,Self-Harness 要把这个改进闭环内化到目标 Agent 自身。这样做能减少对外部指导的依赖——外部指导可能昂贵、对前沿模型不可得、或与目标模型的失败模式不匹配。用柏格森的话说,这指向一种"自我创造"的技术类比:系统不只是被外部改变,而是持续地"go on creating itself"。

三阶段闭环(下节详述):Weakness Mining → Harness Proposal → Proposal Validation。关键约束是每个提案必须"有界且最小"、只有通过 held-out 回归测试才被提升。


2 相关工作:把 Self-Harness 放进"自我改进"谱系

[!TIP] ① 从 prompt 到 agent harness - Prompt / Context Engineering:固定模型可被指令、示范、检索证据、记忆、工具状态、动态输入所引导。 - ReAct [29]:推理与行动交替(reasoning + acting),是"把控制面从单次输入扩展到执行环境"的开山之作。 - SWE-agent [28] / Claude Code / OpenHands [24] / SemaClaw [36]:展示这些"外围机制"如何塑造长时程 Agent 行为与软件工程表现。

[!TIP] ② 自我改进的 Agent 与自动 Agent 设计(本文最近的邻居) - Reflexion [23]:把"口头反馈(verbal feedback)"存起来供后续尝试用——"言语强化学习"。但改进的对象是响应策略/记忆,不是被声明的 harness 状态。 - ACE(Agentic Context Engineering)[34]:为后续模型调用进化上下文。见 [[ref07_ace-agentic-context-engineering]]。 - STOP(Self-Taught Optimizer)[31]:研究代码生成的递归自我改进。见 [[ref16_stop-self-taught-optimizer]]。 - ADAS [3]:在 Agent 设计空间里搜索;语言 Agent = 可优化的图 [37]Meta-Harness [5] 用历史候选的源码/分数/轨迹直接优化 harness 代码。见 [[ref13_adas-automated-design-agentic-systems]]、[[ref09_meta-harness]]。

共同点:这些方法证明"固定模型能从累积反馈获益"。Self-Harness 的差异:前两类改进的对象通常是响应/记忆/上下文/生成的程序;后一类把改进框定为外部搜索/优化过程。而 Self-Harness 研究的是一个更窄、更受控的设定——被评估的模型在它当前的 harness 下,提出一个有界的候选改动去改治理自己未来行为的 harness。

[!TIP] ③ 科学发现 / 自演化 Agent 系统 AI Scientist [11] / AI Scientist-v2 [27]、AlphaEvolve [15]、Alita [19]、Gödel Agent [30]、Darwin Gödel Machine [33] 等,自动化了更广的研究 / 算法设计 / 能力扩张闭环。见 [[ref11_scientistone]]、[[ref20_alphaevolve]]、[[ref23_darwin-godel-machine]]。Self-Harness 在精神上最接近这条自我改进线,但刻意收窄到受控设定:只问"同一固定模型能否提出一个有界的 harness 改动",而非开放式自我改进。


3 方法:三阶段"提议—评估—接受"闭环

3.1 形式化设定

\(M\) 为固定语言模型,\(h\) 为 Agent harness。给定任务实例 \(x\),在 harness \(h\) 下运行 \(M\) 产生执行轨迹 \(\tau\) 和输出 \(y\)\(\tau\) 记录消息、工具调用、verifier 结果);评估器 \(E\) 把 (任务, 轨迹, 输出) 映射到行为结果(如 pass/fail)。\(M\)\(E\) 全程冻结,只有 harness 是被改进的对象。于是 Self-Harness 在一条 harness 谱系 \(h_0, h_1, \dots\) 上操作,每次转移都是对执行协议的一次有界编辑,而非模型权重更新。

Figure 2: 一次 Self-Harness 优化闭环

Figure 2 三阶段逐块解读: - 顶部蓝框「Weakness Mining」:用当前 harness \(h_t\) + 固定模型跑任务 → 收集执行轨迹 → 聚类成"verifier 层锚定的失败模式"(图里 Missing Validation / Corrupted Tool 两簇)。 - 中间绿框「Harness Proposal」:把同一个固定模型(图中「\(h_t\) as Proposer」)拿来当提议者,用挖出的失败模式(W1 Missing Validation / W2 Unlimited Exploration / W3 Corrupted Tool Call)生成有界候选编辑(→ Validate before Conclude / Loop Breaker Middleware / Tool Policy Update)。 - 底部橙框「Proposal Validation」:每个候选过回归测试(held-in + held-out),做"提升/拒绝"决策。绿色"Accept - Update Harness"→ 合并进 \(h_{t+1}\);红色"All Reject - No Update"→ 保持 \(h_t\) 不变(左侧回边)。 - 贯穿全程:模型权重与评估器不变,只改外围 harness。

3.2 Weakness Mining:把失败聚成"可复用机制"

在第 \(t\) 轮,用 \(M\) 在 held-in split \(D_{in}\) 上跑 \(h_t\),每个任务得到轨迹记录 \(r_i = (x_i, \tau_i, y_i, z_i)\)\(z_i\) = pass/fail)。因为 \(M\)\(E\) 固定,跨轮记录的变化就能归因到 harness 的变化。只取失败子集 \(F_t = \{r_i \mid z_i = \text{fail}\}\),然后按失败签名聚类:

\[ \phi(r_i) = (c_i,\ q_i,\ m_i), \qquad C_\phi = \{\, r_i \in F_t \mid \phi(r_i) = \phi \,\} \tag{1} \]
符号 含义
\(c_i\) terminal verifier-level cause:verifier 最终拒绝这次运行的表层原因(如 timeout、缺产物、断言失败)
\(q_i\) causal status:相关 agent 行为在轨迹里的因果地位(它是不是导致失败的真正原因)
\(m_i\) abstract agent mechanism:轨迹暴露出的、可复用的抽象 agent 行为机制

[!TIP] 为什么要三元签名而不是只按 verifier 结果聚类?(讲透 + 举例) 关键设计动机:防止把"表层症状"和"可复用的失败机制"混为一谈举例:两次运行都以"缺少产物文件"(同一个 \(c_i\) = missing artifact)失败,但底层 agent 行为可能完全不同—— - 运行 A:agent 陷入无尽探索,从没开始写产物 → 机制 \(m\) = "exploration loop"; - 运行 B:agent 写了产物,但工具报错后把它删了 → 机制 \(m\) = "failure-recovery deletes artifact"。

这两者需要不同的 harness 修改(A 需要"循环打破器",B 需要"工具错误后拉回缺失产物的中间件")。只按 \(c_i\)(都=缺产物)聚类会把它们错误地并成一簇、逼出一个粗糙补丁。三元签名 \((c,q,m)\)精确一致才聚在一起,于是聚类是确定性的、evaluator 锚定的,目标是"聚合那些大概能用同一个 harness 干预的失败"。

每个簇 \(C_\phi\) 被构造成一个结构化失败模式(含簇大小、代表性实例、共享症状、verifier 证据、推断出的 agent 机制),并按"支持度 + 可操作性"排序。本阶段输出证据包 \(B_t\)——注意 \(B_t\) 只描述失败、不规定该怎么改(把"评估器"和"优化器"解耦),让提议者去针对一个具体可复用弱点,而非打一个"timeout"这样的粗糙结果补丁。

3.3 Harness Proposal:多样但最小

给定 \(B_t\),让同一个固定模型 \(M\)、在当前 harness \(h_t\)扮演提议者(不是一个能无限制访问搜索空间的外部优化器)。给它一个有界的提案上下文:当前 harness 的可编辑面(editable surfaces)、verifier 锚定的失败模式、应当保留的通过行为、以及此前尝试过的编辑摘要。它并行生成 \(K\) 个彼此不同的提案:

\[ P_t = \{(\Delta_j,\ a_j)\}_{j=1}^{K}, \qquad h_t^{(j)} = \Delta_j(h_t) \tag{2} \]

其中 \(\Delta_j\) 是把当前 harness 映射到候选 harness 的一次编辑,\(a_j\)审计记录(描述它瞄准的失败模式、编辑的 harness 面、预期行为效果、回归风险)。约束是全文的灵魂:

[!IMPORTANT] 分支之间鼓励多样(diversity across branches),每个分支内部强制最小(minimality within each branch)。 - 多样:不同提案可瞄准不同失败机制、选不同 harness 面、表达不同的改进假设;候选必须实质不同(不能只是换个措辞重述同一簇/面/机制)。 - 最小:每个编辑只能改"解决它选定机制所必需的那一面",保留无关行为,不做对 Agent 控制架构的大范围重写

提议者还要先做可寻址性(addressability)判断:一个失败簇只有"既有证据支持、又能被某个可编辑 harness 面合理解决"时才被选为目标——因为有些簇反映的是任务本身难 / 结果不稳 / 模型能力上限,而非"缺一条执行规则",这类会被排除而不是硬塞进补丁。

3.4 Proposal Validation:保守的非回退准入

每个候选 \(h_t^{(j)} = \Delta_j(h_t)\) 都当作新 harness 变体,在 held-in \(D_{in}\) 和 held-out \(D_{ho}\) 上评估。设 \(P_{in}(h)\)\(P_{ho}(h)\) 为 harness \(h\) 在两个 split 上的通过任务数,定义相对当前 harness 的分项改进并给出准入规则:

\[ \Delta^{(j)}_{in} = P_{in}(h_t^{(j)}) - P_{in}(h_t), \quad \Delta^{(j)}_{ho} = P_{ho}(h_t^{(j)}) - P_{ho}(h_t) $$ $$ \textbf{接受当且仅当:}\quad \Delta^{(j)}_{in} \ge 0 \ \ \wedge\ \ \Delta^{(j)}_{ho} \ge 0 \ \ \wedge\ \ \max\!\big(\Delta^{(j)}_{in},\, \Delta^{(j)}_{ho}\big) > 0 \tag{3} \]

[!TIP] 把准入规则 (3) 讲透 + 举例 口语版:"两个 split 都不许降,且至少有一个要涨。" 这是一个保守的非回退(non-regressive)准则。 - 为什么不用"总通过数增加"? 因为那会允许"held-in +3、held-out −2 → 净 +1"这种用泛化换过拟合的编辑通过。规则 (3) 明确拒绝任何一个 split 的下降,哪怕总数变多。 - 举例:某编辑 held-in +2、held-out 0 → 接受\(\ge0,\ge0\),max>0);另一编辑 held-in +4、held-out −1 → 拒绝(held-out 降了)。 - 随机性处理:评估有随机性时重复评估并对聚合通过数套同一规则,降低"因单次好运被提升"的概率。 - 此外,"没改任何可编辑面"或"在拿到有效评估前就执行失败"的提案也会被拒。每个候选都记录改动面、分项结果、重复次数、提案摘要、accept/reject 决策——让 harness 谱系的每一步转移都可审计

多个兼容候选同轮通过则合并进下一版 harness;被拒的候选留日志但不改动 active harness。

[!NOTE] Algorithm 1|Self-Harness(伪代码复述) 输入: 固定模型 M, 初始 harness h0, held-in Din, held-out Dho, 评估器 E, 提案宽度 K, 轮数 T for t = 0..T-1: (Pin, Pho, R_t) ← Evaluate(M, h_t, Din, Dho, E) B_t ← BuildEvidenceBundle(R_t) # 来自 held-in、verifier 锚定的失败 P_t ← ParallelPropose(M, h_t, B_t, K) # K 个 (Δ_j, a_j) A_t ← ∅ for (Δ_j, a_j) in P_t: h_t^(j) ← Δ_j(h_t) 评估 h_t^(j) 得 Δin, Δho if Δin≥0 and Δho≥0 and max(Δin,Δho)>0: # 准入规则 A_t ← A_t ∪ {…}; Accept(Δ_j) else: Reject(Δ_j) h_{t+1} ← (h_t if A_t=∅ else MergeAccepted(h_t, A_t)) return h_T


4 实验

4.1 设置

# Figure 3:初始 harness 的可编辑接口(Self-Harness 只能改这些 build_* 面)
def build_system_prompt() -> str:
    return """You are running inside a Terminal Bench 2 Harbor task environment.
    Use the built-in filesystem and shell tools to inspect the workspace, make
    concrete edits, and verify outcomes against the actual task environment.
    Do not assume synthetic datasets, domain-specific tools, or hidden fixtures
    unless you discover them in the repo or runtime.""".strip()

def build_memory_sources()  -> list[str]:  return ["/AGENTS.md"]
def build_subagents()       -> list[dict]: return []      # ← 后来 Qwen3.5 往这里加了 subagent
def build_skills()          -> list[str]:  return []      # ← 后来加了 dependency-verifier skill
def build_bootstrap_instruction()      -> str: return "Start by inspecting the workspace and identifying the smallest relevant edit surface."
def build_execution_instruction()      -> str: return "Prefer concrete repo changes over generic advice, and keep edits tightly scoped to the task."
def build_verification_instruction()   -> str: return "Before concluding, verify the result with the most targeted command, file read, or test you can run."
def build_failure_recovery_instruction() -> str: return "If a tool call fails, inspect the error and adapt; do not blindly retry the same action."
def build_runtime_control_policy() -> dict:      # ← 后来 MiniMax 把 enabled 打开、给工具消息设上限
    return {"enabled": False, "max_recent_tool_errors": None,
            "max_total_tool_messages": None, "instruction": None}

4.2 主结果

Figure 4: 三个模型在 Terminal-Bench-2.0 上的 pass rate

Figure 4 + 数据表:三个基座上,提升后的 harness 在 held-in 和 held-out 都不降或提升

模型 held-in 初始→最终 (相对) held-out 初始→最终 (相对)
MiniMax M2.5 43.0 → 50.0 (+16%) 40.5 → 61.9 (+53%)
Qwen3.5-35B-A3B 15.1 → 36.0 (+138%) 23.8 → 38.1 (+60%)
GLM-5 47.7 → 57.0 (+20%) 42.9 → 57.1 (+33%)

[!IMPORTANT] 增益不局限于用来构造证据的 held-in 失败——三个基座在 held-out 上都提升,且没有任何被提升的 harness 让某个 split 变差。 这直接支撑了核心设计目标:提出的编辑应瞄准可复用的执行机制,而非"针对观察到的评估失败"过拟合;回归门确保"在一个 split 上的提升不会以另一个 split 的代价被提升"。Qwen3.5(最弱的基座)相对增益最大(held-in +138%)——越弱的基座、harness 优化空间越大,这和 ref09 的观察一致。

4.3 定性分析:模型专属的、可审计的小编辑

Figure 5(a): MiniMax M2.5 的 Self-Harness 演化轨迹

Figure 5(a) 解读:横轴迭代、纵轴 pass rate。绿圈 = 被接受的候选灰叉 = 被拒的候选(大量被拒——准入门很严)。阶梯线只在被接受时上台阶、被拒时保持水平。可以看到 MiniMax 从 42.2% 起步,经三次被接受的编辑——① Missing artifacts → create output early(尽早创建输出,49.2)、② Stalled tool loops → redirect after 50 tool calls(工具循环卡死则重定向)、③ Schema-invalid content → use correct content tags(用正确的内容标签,51.6)——最终两条被接受的谱系合并成"artifacts + schemas + loops"的 combined harness,达 53.9%。这张图完美体现了"少数几次验证门控的编辑,而非一串一致成功的提案"。

三个模型学到的是不同的东西(这是"harness 天然模型专属"的直接证据):

模型 诊断出的主要弱点 保留下来的 harness 修改
MiniMax M2.5 缺必需产物、schema 非法的工具内容、工具循环卡死 更早创建所需输出;更小心处理结构化工具输出;工具消息超限后重定向(打开 runtime policy 的 max_total_tool_messages
Qwen3.5-35B-A3B 依赖未预检、重复失败命令、无尽探索、工具错误后不产出 依赖预检 skill;循环打破;命令重试纪律;工具错误触发的中间件把 agent 拉回缺失产物;甚至试过 subagent 分解
GLM-5 环境设置跨 shell 命令丢失、探索过久 让 PATH / 安装的工具跨 shell 会话持久并验证可达;探索太久且没产物时转向实现+测试

[!NOTE] 共享主题 + 模型差异:三者的共同主题是产物可靠性(artifact reliability)——M2.5 的"尽早创建输出"、Qwen3.5 的"产物中间件"、GLM-5 的"从探索转向实现",都是在保证"最后给 verifier 留下所需产物"。但具体机制各异,说明同一个初始 harness 对不同模型暴露出不同的执行病理,而 Self-Harness 能据此选出针对性的编辑。值得注意的是它也能引入更宏观的结构机制(subagent 分解、中间件创建),超出局部失败修补。

轨迹级案例(Fig 7/8/9,此处以文字概括):论文用 before/after 轨迹佐证"编辑确实改变了可观察行为": - MiniMax(count-dataset-tokens 任务):初始 harness 下 agent 找到相关元数据后继续探索直到超时、没写答案文件;编辑后 agent 认定 science 子集→算出 token 总数→写 /app/answer.txt→读回验证。 - Qwen3.5(extract-elf 任务):初始 harness 下 agent 建好脚本后陷入反复覆盖/编辑失败、停机前把 /app/extract.js 删了导致 verifier 因缺文件失败;编辑后"工具错误触发的系统 prompt"把它拉回缺失产物、重建脚本、校验 JSON、留下所需文件。 - GLM-5(build-pov-ray 任务):初始 harness 把预算耗在冗长外部下载、后来对失败的 sanity check 强行合理化;编辑后改用有界分阶段操作、先验证外部归档证据、修好失败的渲染检查再收尾。


5 结论


个人思考

⭐ 与 [[ref09_meta-harness]] 的正面对照(本项目最值得写的一组对比)

这两篇是直接对话的(ref17 明确把 ref09 列为"外部 Agent 优化"范式并引用 [5])。放在一起能把"自动 harness 优化"的设计空间讲清楚:

维度 Meta-Harness (ref09) Self-Harness (ref17)
谁来改 更强的外部 Agent(Claude Code + Opus-4.6) 模型自己(同一个固定模型当提议者)
改进对象 任务专用 harness(分类/检索/终端),任务间 reset Agent 运行 harness(DeepAgent 的可编辑面)
提议者看到什么 全部历史:所有候选的源码/分数/轨迹(文件系统,可 grep) 当前轮的证据包(聚类后的失败模式)+ 可编辑面 + 待保留行为
编辑幅度 可到"整程序重写",无 parent-selection 有界、最小,禁止大范围重写控制架构
准入 Pareto 前沿(多目标) 保守非回退门(两 split 都不降、至少一升)
搜索结构 极简外环,把结构下放给 Agent 显式三阶段闭环(挖掘/提案/验证)
基座 一个强基座(Opus/Haiku) 三个较弱/开源基座(M2.5/Qwen3.5/GLM-5)
共同基准 TerminalBench-2 Terminal-Bench-2.0

我的判断:两者不是竞争而是互补的两个极点。Meta-Harness 押注"能力溢出"——用一个很强的外部 Agent + 无损全历史去大胆搜索,天花板高但依赖强提议者、且外部指导可能与目标模型失配。Self-Harness 押注"对齐 + 纪律"——让被优化的模型自己诊断(失败模式天然贴合自身),并用"有界 + 回归门 + 审计"把风险摁住,代价是探索幅度受限。一个自然的合流猜想:用 Self-Harness 的"证据聚类 + 回归门 + 有界编辑"当安全外壳,套在 Meta-Harness 的"全历史文件系统 + 强提议者"之上——既大胆又可控。这可能是本项目"harness 演化"叙事里很好的一个"未来方向"落点。

与更广谱系的关联

方法论启示(可迁移)

  1. "自我改进"要工程化成"有据、可测、可逆":证据(失败聚类)→ 提案(有界最小)→ 验证(非回退回归门)→ 审计日志。这套纪律几乎可以直接搬到任何"让系统改自己"的场景,是本文最值得抄的部分。
  2. failure signature \((c,q,m)\) 的"症状 vs 机制"分离很聪明——它是"别急着打补丁,先归因到可复用机制"的可操作化。做任何自动化 bug 修复 / 回归分析都可借鉴。
  3. 非回退准入 = 便宜的防过拟合护栏:held-out 只当门、不给提议者看,简单但有效。

在我的工作中能怎么用

开放问题 / 疑问