An Empirical Study of Harness Design for Coding Agents 论文解读
arXiv ID: 2609.20804([cs.AI],v1 提交于 2026-09-17) 论文标题: An Empirical Study of Harness Design for Coding Agents 中文标题: 编码智能体支架(Harness)设计的实证研究 作者: Run-Ze Fan, Zihao Zhang, Simin Ma, Yebowen Hu, Shouju Wang, Kaiqiang Song, Fei Liu, Hamed Zamani, Xiaoyang Wang 机构: UMass Amherst、Zoom、Emory University、UNC Charlotte(部分工作完成于 Zoom 实习期间) 论文链接: https://arxiv.org/abs/2609.20804
一、研究背景与核心问题
大模型驱动的编码智能体(coding agent)并不是只有模型本身——模型外层还有一层"支架"软件,即 harness:它负责把模型的推理翻译成可执行动作、管理上下文、注入系统指令、处理工具调用等。harness 的形态决定了模型能力如何转化为长程软件工程任务上的实际表现。
然而,现有工作通常把 harness 当作一个单体系统来评估(例如直接比较某个 agent 框架的整体得分),无法回答:harness 里到底哪个组件在起作用?这些组件是普遍有效,还是其有效性取决于模型能力、任务类型和资源预算?
本文的核心贡献就是:固定执行循环,只变化三个组件——规划(planning)、动作空间(action space)、上下文管理(context management),在 4 个模型 × 2 个基准上评估了 176 个匹配实验设置,进行严格的组件级消融,得出一系列"条件性"(而非普适性)结论。
二、方法:模块化 Coding Harness 设计(§2)
harness 基于经典的 ReAct 循环(Yao et al., 2022),每轮由推理(reasoning)、动作(action)、观察(observation)组成。实现基于 LangGraph,通过 Harbor 框架驱动基准任务。权限处理、编辑后诊断、卡住检测等支撑组件在所有消融中保持固定。
2.1 Planning(规划组件)
- 由模型维护一个显式、持久的任务进度计划。
- 开启时:系统指令定义规划协议,第一轮提醒要求先制定初始计划,模型通过
update_plan工具维护计划;后续每轮把当前计划注入模型输入,但不写入对话历史。 - 关闭时:移除所有规划指令、提醒、计划注入和
update_plan工具,其余组件完全不变。 - 注意:该设计估计的是"持久规划脚手架"的效果,而非"规划作为通用推理策略"的效果。
2.2 Action Space(动作空间)
两种条件:
- 预定义工具集(predefined tools):
read_file、write_file、edit_file、list_files、glob_files、grep_text、web_fetch、bash。只读工具可在一轮内并行执行;写工具修改工作区或 harness 状态。预定义文件工具强制执行先读后写检查、更新 harness 文件状态、并在支持的编辑后触发自动诊断。排除网络搜索,因为 SWE-Bench 任务来自公开 GitHub issue,搜索可能泄露 ground-truth patch。 - bash-only:移除预定义的文件、搜索、web 工具,只保留
bash进行通用环境交互。
作者强调:该干预是完整动作接口的变化(包括工具可用性、接口指令、状态跟踪、验证支持),而不只是工具数量或动作粒度的孤立效应。
2.3 Context Management(上下文管理)—— 核心设计
三种可组合机制:
| 机制 | 名称 | 功能 |
|---|---|---|
| M1 | Elision(省略/折叠) | 把过期的工具观察正文替换为短 stub(占位符),便宜但丢失细节 |
| M2 | Recall(召回) | 把被省略的观察存入外部文件系统,暴露 recall_event 工具按需读回,使省略可逆 |
| M3 | Summarization(摘要) | 把最旧的消息折叠进一个滚动自然语言摘要;由同一模型以单独的无工具调用生成 |
双阈值策略:软阈值 B₁ 和硬阈值 B₂。前导部分(系统提示 + 初始任务描述)和最近窗口(至少 2 轮)保持逐字不变,只压缩中间区域:
- 历史超过 B₁ → 对中间区域的臃肿工具观察执行 M1+M2(存外部 + 留 stub)
- 仍超过 B₂ → 对最旧的中间事件执行 M3(摘要)
五个策略层级:
| Tier | M1 Elision | M2 Recall | M3 Summarization | 说明 |
|---|---|---|---|---|
| T0 | ✗ | ✗ | ✗ | 无管理,超出窗口即报错终止 |
| T1 | ✓ | ✗ | ✗ | 仅省略(不可逆) |
| T2 | ✓ | ✓ | ✗ | 省略 + 可召回 |
| T3 | ✗ | ✗ | ✓ | 仅摘要 |
| T4 | ✓ | ✓ | ✓ | 完整三机制,先省略后摘要的分级策略 |
2.4 固定组件
- Safety:工作区守卫(拒绝逃逸项目根目录的路径,含符号链接)、先读后写检查(内容哈希检测外部修改)、权限层(allow/ask/deny 分类);工具错误作为观察返回而非抛出异常。
- Post-edit diagnostics:编辑/写入 Python 文件后,用 ruff、pyflakes 或纯语法回退做快速只读检查。
- Stuck detection:监控相同工具名+相同参数的连续调用 streak;达到 5 次注入一次性提醒;相同失败 streak 达 8 次则提前终止运行。
三、实验设置(§3.1)
模型(4 个)
| 模型 | 定位 | 价格(每 1M 输入/输出 tokens,OpenRouter) |
|---|---|---|
| Nemotron-3 30B | 家族内小模型 | $0.05 / $0.20 |
| Nemotron-3 120B | 家族内中模型 | $0.08 / $0.45 |
| Nemotron-3 550B | 家族内大模型 | $0.50 / $2.20 |
| Mistral-Medium-3.5-128B | 跨家族对照 | $1.50 / $7.50 |
Nemotron-3 三个尺寸构成家族内能力轴,Mistral 用于检验结论是否跨家族泛化。
基准与实现
- SWE-Bench Verified:500 个人工验证的真实 GitHub issue(仓库级 issue 解决,纯 Python)。
- Terminal-Bench 2.1:89 个命令行环境的端到端任务。
- 指标:任务成功率(SR) 和 每任务平均成本($)。
- SGLang 本地推理,BF16 精度;temperature = 0,top-p = 0.95;每轮输出上限 16,384 tokens;每任务最多 300 步;软/硬上下文阈值分别为可用窗口的 0.6 / 0.85;逐字最近窗口预算 0.3 且不少于 2 轮;工具结果截断至 24k 字符;每步最多 8 个只读工具并行。
消融设计与统计
- T0–T4 × 4 种上下文窗口预算(32k、64k、96k、128k)= 每个模型-基准对 20 个设置(全部使用预定义工具 + 开启 planning)。
- 以 T4/128k 为基线,再做两个单组件消融:−plan(关闭规划)、bash-only(替换动作空间)。
- 合计每个模型-基准对 22 个设置 × 4 模型 × 2 基准 = 176 个实验设置。
- 统计检验:任务配对的双侧精确 McNemar 检验,Benjamini–Hochberg 控制 FDR = 0.05。
四、主要结果(§3.2)
4.1 上下文管理的价值随窗口收紧而增大
- 管理策略(T1–T4 均值)与 T0 的成功率差距:SWE-Bench 上从 32k 的 35.7 pp 缩至 64k 的 15.9、96k 的 5.5、128k 的 2.7 pp;Terminal-Bench 上从 9.5 → 7.5 → 4.8 → 2.8 pp。
- 机制解释:T0 的窗口溢出失败率从 32k 的 78.7%(SWE-Bench)/ 61.0%(Terminal-Bench)降至 128k 的 8.7% / 12.1%;而所有管理层级在所有预算下溢出率为 0。
- 结论:上下文管理的主要收益是防止窗口溢出导致的过早终止;窗口越大,边际收益越小且更依赖模型。
SWE-Bench Verified 关键数字(T0 → T4):
| 窗口 | 30B | 120B | 550B | Mistral |
|---|---|---|---|---|
| 32k | 9.40 → 21.20% | 11.40 → 42.20% | 6.40 → 55.60% | 12.60 → 63.80% |
| 128k | 24.80 → 25.20% | — | 59.80 → 65.80%(显著) | 67.40 → 68.60% |
Terminal-Bench 呈相同趋势:32k 时 Mistral T0 21.35% → T4 42.70%;128k 时 550B T4 44.94%(显著高于 T0 34.83%)。
4.2 T4(先省略后摘要)性价比最优
- T4 在 8 个模型-基准面板中的 7 个取得最低成本,成功率与 T1–T3 相当。
- 32k 时 T1/T2 轨迹仍逼近满窗口,T3/T4 的峰值上下文显著低于窗口上限;T4 在所有四个预算下峰值上下文比率最低。
- T4 在 32k/64k 比 T1/T2 更少调用 M1 省略,且在所有预算下比 T3 更少调用 M3 摘要——早期省略在需要摘要前就解决了多数情况,减少了昂贵的 LLM 摘要调用。
4.3 Recall(M2)很少被使用且无准确率增益
- T2 vs T1 的 32 个对比中:15 胜、14 负、3 平;平均差 −0.36 pp。
- 64 个 T2/T4 设置中,36 个(56.3%)从未调用
recall_event,中位调用率为 0;平均每任务调用从 32k 的 0.540 降至 128k 的 0.007;T4/128k 的 16 个 planning/动作空间设置中召回调用为 0。 - 使用最多的是 Nemotron-3 30B 在 Terminal-Bench 32k T2(平均每任务 4.326 次),但该配置反而比 T1 低 3.37%。
- 结论:无损存储增加了模型很少使用的机制,取回被省略内容并不能稳定转化为任务完成。
4.4 Planning:弱模型的准确率脚手架 → 强模型的成本节约器
在 T4/128k + 全工具下对比 planning 开/关:
- Nemotron-3 30B(弱模型):planning 使成功率 +11.6 pp(SWE-Bench)、+4.5 pp(Terminal-Bench),但成本更高。
- Nemotron-3 120B:成功率无一致增益。
- 550B 与 Mistral(强模型):planning 在 SWE-Bench 上分别降成本约 30% 和 32%,成功率仅降 2.0 和 0.4 pp。
planning 开 vs 关的变化百分比(T4/128k,轮数 / 工具调用 / 平均输入 tokens):
| 模型 | SWE-Bench | Terminal-Bench |
|---|---|---|
| 30B | +293.2% / +474.0% / +104.1% | +66.7% / +83.8% / +24.0% |
| 120B | +20.1% / +42.7% / +10.3% | −15.0% / −23.1% / −12.0% |
| 550B | −24.3% / −24.5% / −12.4% | +6.8% / +7.9% / −1.7% |
| Mistral | −23.2% / −23.3% / −15.1% | −22.5% / −21.9% / −13.0% |
4.5 动作空间:预定义工具支撑弱模型,bash-only 利好强模型
- 30B:预定义工具 +15.0%(SWE-Bench)、+10.1%(Terminal-Bench)。bash-only 时模型发出训练中学到的工具调用模式,harness 无法解析——Terminal-Bench 上 66% 的 bash-only 轨迹因接口外调用终止,平均轨迹从 71 轮缩至 15 轮。
- 120B:增益缩至 +1.6% / +4.5%,但预定义工具让运行更短(SWE-Bench 101→77 轮,Terminal-Bench 96→70 轮)。
- 550B:bash-only 反而 +3.6%(SWE-Bench)、+5.6%(Terminal-Bench),成本降 53% / 30%;调用次数减少 32% / 24%——强模型能把多个操作打包进复合 shell 命令。
- Mistral(揭示任务类型边界):全工具在 SWE-Bench 上 +23.2%,但 bash-only 在 Terminal-Bench 上 +6.7%。Mistral 在 Terminal-Bench 上 71.9% 的工作区动作经由 bash(SWE-Bench 仅 40.4%);且 bash-only 时 32.8% 的 SWE-Bench 运行未编辑任何文件就结束(全工具仅 1.2%)。
五、轨迹级分析(§4)
- 上下文管理只延长轨迹、不改变行为:32k 时 T0 中位轨迹仅 20–30 轮,多数死于 Localize 阶段;管理策略延长至约 50–180 轮,阶段顺序和比例基本保持。128k 时各层级差异大幅缩小。
- Planning 对弱模型是"续命"机制:关闭 planning 后,30B 在 SWE-Bench 上"未编辑即终止"比例从 27.8% 飙至 68.6%,停滞在定位阶段的比例从 10.4% 飙至 58.4%,中位轨迹从 40 轮崩至 5 轮;强模型(550B、Mistral)几乎不受影响。
- Planning 缩短强模型轨迹的机制是减少编辑后验证:550B 中位轨迹 108→74 轮、Mistral 68→53 轮,减少的主要是 Verify 阶段而非定位或修复。Terminal-Bench 上 planning 同时"救活过早终止"和"截断过长尾部",净效应决定成本变化。
- 动作粒度:bash-only 使重复修补(re-patch)次数全面下降(550B 4.6→1.5、Mistral 3.0→1.3);Terminal-Bench 上"创建/整体替换"式写文件占比大幅上升(550B 51→76%、Mistral 28→57%)。550B 在 Terminal-Bench 上中位轨迹 47→31 个动作,Write-code 占比 16%→27%。
六、图表速览
| 图表 | 内容 |
|---|---|
| Figure 1 | 论文总览:三个组件的系统消融,揭示四个条件性效应 |
| Figure 2 | harness 架构:ReAct 循环 + T4 双阈值上下文管理示意 |
| Figure 3 | 成功率与窗口溢出率随上下文预算变化 |
| Figure 4 | 各 tier 成功率胶囊图 + 平均成本,T4 高亮 |
| Figure 5 | (a) 峰值上下文/标称预算比;(b) M1/M3 每任务调用次数;(c) 每任务平均成本 |
| Figure 6 | planning 开/关对比(成功率与成本) |
| Figure 7 | 动作空间对比:成功率、成本、经 bash 发起的调用占比 |
| Figure 8 / 9 | SWE-Bench / Terminal-Bench 轨迹剖面(按阶段分解的堆叠面积图) |
| Table 1 / 2 | 工具清单;五个上下文管理层级的机制组合 |
| Table 3 / 4 | SWE-Bench / Terminal-Bench 主结果(McNemar+BH 校正显著性) |
| Table 5 / 6 / 7 | planning 开关的轨迹变化;未编辑即终止比例;动作粒度统计 |
| Figures 10–30 | 附录:系统提示、planning 提示、各工具完整描述原文 |
七、结论与启示
harness 设计是一个条件性系统问题,而非"组件全开就是最好":
- 上下文管理在窗口紧张时最关键(本质是防溢出失败);T4(先规则省略、后选择性 LLM 摘要)以相近成功率取得最低成本;而让省略内容可召回(M2)增加的机制模型很少使用,无准确率增益——简单的不可逆省略即可。
- Planning 的价值取决于模型强度:对弱模型是提升成功率的脚手架(维持轨迹活到首次编辑);对强模型主要是省成本(削减冗余的编辑后验证),成功率几乎不变。
- 动作空间取决于模型的 bash 熟练度与任务类型:预定义工具支撑 bash 能力弱的模型;bash 能力强的模型用 bash-only 接口反而更准、更省,尤其在命令行中心任务上。
- 实践建议:组件选择应针对目标模型、任务类型和资源预算做匹配,而非默认全开;本文的模块化 harness 也可作为评估未来 harness 组件的框架。
局限:组件实例化方式单一(一种 planning 提示、一种阈值策略);planning 和动作空间仅在 T4/128k 下消融;每设置只跑一次且 Terminal-Bench 仅 89 个任务(很多对比未达统计显著);SWE-Bench 仅覆盖 Python;模型规模是能力的不完美代理,交叉点结论迁移前需验证。