Harness² 开源之后:自建 Agent 先过编辑面合同、Propose 范围、Probe 对比证据、Compose 采纳与改进库递归预算闸门

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),
    }

实践建议(示例):

  1. 把「可编辑根目录」写进任务元数据,编辑器会话只能看到该树 + 证据目录,看不到评分器 / rubric / 权重路径;
  2. CI 对 diff 做路径白名单:只允许八类组件对应的文件模式;
  3. 任何声称「同时微调模型」的流水线,与 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. 每个候选必须附 ≥1 条「轨迹时刻」引用;写不出时刻 = 投机编辑,直接拒;
  2. INV / DOM 分会话、分 system 指令(论文编辑器 prompt 即如此);合并留给 Compose;
  3. 库里抄来的组件,必须按当前任务证据重核 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",
    }

实践建议(示例):

  1. Probe 会话的工作目录禁止出现 rubric / 分数 / 标准答案文件(论文实现有 guard);
  2. 记录 env_hash(容器镜像、工具版本、超时、turn cap);不 matched 就不要进 Compose;
  3. 随机性存在:单次好结果是弱证据;重复失败模式才是强动机(论文 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),
    }

实践建议(示例):

  1. 审计日志强制:edit_id → evidence_ref 映射;缺映射的 diff 不得进入「已采纳」库;
  2. 选择器(k>1)只比较匿名交付物 与任务请求,不回头改 harness(论文 Final Selection);
  3. 把 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,
    }

实践建议(示例):

  1. 库按 benchmark / executor / mode / budget / seed 分桶(仓库实验指南亦强调分离),域内任务有序读更早条目;
  2. EXPERIENCE 只收「有对比证据支持的可迁移教训」;选了一个交付物 ≠ 可迁移;
  3. k 提升会抬高成本(论文 Figure 6 讨论 compute--performance);生产默认用小 k,难题再升,并设硬 token / 会话上限;
  4. 消融提醒: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 等,见表注)。

工程上应记住:

  1. 这些是特定基准 / 执行器 / 初始 harness / 编辑器组合上的结果,不是通用 SLA;
  2. 弱执行器在部分基准上绝对增益更大;「弱模型 + 更好 harness」可以超过「强模型 + 原 harness」------论文有此观察,但仍是实验条件内结论;
  3. 同模型兼任 executor 与 editor 时仍有增益(论文 Figure 8),说明不必神话「必须更强编辑器」,但也不等于你的栈零成本。

10. 上线清单(示例)

在宣布「我们支持 Harness² 风格在线改进」之前,建议逐条勾选(字段均为示例):

  1. 编辑面:权重路径不可达;八类组件路径白名单;编辑会话无 grader 文件;
  2. Propose:强制 INV/DOM scope;强制轨迹动机;禁止捏造权威;
  3. Probe :matched model+env_hash;行为 delta 结构化;禁止仅凭自评;
  4. Compose :edit→evidence 绑定;允许 KEEP_BASE;空交付关联编辑默认拒绝;
  5. 库与预算 :EXPERIENCE 证据准入;事项事实隔离;k 与 token/会话硬顶;分桶库;
  6. 观测:KEEP_BASE 率、空交付率、库命中/改编率、单任务成本、回归抽样;
  7. 安全:候选 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 为准;本文示例代码仅为工程骨架。

参考资料

  1. 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)
  2. 代码仓库:https://github.com/google-research/harness2 (Apache-2.0)
  3. 项目页:https://harness2.github.io
  4. 仓库实验说明(并行/顺序与 --k):https://github.com/google-research/harness2/blob/main/docs/EXPERIMENTS.md
相关推荐
wangfpp1 小时前
本地大模型微调与 GGUF 部署全指南
人工智能·agent
小弥儿2 小时前
GitHub今日热榜 | 2026-10-20:智能体基建七席连庄,生成类项目回流
学习·开源·github
析数塔2 小时前
OpenCode 213.5k Stars、Cursor 被曝 600 亿卖身:从开发者视角拆 AI 编程 Agent 三国杀的工程逻辑
agent·ai编程
挖掘狂人2 小时前
2026 年,为什么一线团队开始从 MCP 撤回 CLI?
人工智能·agent·mcp
林伽一2 小时前
GPU 调度栈开源与框架层精炼:AI 基础设施的两个新落点|2026年10月20日
人工智能·科技·安全·ai·开源
武子康2 小时前
从预约改期看 Agent 工具粒度:把不变量留在权威服务
人工智能·后端·agent
miofly2 小时前
GitHub 今日推荐|security-audit-skill:让编码代理自己审计漏洞还互相验证
javascript·开源·github