
2026 年 10 月前后,Google Cloud AI Research 公开了 Harness² (Harness^2 / Harness2):论文 arXiv 2610.14224 《Harness²: Recursive Agent Harnessing for an Open World》,代码仓库 github.com/google-research/harness2(Apache-2.0),项目页 harness2.github.io。作者包括 Ruiyao Xu、Yanfei Chen、Zhongying CuiZhu、Bhavana Dalvi Mishra、Yifei Ming、Han Yu、Rujun Han、Chen-Yu Lee、Tomas Pfister 等。核心论断并不玄:
Agent = Model + Harness。 Harness 是环绕冻结模型的提示、工具、记忆、技能与编排;Harnessing 是在不改模型权重的前提下,递归优化这层脚手架。
开源世界里任务往往没有 ground-truth 校验器 :你不能靠「答案对不对」来在线改 harness。Harness² 用对比式 Propose--Probe--Compose 在任务层改执行 harness,再用 Harnessing 层 把采纳结果与 EXPERIENCE.md 写入持续改进库,指导后续任务------不是把上一任务的执行 harness 盲继承下去。
本文不复述榜单叙事,也不软广任何商业 Agent 产品。按公开论文与仓库事实,整理五道可落地闸门:编辑面与冻结权重合同 → Propose 范围 → Probe 对比证据 → Compose / 采纳 → 改进库与递归预算 ,并给出标注为示例的 Python 骨架。
1. 先把公开事实和工程推论分开
| 类别 | 内容 | 出处 |
|---|---|---|
| 公开事实 | 论文:arXiv 2610.14224;标题 Harness²: Recursive Agent Harnessing for an Open World;Google Cloud AI Research | arXiv HTML / abs |
| 公开事实 | 代码:github.com/google-research/harness2(Apache-2.0);站点 harness2.github.io | GitHub README / 论文页脚 |
| 公开事实 | Agent = Model + Harness;Harnessing = 在冻结权重下优化运行时脚手架 | 论文 §2.1 |
| 公开事实 | 任务层:对比式 Propose--Probe--Compose;可并行或顺序扩展;预算参数 k | 论文 §2.2 |
| 公开事实 | Propose:在参考执行后提出 invariant(不变式 / 跨域过程) 与 domain-specific(域特定) 两类候选 harness 编辑 | 论文 §2.2.1 |
| 公开事实 | Probe:在 matched 模型与环境配置下执行候选,用轨迹与交付物做行为对比(非正确性证明) | 同上 |
| 公开事实 | Compose:可合并支持的编辑、采纳某一候选、或 KEEP_BASE;决策须绑定具体观察 | 同上 |
| 公开事实 | Harnessing 层:更新 continual improvement harness / 库;条目含可执行 harness + EXPERIENCE.md;下一任务仍从公共执行 harness H₀ 起步 | 论文 §2.3 |
| 公开事实 | 8 个可编辑组件(AHE 风格扩展):system prompt、guardrails、memory、skills、tool guidance、scripts、subagents、middleware plugin | 论文 Figure 2 / Appendix D.3 |
| 公开事实 | 执行器:Gemini 3.5 Flash、GLM-5;初始 harness:OpenCode、Codex;默认编辑器常为 Claude Opus 4.8(OpenCode) | 论文 §3.1 |
| 公开事实 | 单步(k=1)相对 base 的增益:WorkBuddy-Bench 最高约 11.5 分(GLM-5/OpenCode);JobBench 最高约 4.5 ;LAB Partial 最高约 11.8 个百分点;并行 k=5 有进一步增益 | 论文 Abstract / §3.2 |
| 公开事实 | 消融:去掉 library / scoping / composition 在 WorkBuddy 与 JobBench 上均掉分 | 论文 Table 3 |
| 工程推论 | 自建「在线改 harness」能力前,应先过编辑面合同、Propose 范围、Probe 对比、Compose 采纳、改进库与 k 预算五道闸门 | 作者建议 |
下文字段名、路径、阈值、默认 k、准入规则,凡未注明出处的,都是示例值 。本文示例不对接 Harness² 官方 CLI,也不声称与内部实现一致。
2. 为什么「能递归改 Harness」会换失败面
离线 harness 搜索(固定训练集 + 验证器)失败面多在:分布外任务泛化差、准备成本高。开到「任务流上在线改」之后,常见失败面变成:
- 偷偷动权重:把「改进」做成微调或私有 adapter 热更,审计面与合规面全变;
- Propose 空想:没有轨迹动机就大改 system prompt / 堆技能,上下文膨胀、行为漂移;
- Probe 自评:用「模型说自己更好了」或未 matched 的单次运行当放行证据;
- Compose 盲合:把 INV 与 DOM 候选无脑拼接,或永远拒绝 KEEP_BASE;
- 库污染与预算失控 :把一次性事项事实写进 EXPERIENCE;
k无上限导致成本与回归风险失控。
工程翻译可以写成:
把「无 ground-truth 的递归 harness 改进」接进生产 Agent 栈之前,必须先过编辑面合同、Propose 范围、Probe 对比证据、Compose 采纳、改进库与递归预算五道闸门;任一门失败则不得对外提供「默认可在线改 harness」能力。

3. 闸门一:编辑面与冻结权重合同------只改 harness 文件
Harness² 的合同边界很清楚:模型参数冻结 ;改进对象是挂载到运行时的组件文件树。自建系统若没有同等硬边界,很容易把「harnessing」偷换成「偷偷训一点」。
python
# edit_surface_contract.py ------ 示例:编辑面与冻结权重合同闸门
from dataclasses import dataclass, field
from pathlib import Path
from typing import Literal
Verdict = Literal["allow", "deny"]
# 示例:与论文 Appendix D.3 对齐的八个逻辑组件名(路径可按执行器映射)
ALLOWED_COMPONENTS = frozenset({
"system_prompt",
"guardrails",
"memory",
"skills",
"tool_guidance",
"scripts",
"subagents",
"middleware_plugin",
})
FORBIDDEN_PATH_GLOBS = (
"**/weights/**",
"**/*.safetensors",
"**/*.bin",
"**/lora/**",
"**/checkpoints/**",
"**/.env",
"**/secrets/**",
)
@dataclass(frozen=True)
class EditSurfaceContract:
"""示例:一次 harness 编辑会话的合同(非官方 schema)。"""
task_id: str
executor_id: str # 示例:opencode / codex
model_frozen: bool = True # 合同:必须为 True
allow_weight_touch: bool = False # 合同:必须为 False
max_files_touched: int = 24 # 示例本地上限
allowed_roots: tuple[Path, ...] = field(default_factory=tuple)
notes: str = ""
@dataclass(frozen=True)
class ProposedEdit:
component: str
relative_path: str
op: Literal["create", "modify", "delete"]
bytes_delta: int
motive_trajectory_ref: str | None # 指向某条轨迹时刻;闸门二再严查
def gate_edit_surface(contract: EditSurfaceContract, edits: list[ProposedEdit]) -> dict:
if not contract.model_frozen or contract.allow_weight_touch:
return {"decision": "deny", "reason": "weights_must_stay_frozen"}
if not contract.allowed_roots:
return {"decision": "deny", "reason": "no_allowed_harness_root"}
if len(edits) > contract.max_files_touched:
return {"decision": "deny", "reason": "too_many_files_touched"}
for e in edits:
if e.component not in ALLOWED_COMPONENTS:
return {"decision": "deny", "reason": f"component_not_in_surface:{e.component}"}
rel = e.relative_path.replace("\\", "/")
for bad in ("../", "weights/", "checkpoints/", "lora/", ".env"):
if bad in rel:
return {"decision": "deny", "reason": f"path_escape_or_weight:{rel}"}
# 示例:拒绝超大单文件补丁,防止把整库数据塞进 prompt 文件
if e.bytes_delta > 200_000:
return {"decision": "deny", "reason": "patch_too_large"}
return {
"decision": "allow",
"components": sorted({e.component for e in edits}),
"n_edits": len(edits),
}
实践建议(示例):
- 把「可编辑根目录」写进任务元数据,编辑器会话只能看到该树 + 证据目录,看不到评分器 / rubric / 权重路径;
- CI 对 diff 做路径白名单:只允许八类组件对应的文件模式;
- 任何声称「同时微调模型」的流水线,与 Harness² 合同分轨------单独审批面,不要混进 harness 递归。

4. 闸门二:Propose 范围------invariant vs domain;禁止无轨迹动机
论文把 Propose 拆成两个 scope:invariant(过程 / 工具使用 / 完成纪律) 与 domain-specific(从业者知识 / 交付物结构 / 域检查) 。消融显示去掉 scoping 会明显掉分。工程上更危险的是第三种编辑:既无轨迹动机、又跨 scope 乱写。
python
# propose_scope_gate.py ------ 示例:Propose 范围闸门
from dataclasses import dataclass
from typing import Literal
Scope = Literal["invariant", "domain", "forbidden_mixed"]
Verdict = Literal["allow", "deny", "keep_base_ok"]
@dataclass(frozen=True)
class TrajectoryMoment:
run_id: str
step_index: int
summary: str # 示例:人读摘要;生产可用结构化事件 id
@dataclass
class ProposeCandidate:
scope: Scope
edits: list[str] # 示例:组件名列表
moments: list[TrajectoryMoment]
claims_workspace_fact: bool # DOM 可写「本工作区已核实事实」;须有证据
invents_authority: bool # 论文硬规则:禁止捏造标准/引用
def gate_propose(
scope: Scope,
moments: list[TrajectoryMoment],
edits: list[str],
*,
invents_authority: bool = False,
claims_workspace_fact: bool = False,
fact_verified: bool = False,
) -> dict:
if invents_authority:
return {"decision": "deny", "reason": "invented_authority_forbidden"}
if not moments:
return {"decision": "deny", "reason": "no_trajectory_motive"}
if scope == "forbidden_mixed":
return {"decision": "deny", "reason": "scope_must_be_inv_or_dom"}
# 示例:INV 不得塞域专章节清单;DOM 不得改插件/重试策略(分工示意)
inv_only = {"middleware_plugin", "scripts", "tool_guidance"}
dom_heavy = {"memory"}
if scope == "invariant" and any(c in dom_heavy for c in edits) and len(edits) == 1:
# 弱提示:允许,但记审计;此处示例直接放行并打标
return {"decision": "allow", "flag": "inv_touching_memory_review"}
if scope == "domain" and "middleware_plugin" in edits:
return {"decision": "deny", "reason": "dom_must_not_own_plugin_hooks"}
if claims_workspace_fact and not fact_verified:
return {"decision": "deny", "reason": "workspace_fact_not_verified"}
return {
"decision": "allow",
"scope": scope,
"n_moments": len(moments),
"note": "KEEP_BASE is valid if evidence supports no change",
}
实践建议(示例):
- 每个候选必须附 ≥1 条「轨迹时刻」引用;写不出时刻 = 投机编辑,直接拒;
- INV / DOM 分会话、分 system 指令(论文编辑器 prompt 即如此);合并留给 Compose;
- 库里抄来的组件,必须按当前任务证据重核 workspace 事实------论文明确:库是范例,不是当前磁盘上的运行文件。
5. 闸门三:Probe 对比证据------matched 执行;禁止「自评正确」放行
开世界设定下,Probe 产出的是行为对比,不是 correctness label。把「候选跑完模型自夸更好」当成放行,等于把 RSI 退化成自我说服。
python
# probe_contrast_gate.py ------ 示例:Probe 对比证据闸门
from dataclasses import dataclass
from typing import Literal
Verdict = Literal["usable_contrast", "weak", "reject"]
@dataclass(frozen=True)
class ExecutionRecord:
harness_id: str
run_id: str
matched_model: str
matched_env_hash: str
produced_deliverable: bool
trajectory_digest: str
# 注意:生产流水线不应出现 grader_score;此处刻意不设该字段
@dataclass(frozen=True)
class ContrastReport:
reference: ExecutionRecord
candidate: ExecutionRecord
same_task_id: bool
model_match: bool
env_match: bool
observed_deltas: list[str] # 示例:具体行为差异描述
self_grade_better: bool # 若仅有自评,不得放行
def gate_probe(report: ContrastReport) -> dict:
if not (report.same_task_id and report.model_match and report.env_match):
return {"decision": "reject", "reason": "not_matched_conditions"}
if report.reference.matched_env_hash != report.candidate.matched_env_hash:
return {"decision": "reject", "reason": "env_hash_mismatch"}
if report.self_grade_better and not report.observed_deltas:
return {"decision": "reject", "reason": "self_grade_without_behavioral_delta"}
if not report.candidate.produced_deliverable:
# 论文 Compose 指引:无交付 rollout 关联的编辑默认不安全
return {
"decision": "weak",
"reason": "candidate_produced_nothing",
"compose_hint": "treat_edits_as_unsafe_unless_overwhelming",
}
if not report.observed_deltas:
return {"decision": "weak", "reason": "no_named_behavioral_delta"}
return {
"decision": "usable_contrast",
"n_deltas": len(report.observed_deltas),
"note": "contrast informs compose; it does not prove task correctness",
}
实践建议(示例):
- Probe 会话的工作目录禁止出现 rubric / 分数 / 标准答案文件(论文实现有 guard);
- 记录
env_hash(容器镜像、工具版本、超时、turn cap);不 matched 就不要进 Compose; - 随机性存在:单次好结果是弱证据;重复失败模式才是强动机(论文 Compose 提示亦强调)。
6. 闸门四:Compose / 采纳------必须绑定具体观察;KEEP_BASE 合法
Compose 不是投票器,也不是「永远改一点显得在工作」。合法结局包括:合并 INV+DOM 支持的编辑、整采纳某一候选、或 KEEP_BASE。每条采纳须能指到观察。
python
# compose_adoption_gate.py ------ 示例:Compose / 采纳闸门
from dataclasses import dataclass
from typing import Literal
Action = Literal["merge", "adopt_one", "keep_base"]
Verdict = Literal["allow", "deny"]
@dataclass(frozen=True)
class ComposeDecision:
action: Action
adopted_edit_ids: tuple[str, ...]
evidence_refs: tuple[str, ...] # 必须非空(keep_base 时可引用「无支持变更的观察」)
from_empty_deliverable: bool
notes: str
def gate_compose(decision: ComposeDecision) -> dict:
if not decision.evidence_refs:
return {"decision": "deny", "reason": "adoption_not_bound_to_observation"}
if decision.action == "keep_base":
return {
"decision": "allow",
"action": "keep_base",
"note": "KEEP_BASE is a first-class outcome, not a failure",
}
if decision.from_empty_deliverable and decision.action != "keep_base":
return {
"decision": "deny",
"reason": "edits_from_empty_rollout_blocked",
}
if decision.action in ("merge", "adopt_one") and not decision.adopted_edit_ids:
return {"decision": "deny", "reason": "empty_adoption_set"}
return {
"decision": "allow",
"action": decision.action,
"n_edits": len(decision.adopted_edit_ids),
"n_evidence": len(decision.evidence_refs),
}
实践建议(示例):
- 审计日志强制:
edit_id → evidence_ref映射;缺映射的 diff 不得进入「已采纳」库; - 选择器(k>1)只比较匿名交付物 与任务请求,不回头改 harness(论文 Final Selection);
- 把 KEEP_BASE 率做成监控:过低可能「为改而改」,过高可能 Propose/Probe 失效------阈值本地定,勿写成 SLA。
7. 闸门五:改进库与递归预算------EXPERIENCE 准入、k、成本与回归
Harnessing 层的价值在于:下一任务从 H₀ 起步,靠库里的可执行组件 + EXPERIENCE 指导 Propose/Probe/Compose,而不是盲继承上一任务的高度定制执行 harness。库与预算失控时,递归会变成成本放大器与噪声放大器。
python
# library_budget_gate.py ------ 示例:改进库准入与递归预算闸门
from dataclasses import dataclass
from typing import Literal
Verdict = Literal["admit", "reject", "budget_exhausted"]
@dataclass(frozen=True)
class ExperienceEntry:
domain_id: str
harness_snapshot_id: str
situation: str
lessons: tuple[str, ...]
evidence_refs: tuple[str, ...]
contains_matter_specific_fact: bool # 事项级事实不得当「域永久记忆」
@dataclass(frozen=True)
class RecursionBudget:
mode: Literal["parallel", "sequential"]
k: int
max_k: int = 5 # 示例上限;论文主表常用 1,+Recursion 用 5
max_editor_sessions: int = 40 # 示例
max_executor_rollouts: int = 80
max_token_spend: int = 8_000_000 # 示例
@dataclass
class BudgetLedger:
editor_sessions: int = 0
executor_rollouts: int = 0
token_spend: int = 0
def gate_experience_admit(entry: ExperienceEntry) -> dict:
if not entry.evidence_refs:
return {"decision": "reject", "reason": "experience_without_contrast_evidence"}
if not entry.lessons:
return {"decision": "reject", "reason": "empty_lessons"}
if entry.contains_matter_specific_fact:
return {"decision": "reject", "reason": "matter_fact_must_not_enter_durable_memory"}
return {"decision": "admit", "domain_id": entry.domain_id}
def gate_recursion_budget(budget: RecursionBudget, ledger: BudgetLedger) -> dict:
if budget.k < 1 or budget.k > budget.max_k:
return {"decision": "budget_exhausted", "reason": "k_out_of_range"}
if ledger.editor_sessions >= budget.max_editor_sessions:
return {"decision": "budget_exhausted", "reason": "editor_session_cap"}
if ledger.executor_rollouts >= budget.max_executor_rollouts:
return {"decision": "budget_exhausted", "reason": "rollout_cap"}
if ledger.token_spend >= budget.max_token_spend:
return {"decision": "budget_exhausted", "reason": "token_cap"}
# 示例:并行模式粗估宽度(非官方公式)
if budget.mode == "parallel":
est = budget.k * 4 # 示意:参考 + INV + DOM + compose 相关 rollouts
else:
est = budget.k * 3
return {
"decision": "admit",
"mode": budget.mode,
"k": budget.k,
"estimated_rollout_units": est,
}
实践建议(示例):
- 库按 benchmark / executor / mode / budget / seed 分桶(仓库实验指南亦强调分离),域内任务有序读更早条目;
- EXPERIENCE 只收「有对比证据支持的可迁移教训」;选了一个交付物 ≠ 可迁移;
k提升会抬高成本(论文 Figure 6 讨论 compute--performance);生产默认用小 k,难题再升,并设硬 token / 会话上限;- 消融提醒:library、scoping、composition 各自都有贡献------不要为了省事拆掉其中一环还声称「等价 Harness²」。

8. 并行 vs 顺序递归:怎么选(工程视角)
| 模式 | 公开行为(转述) | 工程含义(示例) |
|---|---|---|
| parallel | 提出并探测 k 个 INV + k 个 DOM;k 次独立 Compose 共享候选池 | 宽度探索;可并发降延迟,但不消总计算 |
| sequential | k 次 Propose--Probe--Compose 串链,携带 refined harness 与累积证据 | 深度修正;可纠正前步,但路径依赖 |
| k=1 | 两种模式都退化为单次对比步骤 | 适合作为生产默认起步 |
论文 Figure 5:在 WB-code / WB-office 上,两种模式随 k 从 1→5 大致单调变好;并行在 k=5 时更高一些。这是论文设定下的观察,不是你业务上的最优 k。
9. 公开数字怎么读(避免过度承诺)
单步相对 base 的「最高约」数字来自论文摘要与主结果叙述,例如:
- WorkBuddy-Bench:最高约 11.5 分(GLM-5 + OpenCode 场景被特别点出);
- JobBench:最高约 4.5;
- LAB Partial:最高约 11.8 个百分点;
- 并行 k=5:相对单步还有额外增益(例如 WorkBuddy 上约 +2.9~+3.9 等,见表注)。
工程上应记住:
- 这些是特定基准 / 执行器 / 初始 harness / 编辑器组合上的结果,不是通用 SLA;
- 弱执行器在部分基准上绝对增益更大;「弱模型 + 更好 harness」可以超过「强模型 + 原 harness」------论文有此观察,但仍是实验条件内结论;
- 同模型兼任 executor 与 editor 时仍有增益(论文 Figure 8),说明不必神话「必须更强编辑器」,但也不等于你的栈零成本。
10. 上线清单(示例)
在宣布「我们支持 Harness² 风格在线改进」之前,建议逐条勾选(字段均为示例):
- 编辑面:权重路径不可达;八类组件路径白名单;编辑会话无 grader 文件;
- Propose:强制 INV/DOM scope;强制轨迹动机;禁止捏造权威;
- Probe :matched
model+env_hash;行为 delta 结构化;禁止仅凭自评; - Compose :
edit→evidence绑定;允许 KEEP_BASE;空交付关联编辑默认拒绝; - 库与预算 :EXPERIENCE 证据准入;事项事实隔离;
k与 token/会话硬顶;分桶库; - 观测:KEEP_BASE 率、空交付率、库命中/改编率、单任务成本、回归抽样;
- 安全:候选 harness 内脚本/插件只当文本审阅,Compose 前校验;不在未沙箱环境执行候选树里的未知代码。
11. 小结
Harness² 把「开世界、无 ground-truth」下的 harness RSI,收成了可插拔的双层递归:任务层用对比式 Propose--Probe--Compose 改执行 harness,Harnessing 层用采纳结果与 EXPERIENCE 升级改进机制本身。对自建 Agent 团队,真正可迁移的不是某一个 k=5 分数,而是合同化闸门:
- 只改 harness 文件,冻结权重;
- Propose 有范围、有轨迹动机;
- Probe 要 matched 对比,不拿自评当真理;
- Compose 绑定观察,KEEP_BASE 合法;
- 改进库有准入,递归预算有天花板。
公开实现与数字以 arXiv:2610.14224 与 google-research/harness2 为准;本文示例代码仅为工程骨架。
参考资料
- Ruiyao Xu et al., Harness²: Recursive Agent Harnessing for an Open World, arXiv:2610.14224(HTML: https://arxiv.org/html/2610.14224 ;ABS: https://arxiv.org/abs/2610.14224)
- 代码仓库:https://github.com/google-research/harness2 (Apache-2.0)
- 项目页:https://harness2.github.io
- 仓库实验说明(并行/顺序与
--k):https://github.com/google-research/harness2/blob/main/docs/EXPERIMENTS.md