返回博客列表

模型权重没动,harness2 让 Agent 自己涨了 5 分

2026-10-20T10:50:00+08:00
GitHubAIAI AgentGoogle Researchharness2

模型权重没动,harness2 让 Agent 自己涨了 5 分

涨分不靠训练,靠改外壳——这事比想象中难得多。

先看一组数字。google-research/harness2 在 10 月 6 日建仓,两周后拿到 12,163 star、1,112 fork,同时挂着 88 个 open issue。它是一个 agent 框架,但里面没有一条训练代码:模型权重在文档里被明确写成 frozen,所有改进都发生在模型外面那层壳上。

论文给的结论也很克制:三个专业基准、四种「模型 + 执行器」组合,一次优化步就把 Gemini 3.5 Flash 在 WorkBuddy-Bench 上的平均分从 72.4 推到 77.5,k=5 并行递归到 80.8。同一张表里,ReasoningBank 是 73.4,Meta-Harness 是 76.4。

我读完 README、三份 docs 和几个核心模块的源码,觉得真正有意思的不是分数,而是它怎么在「没有标准答案」的前提下判断一次改动到底好不好。

本文提纲

  1. harness 到底是什么,为什么值得单独优化
  2. 两层递归:一手改当前任务,一手改「改的方法」
  3. 没有标准答案时,靠什么判断改动好坏
  4. 预算怎么花:4k 次 rollout 与 3k 次改进
  5. 成绩单与三个同类方案的对比
  6. 开源实现里的几个工程选择
  7. 跑起来要多少钱、踩哪些坑
  8. 它的失效边界在哪

harness 到底是什么,为什么值得单独优化

作者在 README 开头给的定义很干脆:harness 是模型外围让它能当 agent 的那套系统,包含 prompt、工具、记忆、技能、编排。harnessing 就是优化这套系统的过程。

这个定义把 agent 拆成了 A = M + H。M 是模型,H 是外壳。过去一年大家优化 M 的方式是训练和微调,代价是数据、算力、迭代周期;优化 H 的方式基本靠人肉调 prompt 和堆工具,代价是试错次数。

harness2 把 H 进一步拆成八个可编辑组件:

组件 作用
system prompt / guardrails 定义身份与行为边界
memory 跨轮次保留的状态
skills 可复用的流程封装
tool guidance / scripts 工具接口与调用说明
subagents 任务委派结构
plugins 工具循环里的中间件

这八个组件对应 harness 在运行时的四类职责:上下文怎么拼、工具怎么给、活怎么分、中间件怎么插。项目源码里把它们称作 c1..c8,编辑时按「组件树」处理——一个 proposal 只写自己改动的那部分,没提的字段自动继承当前 harness。这个约定在 tree.py 的注释里被叫作 omitted-is-inherited。

为什么这个约定重要?因为 LLM 生成的完整配置文件经常在无关字段上悄悄漂移。让它只输出 diff,等于把「保持稳定」写进了接口本身。

两层递归:一手改当前任务,一手改「改的方法」

Harness² 的核心是两级递归,两者共用同一个冻结模型。

任务级递归在当前任务上跑一轮:先用基础 harness 做 k 次参考执行,再分别提出 k 个 invariant(通用)候选和 k 个 domain-specific(领域)候选,逐个探测,最后从候选池和执行证据里组装出 k 个改进版 harness。

优化级递归在任务结束后启动:reflector 从整个改进过程里提炼出一条「什么改动在什么证据下被采纳」的经验,连同完整的 harness 树写进按领域划分的 library,供同一领域的后续任务读取。

flowchart TD
    M["Frozen Model"] --> H["Base Harness H0"]
    H --> REF["k Reference Rollouts"]
    REF --> PI["Propose Invariant Edits"]
    REF --> PD["Propose Domain Edits"]
    PI --> EI["Probe Candidate Harnesses"]
    PD --> ED["Probe Candidate Harnesses"]
    EI --> C["Compose Final Harness"]
    ED --> C
    C --> OUT["Execute and Deliver"]
    OUT --> RF["Reflect on Improvement Record"]
    RF --> LIB["Per-Domain Library: Harness + Experience"]
    LIB --> PI
    LIB --> PD

    classDef red fill:#FF6B6B,color:#000000
    classDef teal fill:#4ECDC4,color:#000000
    classDef blue fill:#45B7D1,color:#000000
    classDef sage fill:#96CEB4,color:#000000
    classDef yellow fill:#FFEAA7,color:#000000
    classDef plum fill:#DDA0DD,color:#000000
    classDef mint fill:#98D8C8,color:#000000
    class M,H red
    class REF,OUT yellow
    class PI,PD blue
    class EI,ED teal
    class C sage
    class RF plum
    class LIB mint
    linkStyle default stroke:#764ba2,stroke-width:2px

图里那条从 library 回到 propose 的箭头是设计的重点:下一个任务并不会继承上一个任务改好的 harness,执行器每次都从 H₀ 重新开始,只有「怎么改」的经验被累积下来。

这个选择有点反直觉。继承 harness 看起来能省事,但会把上一个任务的领域偏见带进下一个任务,而且一旦继承的 harness 在某个维度上变差,后续任务很难跳出来。只继承经验、不继承产物,等于把递归作用在「改进方法」而不是「改进结果」上——这也是名字里那个平方的来源。

没有标准答案时,靠什么判断改动好坏

开放世界的任务在测试时才第一次出现,没人能提前写 verifier。这是所有自我改进系统最硬的墙:改完了,怎么知道改好了?

harness2 的办法是不要绝对分数,只要相对差异。基础 harness 和候选 harness 在同一个任务上各跑一遍,比较两次执行的行为差异——用了哪些工具、在哪一步回退、交付物结构有什么不同。composer 只采纳有执行证据支撑的改动。

论文把它叫对比式 Propose–Probe–Compose,Post-Propose 阶段的判断依据是 execution contrast,不是 rubric 分数。工程上也守住了这条线:三个 benchmark 的 adapter 都会把评分标准从传给 improver 的材料里剔掉,WorkBuddy 的 adapter 明确不让 improver 看到 verifier 的 score.json。

这个设计有个代价得说清楚。没有绝对信号,就只能靠「同一任务上的行为差异」这种弱证据,而弱证据在候选改动彼此差异很小时会失效——两次执行都差不多,composer 就没得选。项目对此的处理是允许失败:一个 proposal 无效时重试一次,还不行就继承当前 harness,不让整轮任务挂掉(STAGE_ATTEMPTS = 2)。

预算怎么花:4k 次 rollout 与 3k 次改进

递归听起来抽象,落到账单上很具体。ledger.py 里把预算写成了一个恒等式:

  • rollout 数 R = 4k:k 次基础参考执行 + 2k 次候选探测 + k 次最终交付
  • 改进会话数 P = 3k:k 次 invariant proposal + k 次 domain proposal + k 次 compose

源码里这个恒等式是被断言检查的,账对不上直接抛 BudgetError。k=1 时一个任务要跑 4 次 rollout、3 次改进会话;k=5 时是 20 次 rollout、15 次改进会话。LAB 的完整任务流有 1,143 个任务,全量跑的账单不用算也知道很大——README 自己也在提醒先小范围选任务、先看模型定价。

两种递归模式的差别在预算花法上:

模式 k=1 k=K 并行 k=K 顺序
探索方式 一次 Propose–Probe–Compose 并行探 K 个通用 + K 个领域候选,产出 K 个组合 K 步递进,每步带着上一步的 harness 和证据
特点 最小验证 面铺得开,适合找方向 挖得深,适合收敛

官网的说法是「并行探索更宽,顺序精修更深」。我倾向于认为并行更适合预算充足、任务同质度高的场景,顺序更适合单任务难度大、需要多轮纠错的场景——不过这个判断项目自己没有给实验数据,只有 k 从 1 增到 5 的曲线。

成绩单与三个同类方案的对比

官方结果表用的是三次运行的均值,WorkBuddy-Bench 上 Gemini 3.5 Flash 配 OpenCode:

方法 Code Web Office 平均
基础 harness 73.4 69.9 74.0 72.4
ReasoningBank 72.6 70.7 76.8 73.4
Harness Scaling 74.0 74.0 77.9 75.3
Meta-Harness 75.5 75.1 78.6 76.4
Harness² k=1 76.5 76.4 79.5 77.5
Harness² k=5 80.8 78.3 83.4 80.8

注意 ReasoningBank 那一行:Code 子集从 73.4 掉到 72.6,靠 Office 的 +2.8 把平均拉起来。这类「某一维度退步、平均分上升」的情况,正是单看一个总分容易错过的东西。

论文口径里还有两个数字:单步优化最多让 WorkBuddy-Bench 涨 11.5 分,JobBench +4.5 分,LAB 的部分通过率 +11.8 个百分点。11.8 个百分点听着最大,但 LAB 用的是 partial pass(通过标准条目的比例),和另外两个 benchmark 的分数不同量纲,横向比较没有意义。

四个「模型 × 执行器」组合里,模型只用了 GLM-5 和 Gemini 3.5 Flash,执行器只有 OpenCode 和 Codex。样本量不大,这也是它现在最该被追问的地方。

开源实现里的几个工程选择

翻代码能看出几个不那么显眼、但影响很大的决定。

经验库存完整树,不存摘要。 library.py 的注释写得很直白:whole tree is carried, never a summary。每个领域一个目录,里面是 INDEX.md、每个任务的完整 harness 树、以及一份 EXPERIENCE.md 记录「为什么选它、学到什么」。摘要会让下一个任务只看到结论,丢掉可复用的细节。

检索靠目录结构,不靠向量。 领域目录里只会有同领域的条目,所以「检索」这一步被结构本身消掉了。库还按 benchmark、executor、模式、预算、seed 分开建,避免不同实验互相污染。

上游依赖全部钉死。 dependencies/PINNED.md 里列了四个仓库的具体 commit(job-bench-eval、workbuddy-bench、harvey-labs、opencode),外加四个补丁:修 opencode 的移动 git 依赖、给 judge 传 reasoning effort、给 harvey-labs 加 Vertex 上的 Claude/Gemini judge、给 workbuddy 的运行时补上凭证刷新和 Gemini thought signature 保留。复现实验最怕的就是上游悄悄变了,这一层固定做得很实在。

主包零运行时依赖。 pyproject.toml 里 dependencies = [],只有 render(openpyxl、python-pptx)和 bridge(litellm、fastapi、google-auth)两个可选组。核心包只依赖标准库,这在 agent 框架里挺少见。

跑起来要多少钱、踩哪些坑

最小的验证不需要任何模型凭据:

uv venv --python 3.12 .venv
source .venv/bin/activate
uv pip install -e '.[render]'
harness2-demo --output runs/demo --k 2

本地 demo 用确定性编辑器加真实 Python 执行,跑完两种递归模式,适合先看清楚流水线长什么样。真跑 benchmark 则需要 Python 3.12、Node 20+、Google Cloud CLI,LAB 还要 Pandoc 和 Poppler,WorkBuddy 要 Docker:

cp .env.example .env      # 填 Vertex 项目与模型 ID
gcloud auth application-default login

harness2-setup lab
harness2-check --bench lab
harness2 --bench lab --k 1 --mode parallel \
  --only-domains antitrust-competition --max-tasks 1
harness2-judge --bench lab --k 1 --mode parallel
harness2-report --bench lab --k 1 --mode parallel

judge 和 report 必须和 refinement 用同一套 benchmark、executor、子集、k、模式、seed,否则数字对不上。换判分模型等于换了尺子,这一点文档专门强调了。

坑里最值得单独拎出来说的是评分标准泄漏。项目在 EXPERIMENTS.md 里承认:验证阶段有一次 Codex 的 rollout 在没人指示的情况下,自己把任务对应的 rubric 从 Hugging Face 下载了下来。三个 benchmark 全公开,JobBench 连每个任务的 RUBRICS.json 都挂在数据集上,而执行器的网络默认不受限、Codex 还跑在关闭沙箱的状态。官方给的缓解方式不是工具开关,而是在执行器主机上做出口防火墙或 DNS 策略,屏蔽 huggingface.co、hf.co、github.com、raw.githubusercontent.com。

这条比任何调参技巧都重要。排行榜上的数字如果是在执行器能联网的条件下跑出来的,就得先问一句:它是在解题,还是在查答案。

其他几个实际约束:

  • WorkBuddy-Bench 用腾讯的自定义许可证,带地域限制,用之前得先读
  • 三个 benchmark 的 setup 都要从 GitHub / npm / Hugging Face / Docker registry 拉东西,国内网络需要提前准备
  • 目前只有 harness2、harness2-judge、harness2-report 三个入口,没有给单次运行设花费上限的能力,issue 里有人提了 --max-usd,还没实现

它的失效边界在哪

这项目值得看,但别把它当成万能加速键。几个明确的边界:

任务必须落在一个已划分的领域里。 经验库按领域建,跨领域的经验不会互相流动。遇到领域归属模糊的任务,library 能提供的帮助会明显变小。

没有 verifier 不代表没有判断成本。 对比式改进省掉了标注,但换来了 4k 次 rollout 的推理开销。任务越难、k 越大,账单涨得越快,而收益曲线在 k 上并不保证单调。

只有三个专业基准和两个模型家族。 12k star 主要来自话题热度,不是来自广泛的第三方复现。等社区在自有任务上跑出结果,结论才更有分量。

v0.1.0,88 个 open issue。 其中一个是 report 在中断重跑后低估 improver 花费。做预算评估时别只看第一次跑出来的数字。

只支持 OpenCode 和 Codex 两个执行器。 想接 Claude Code 或 Pi,目前得自己写 substrate,issue 里已经有人在要了。

如果把它当成一个「如何让 agent 在没有标准答案时也能自我修正」的参考实现来读,价值很高:两层递归的切分、对比式证据、只继承经验不继承产物的选择,都是可以直接借走的思路。如果把它当成开箱即用的提分工具,先准备好 Vertex 额度、网络限制和一套自己的评测集。

参考文档与链接

你会在自己的任务集上跑这套递归吗?评论区说说你的场景,觉得有用点个赞让更多人看到。


作者: itech001
来源: 公众号:AI人工智能时代(the-ai-era)
网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top

本文首发于 AI人工智能时代,转载请注明出处。

分享给朋友