研究提案 · v2

HarnessForge v2:轨迹优先的 Coding Agent 训练数据工厂

从"先设计任务再收集轨迹"到"先收集轨迹再提炼任务"的范式转变。
三阶段解耦架构:Repo 筛选 → Harness 持续开发 → 轨迹理解与任务提炼。
让数据说话,而不是凭空设计。

核心最本质的设计洞察

PR/issue 不是用来驱动任务的——它们是 Dev 卡住时的后备提示。

如果按 PR 粒度给任务,等于直接告诉 Dev 改什么,任务太简单,轨迹没有训练价值。所以要故意把里程碑粒度做粗,让 Dev 面对一个大的、模糊的开发目标——必须自己探索。

而 PR/issue 的真正价值在于:它们是现成的、ground truth 级别的提示储备。Dev 卡住时,系统只需按粒度逐步释放这些已有信息。不需要 LLM 合成提示——repo 里已经有了。

粗粒度 → 任务难 → 轨迹有价值。PR/issue 作为后备提示 → 保证不会卡死。

01v1 方案:五角色串行流水线

v1:先设计任务,再收集轨迹(紧耦合 · 串行依赖) Release Notes + Changelog PM 任务设计 提示合成 LLM ⭐⭐ Test Crafter 合成验收测试 LLM ⭐ Dev 逐个执行任务 LLM ⭐⭐ Reviewer 筛选 LLM ⭐⭐ ⚠ 核心问题:4 个 LLM 角色串行依赖,一环断全线停 在没有一条轨迹数据之前,就在投入大量精力"优化"任务设计
v1 架构:Release Notes → PM 设计任务 → Test Crafter 合成测试 → Dev 逐个执行 → Reviewer 筛选

02v2 方案:三阶段解耦 · 轨迹优先

v2:先收集轨迹,再提炼任务(三阶段解耦 · 独立可控) Stage 1 · Repo 筛选 📋 Release Notes + Changelog + PR/Issue ▼ LLM 辅助 + 脚本 里程碑序列 M1 → M2 → M3 → ... 🔑 粒度故意做粗 Stage 2 · 持续开发 Dev HY3.0(目标模型) 核心执行 · 不停开发 Mentor 卡住时按需提示 卡住时请求 Navigator Verifier Rec ↑ 规则/脚本,非 LLM 原始轨迹 (JSONL) ~210 里程碑 × ~50 turns Stage 3 · 轨迹提炼 卡点切片 试错-修正对提取 长程 SFT 样本 片段切割 Mentor 交互提取 → Verified Tasks 独立执行 ✓ 独立执行 ✓ · LLM 仅 2 个 独立执行 ✓
v2 架构:三阶段完全独立。Stage 2 的唯一目标是"不停开发,留下轨迹"

03为什么不直接用 PR/Issue 驱动任务

✗ 按 PR 粒度给任务 Issue: "QuerySet union() 与 annotate() 不兼容" PR: "Fix union/intersection with annotate" ↓ 信息太充分,任务太简单 Dev 5 轮搞定 轨迹短 · 探索浅 · 训练价值低 ✓ 粗粒度里程碑 "支持 QuerySet 的嵌套聚合操作" ↓ 模糊目标,必须自己探索 Dev 30-50 轮探索 试错 → 回退 → 换方向 → 突破 卡住时释放 PR/issue 作为提示 轨迹长 · 探索深 · 训练价值高
粗粒度保证轨迹质量,PR/issue 作为后备提示保证 Dev 不会卡死

后备提示释放层级

层级信息来源释放条件示例
L0 最模糊 Issue 标题 初始就可见(需求背景) "QuerySet union() 与 annotate() 不兼容"
L1 方向级 Issue 描述 + 复现步骤 连续 3 次失败 "在 union 后调用 annotate,SQL 缺少列投影"
L2 模块级 PR 标题 + 描述 连续 5 次失败 "Fix union/intersection with annotate"
L3 文件级 PR 的文件列表 连续 8 次失败 query.py, compiler.py
L4 代码级 PR diff 关键片段 连续 12 次(最后手段) Query.combine() 第 542 行

04v1 → v2 关键变化

❌ v1 的做法

先设计任务,再收集轨迹

4 个 LLM 角色串行依赖

PM Agent 动态合成提示

每个 Feature 独立执行

任务间无关联

前置设计(靠假设)

✓ v2 的做法

先收集轨迹,再提炼任务

2 个 LLM + 规则/脚本

PR/issue 作为后备提示按需释放

沿里程碑持续开发

前序代码是后序的上下文

后置分析(靠数据)

维度v1v2为什么更好
设计哲学先设计任务,再收集轨迹先收集轨迹,再提炼任务数据驱动 vs 假设驱动
核心流程串行耦合三阶段完全解耦任何阶段可独立迭代
LLM 角色4 个2 个 + 规则/脚本复杂度大幅降低
提示机制PM Agent 动态合成粗粒度保证难度,PR/issue 按需释放不需要 LLM 合成提示
Dev 模型Sonnet-4.5(外部)HY3.0(默认)/ Opus-4.6(备选)目标模型低成本;强模型高质量轨迹
失败处理任务失败 → 丢弃STUCK → 给提示 → 继续失败本身是训练信号
最小验证需要全部角色就绪Stage 2 单独跑 3 天即可快速 Go/No-Go

05里程碑粒度:成败的关键

里程碑粒度 太细 合适 太粗 🔴 单 commit DomainNameValidator 126 行 / 2 文件 1-2 轮搞定 = SWE-bench 模式 🟢 完整 Feature LoginRequiredMiddleware 537 行 / 12 文件 / 跨模块 15-50 轮探索 试错 + 回退 + 方向调整 🔴 整个版本 Django 5.1 全部特性 数千行 / 100+ 文件 Dev 卡死 反复收提示 = 无效循环
经验法则:一个好的里程碑让 Dev 需要 15-50 轮交互。<10 轮太简单,>80 轮说明超出模型能力

06业界全景对比

轨迹完整性 → 任务复杂度 → 无轨迹 (patch) 单任务轨迹 (~20 turns) 长程连续轨迹 (~200 turns) 单文件 Bug Fix 跨模块 Bug Fix Feature + 重构 SWE bench 2.3K SWE smith 50K Coder Forge 258K Nebius 80K HarnessForge v2 规模可伸缩 长程 + 交互 + 多类型
HarnessForge v2 占据"长程 × 多类型 × 有交互"的空白象限,同时具备规模弹性
SWE-benchSWE-smithCoderForgeNebiusHarnessForge v2
任务类型Bug fixBug 注入 fixBug fixBug fixFeature+重构+fix
轨迹❌ 无✅ 单任务✅ 单任务✅ 单任务✅ 长程连续
交互❌❌❌❌✅ Mentor 提示
多语言PythonPythonPythonPythonPy/TS/Go/Rust
规模2.3K50K258K80K上限极高
Dev 模型——固定固定HY3.0(目标模型)
信息密度低中中中高
规模弹性固定固定固定固定Repo×Release×策略

07Stage 3:轨迹理解与任务提炼

有了详细的完整轨迹,筛选出好的 task 不是难事。

每条轨迹里天然包含了所有关键信号:卡住了多少轮、需不需要提示、提示后有没有调整方向、最终是否通过。这些信号是结构化的、可量化的——基本的规则过滤就能完成大部分筛选。

在没有数据的时候设计数据处理流程——这正是 v1 犯过的错误,不能重蹈覆辙。

轨迹中可直接识别的信号

信号如何识别价值
卡点连续 N 次 edit→test→fail,错误类型不变天然的 hard task
方向调整提示前后搜索/编辑的文件发生变化"从反馈中调整"的训练数据
渐进成功测试通过数从 0 → N 逐步增加问题分解和逐步推进
无效探索Dev 走一个方向多轮后回退负样本——什么不该做
高效路径< 15 轮完成,无需提示正样本——什么该做

可能的输出形式(待数据验证)

输出描述确定程度
完整里程碑轨迹全部 turns,训练长程能力基本确定
卡点片段从卡住到解决的 10-20 轮基本确定
按阶段切割探索→规划→编码→debug 各自独立待验证
更复杂的提炼取决于数据实际长什么样完全待定

什么时候做:Phase 1 拿到第一批轨迹后,先人工看 5-10 条,理解数据特征,再设计具体规则。不排除"整条轨迹直接训练效果就很好"的可能性。让数据说话。

7½Stage 2 备选:渐进式 Harness 增强

一开始让 Dev 自由发挥。拿到数据后,再考虑加 Harness 组件。

版本复杂度新增组件何时引入
V0(当前)★Dev + Mentor + Recorder初始版本
V1★★+ Plan 要求:Dev 每个里程碑先输出开发计划数据显示 Dev 无规划就动手、频繁返工
V2★★★+ Plan 审查:计划与 ground truth 对比,偏差大时纠正V1 数据显示 Dev 计划质量差
V3★★★★+ 阶段检查点:每改完一个模块,检查中间状态V2 数据显示 Dev 中途偏离但最后才发现

关键原则:每一级增强都基于前一级的数据反馈,不预设。

渐进式增强本身也产出高价值训练信号——"plan → 被纠正 → 修正 plan → 执行"的轨迹训练规划和自我修正能力。但这些都是未来选项,先跑通 V0。

08实施路线

1 最小验证 3 天

选 1 个 repo(Django),3 个里程碑。Docker 环境 + HY3.0 作为 Dev,手动充当 Mentor。记录完整轨迹,人工分析。

成功标准:3 个里程碑的轨迹中,至少提炼出 5 个有训练价值的 task。

2 自动化管线 2 周

编写 milestone_runner.py + mentor_service.py + recorder.py。5 个 repo,~70 个里程碑轨迹。Stage 3 分析脚本:卡点识别 / 试错修正对提取 / 片段切割。

3 规模化 + RL 验证 3 周

15 个 repo 全量执行。消融实验:长程 vs 单任务、有交互 vs 无交互、HarnessForge v2 vs CoderForge 头对头。RL 训练 + SWE-bench 评测。

09风险评估

风险严重程度缓解
Dev 在复杂里程碑上完全卡死高Phase 1 就能发现;用更强模型做 Dev 备选
长程轨迹在 RL 训练中不如短任务有效中消融实验验证;Stage 3 片段切割兜底
上下文窗口溢出中每个里程碑重置上下文 + 保留摘要
Mentor 提示后 Dev 无方向变化中Mentor 用 Opus + ground truth;Phase 1 验证
里程碑依赖太紧,某个失败后续全崩低STUCK 时用 verify_commit 强制推进
预训练数据污染——Dev "记住了答案"而不是在探索高见下方专节讨论

9½核心风险:预训练数据污染

我们选的高 star 知名 repo,恰好是预训练数据中覆盖最充分的那批。HY3.0 的训练集里大概率包含了 Django 的每一个 commit、每一条 PR。当我们给它"实现 GeneratedField"的任务时,它可能不是在探索,而是在回忆。

这种轨迹拿去做 RL,强化的是记忆而不是推理能力。

为什么不是致命的

预训练学到的是"知识",RL 要训练的是"行为"。一个人读过 Django 源码,不代表他能在一个复杂 bug 中高效定位问题。RL 训练的是后者。

✓ 天然 unseen 的信号

  • 粗粒度里程碑的组合——见过 A 和 B,但没见过"做完 A 紧接着做 B"
  • Dev 的执行偏差——不同的变量名、不同的 debug 顺序
  • 卡点和提示响应——特定模型在特定上下文中的行为序列
  • "记住一部分但没记住全部"的中间地带——探索行为最真实

✗ 需要警惕的信号

  • Dev 前 3 轮就精准定位到正确文件 → 高度疑似记忆
  • 从未走错方向、从未需要提示、从未回退 → 疑似记忆
  • seen repo 上提升 10% 但 unseen repo 只提升 2% → RL 强化了记忆

缓解措施

阶段措施具体做法
Stage 1
Repo 筛选
混入低污染 repo2025 年底之后新建的 repo(cutoff 之后)、star 500-2000 的小众高质量项目、知名 repo 的最新 release(接近 cutoff 边界)
Phase 1
验证
直接测量 contamination给 Dev 里程碑任务,零提示观察:前 3 轮精准定位 = 疑似记忆;10+ 轮搜索试探 = 较真实。统计比例,超 50% 需调整
Stage 3
轨迹提炼
contamination 过滤从未走错方向 + 从未需要提示 + 从未回退 → 标记为"疑似记忆",降低权重或排除
RL 训练
验证
held-out unseen repo留出一组不在任何训练数据中的新项目,作为 RL 效果的真实测量基准

坦率的判断:这个风险是真实的,但不是致命的。RL 训练的核心目标是行为策略,不是知识。即使 repo 见过,执行层面的探索行为仍然是新的。通过 repo 选择、Phase 1 测量、Stage 3 过滤,可以量化并控制风险。

最坏情况:即使 contamination 严重,Stage 3 仍然能识别出真实的探索片段——只是量会少一些。

10核心教训

不要在没有数据的时候做优化。

v1 设计了精巧的五角色系统来"合成高质量任务"。这些设计全建立在未经验证的假设上。

退后一步问"最简单的方式是什么?"——让 Agent 直接去开发,把过程录下来,之后再分析。

这和预训练数据的核心经验一致:数据采集和数据筛选应该解耦。没有人试图在爬取阶段就"只爬高质量数据"。v1 犯了同样的错误:在轨迹采集阶段做了任务设计的事。

先采集,再筛选。让数据说话。