ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Ornith-1.5 从自我脚手架到自我改进:MoE 与 Dense 架构下 GRPO 的 SWE-bench 实战拆解

2026/10/4 22:32:42 拓冰建站 浏览量
Ornith-1.5 从自我脚手架到自我改进:MoE 与 Dense 架构下 GRPO 的 SWE-bench 实战拆解 1. Ornith-1.5 自我改进闭环到底解决了什么工程问题如果你最近在折腾 SWE-bench 这类仓库级修复评测大概率会遇到一个很尴尬的局面模型在单文件补丁上表现还行一旦任务变成读懂一个陌生仓库、定位跨文件调用链、改完还要跑通测试成功率就断崖式下跌。Ornith-1.5 这篇论文想回答的正是这个落差从哪来、又该怎么补。先说清楚它是什么。Ornith-1.5 是一个端到端的自我改进框架核心思路是让模型自己出题、自己搭脚手架、自己产出解题轨迹再用 GRPO 把这三个环节联合优化。它适合谁适合两类人一类是想复现 GRPO 训练流程的算法工程师另一类是只想拿它当编码 Agent 用、关心 SWE-bench Verified 分数的应用开发者。前者关心训练循环怎么搭后者关心推理时怎么接。它和 Ornith-1.0 的区别在于闭环的完整度。1.0 只做了自我脚手架——给定任务模型生成指令、工具、分解策略。1.5 把任务生成和轨迹生成也纳入同一个循环奖励信号反向传播到全部三个阶段。用一句话概括1.0 是模型学会怎么解题1.5 是模型学会怎么出题、怎么搭台、怎么解题三件事一起练。这里有个容易被忽略的工程细节。论文里任务奖励是乘积形式有效性 V、前沿难度 D、新颖性 N 三者相乘。乘积意味着任何一项为零整个任务奖励就归零。这在实际训练里非常关键——它天然过滤掉了看起来很难但根本没法验证的脏任务。我见过不少自训练 pipeline 崩掉就是因为任务生成器开始产出无法验证的题目模型在错误奖励上越练越偏。乘积门控相当于给数据质量上了一道硬闸。架构层面Ornith-1.5 分三档397B MoE 旗舰、35B MoE每 token 激活 3B、9B Dense。这个划分本身就值得琢磨。MoE 用稀疏激活换容量Dense 用全参数激活换部署便利。9B Dense 能塞进手机靠的是量化35B MoE 每 token 只激活 3B推理成本接近一个 3B 密集模型但容量是 35B 级别。理解这个差异直接决定了你后面选哪个模型跑 SWE-bench、显存怎么算、batch 怎么设。SWE-bench Verified 上397B 拿到 86.035B 拿到 79.09B 拿到 70.6。9B 这个数字很有意思——它超过了 Gemma 4-31B 的 52.0 和 Qwen 3.6-35B 的 73.4。一个 90 亿参数的密集模型在仓库级修复任务上打赢了 30B 级别的对手这说明自我改进循环带来的数据质量提升可能比单纯堆参数更划算。对预算有限的团队来说这个信号比旗舰分数更有参考价值。接下来我会按环境准备 → GRPO 配置 → SWE-bench 评测 → 报错排查的顺序把可复现的片段拆开讲。训练部分给 JSON 配置评测部分给脚本中间穿插 MoE 和 Dense 在显存与并行策略上的差异。2. 接入前的环境准备与模型选型MoE 与 Dense 的显存账怎么算在写任何配置之前先把模型选型和显存账算清楚否则后面 GRPO 一跑就 OOM排查起来很浪费时间。先说接入侧。如果你只是想调用 Ornith-1.5 做编码任务不需要自己跑训练那走 API 是最省事的路径。TaoToken 提供了统一的模型接入入口Base URL 是https://taotoken.net/api模型对话入口在https://taotoken.net/api对应的对话页API Key 在控制台的 api-keys 页面生成。这套接入对 OpenAI 兼容协议友好后面配置里我会用标准的环境变量方式写方便你直接复制。选型上我建议按显存和任务类型分三档模型架构激活参数典型显存需求推理FP16适用场景Ornith-1.5-397BMoE旗舰级多卡需张量并行高难度 SWE-bench Pro、跨仓库任务Ornith-1.5-35BMoE每 token 3B单卡 48G 可跑量化日常编码 Agent、批量评测Ornith-1.5-9BDense9B 全激活单卡 24G量化后更小端侧、本地快速验证MoE 的显存账和 Dense 不一样。35B MoE 虽然总参数 35B但每 token 只激活 3B推理时的计算量接近 3B 密集模型可显存占用仍要装下全部专家权重。所以你会看到一个现象35B MoE 的推理速度可能比 9B Dense 还快但显存占用反而更高。做 GRPO 训练时这个差异更明显因为训练要存优化器状态和梯度MoE 的专家参数都要参与更新显存压力比推理大得多。我试过在单卡上跑 35B MoE 的 GRPO结论是必须上 LoRA 或者冻结部分专家否则优化器状态直接爆。Dense 的 9B 相对友好全参数微调在 80G 卡上能跑但 batch 要压得很小。环境依赖方面核心是这几样Python 3.10、PyTorch 2.3、vLLM推理和 rollout 用、transformers、以及 SWE-bench 官方的评测 harness。如果你用 OpenHands 做评测工具包还要装它的依赖。论文里提到他们改了 Harbor 来适配 vLLM 的reasoning_content键这个改动在你自己搭评测时也要注意否则推理输出里的思维链字段会丢。一个实操建议先用 9B Dense 把整条链路跑通包括 GRPO 配置加载、rollout、奖励计算、SWE-bench 评测脚本。链路通了再换 35B MoE 或 397B这样出问题能快速定位是配置问题还是规模问题。我踩过的坑就是一开始直接上大模型结果 OOM 和配置错误混在一起排查了两天才发现是 chat template 没对齐。关于 chat template论文脚注里专门提了调整 Qwen 聊天模板以确保训练和推理之间的一致性。这句话分量很重。Ornith-1.5 基于 Qwen3.5 和 Gemma 4 扩展如果训练时用的模板和推理时不一致模型输出的格式会漂移SWE-bench 的 parser 直接解析失败。所以你在配置里一定要显式指定 chat template别依赖默认值。3. 可复制的 GRPO 配置片段与三阶段奖励设置这一节给可直接落地的配置。先给训练侧的 GRPO 配置用 JSON 写路径按你本地实际调整。{ model_name_or_path: ornith-1.5-9b-dense, architecture: dense, grpo: { num_generations: 8, max_new_tokens: 8192, temperature: 1.0, top_p: 0.95, kl_coef: 0.001, clip_range: 0.2, learning_rate: 1e-6, per_device_train_batch_size: 1, gradient_accumulation_steps: 8 }, reward: { task_reward: validity * frontier_difficulty * novelty, validity_gate: true, frontier_target_success_rate: 0.2, novelty_buffer_size: 10000, toolkit_reward: faithfulness * fidelity * hack_resistance }, rollout: { backend: vllm, tensor_parallel_size: 1, gpu_memory_utilization: 0.85, enable_reasoning_content: true } }几个参数要重点解释。num_generations设为 8是因为 GRPO 靠组内相对奖励来估计优势组太小方差大组太大显存吃紧。8 是个平衡点。frontier_target_success_rate设 0.2对应论文里成功率接近 20% 最好的前沿难度定义——太难产不出成功轨迹太易没有学习信号。validity_gate打开后有效性为零的任务直接奖励归零这就是前面说的硬门控。novelty_buffer_size控制历史任务库大小用来算新颖性太小会导致重复任务被反复生成太大则显存和检索开销上升。MoE 版本要额外加专家并行配置{ model_name_or_path: ornith-1.5-35b-moe, architecture: moe, expert_parallel_size: 2, moe_lora: { enable: true, target_modules: [q_proj, v_proj, gate_proj], r: 16, lora_alpha: 32 }, grpo: { num_generations: 4, per_device_train_batch_size: 1, gradient_accumulation_steps: 16 } }MoE 上 LoRA 是为了压优化器状态。expert_parallel_size按你的卡数设两张卡就设 2。注意 MoE 的num_generations我降到 4因为显存更紧张组内样本数只能牺牲一点。接入侧如果你走 API 而不是本地训练配置更简单用环境变量export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-your-key-here export ORNITH_MODELornith-1.5-35b-moe然后在代码里用 OpenAI 兼容客户端指向这个 Base URL。模型 ID 填ornith-1.5-35b-moe或对应版本。这里三件套要齐全Base URL、API Key、Model ID缺一个都会报 401 或 model not found。三阶段奖励的落地我建议拆成三个独立函数别揉在一起def validity_reward(task, scaffold, solution): if not scaffold.runs_successfully(): return 0.0 if not high_confidence_solution_passes(solution): return 0.0 if obviously_wrong_solution_passes(solution): return 0.0 return 1.0 def frontier_difficulty(success_rate, target0.2): return 1.0 - abs(success_rate - target) / max(target, 1 - target) def novelty_reward(task, buffer): max_sim max(similarity(task, t) for t in buffer) if buffer else 0.0 return 1.0 - max_simvalidity_reward里那三个检查对应论文里的有效性定义脚手架能跑、高置信解通过、明显错误解失败。第三个检查最容易被忽略但它是防奖励作弊的关键——如果错误解也能通过说明评估环境不可靠这个任务就不该给奖励。frontier_difficulty用成功率到 0.2 的距离做惩罚越接近 0.2 分越高。novelty_reward用和历史任务的最大相似度反向计算越不相似分越高。工具包奖励单独算对应论文里的 C、F、H 三项忠实反映任务规范、奖励追踪真实质量、抵抗奖励作弊。这三项在实现时可以用人工抽检加自动检测结合纯自动很难做准。4. SWE-bench 评测脚本与成功结果验证配置好了接下来是评测。SWE-bench 的评测脚本核心是三步拉取任务实例、让模型生成补丁、跑测试验证。import json import subprocess from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keysk-your-key-here ) def generate_patch(instance): prompt build_swe_prompt(instance) resp client.chat.completions.create( modelornith-1.5-35b-moe, messages[{role: user, content: prompt}], temperature1.0, top_p0.95, max_tokens131072 ) return extract_diff(resp.choices[0].message.content) def run_eval(instances, output_file): results [] for inst in instances: patch generate_patch(inst) passed apply_and_test(inst, patch) results.append({ instance_id: inst[instance_id], resolved: passed, patch: patch }) with open(output_file, w) as f: json.dump(results, f, indent2) return resultsapply_and_test里要做反作弊处理这点论文专门强调了从本地仓库镜像移除 Git 历史、禁用网络访问。移除 Git 历史是防止模型翻提交记录找答案禁网是防止它去外部检索。你自己搭评测时如果漏了这两步分数会虚高而且虚高得没有意义。def apply_and_test(instance, patch): repo_dir prepare_repo(instance, strip_git_historyTrue) disable_network(repo_dir) apply_patch(repo_dir, patch) result subprocess.run( instance[test_command], cwdrepo_dir, capture_outputTrue, timeout1800 ) return result.returncode 0超时设 1800 秒对应论文里 4 小时超时的一半左右实际按任务复杂度调。上下文窗口论文用的是 256K你如果显存不够可以降到 128K但跨文件任务的成功率会掉。成功结果长这样脚本跑完输出一个 JSON里面每个实例有resolved字段。统计resolved为 true 的比例就是 SWE-bench Verified 的分数。35B MoE 的目标是 79.0 左右9B Dense 是 70.6 左右。如果你跑出来明显低于这个数先别怀疑模型去查 chat template 和 parser 设置。验证请求是否真的通了可以用一个最小请求curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: ornith-1.5-35b-moe, messages: [{role: user, content: print hello}], max_tokens: 64 }返回里有choices[0].message.content就说明链路通了。如果返回里带reasoning_content字段说明思维链输出正常这对 SWE-bench 这种需要多步推理的任务很重要。从自我脚手架过渡到自我改进阶段验证动作清单我列一下第一确认任务生成器产出的任务有效性门控通过率在合理区间太低说明生成质量差太高可能门控太松第二确认前沿难度分布集中在成功率 0.2 附近偏离说明课程没演进第三确认新颖性分数没有持续走低走低说明任务开始重复第四确认工具包奖励的作弊检测有实际拦截记录没有拦截说明检测太弱。这四条都正常才说明闭环真的在自我改进而不是在原地打转。5. 常见报错排查401、local proxy failed 与 reading choices这一节按真实报错来。我把接入和评测里最容易撞的几类错误拆开讲。401 Unauthorized。这个最常见原因基本是 Key 没配对或没带上。检查三件套Base URL 是不是https://taotoken.net/apiAPI Key 是不是从控制台 api-keys 页面复制的完整串Model ID 是不是写对了。注意 Base URL 末尾不要多加/v1有些客户端会自动补重复了会 404。如果你用环境变量确认export在当前 shell 生效别在子进程里丢了。local proxy failed。这个报错通常出现在客户端配置了本地代理但代理没起来或者代理地址写错。排查顺序先确认本地有没有跑代理进程再看客户端配置里的代理地址和端口对不对。如果你根本没打算用代理就把相关环境变量清掉unset HTTP_PROXY HTTPS_PROXY避免客户端误读。这类问题和网络环境相关配置干净最重要。Error reading choices / choices 字段为空。这个多半是响应格式和解析代码不匹配。可能原因有三个一是模型返回的是流式你没按流式解析二是返回体里choices为空数组通常是请求被拦截或模型拒答三是reasoning_content和content字段混淆你取错了字段。排查时先把原始响应打印出来看结构别直接取choices[0]。resp client.chat.completions.create(...) print(resp.model_dump_json(indent2))打印出来你就能看到实际字段名。论文里提到他们改了 Harbor 适配 vLLM 的reasoning_content键就是因为这个字段在不同后端命名不一致取错了就拿到空内容。OAuth / 认证相关报错。如果你用的是 Claude Code 这类工具接入可能会碰到 OAuth 流程问题。这类工具通常要求配置 Base URL、API Key、Model ID 三件套缺一个就走不通。配置时注意别把 OAuth token 和 API Key 混用两者认证路径不同。如果工具报 OAuth 失败先确认你用的是 API Key 模式而不是 OAuth 模式。显存 OOM。MoE 训练时高发。降 batch、开 LoRA、减num_generations、降gpu_memory_utilization四个手段按顺序试。Dense 9B 如果还 OOM检查是不是优化器状态没开 8-bit。评测分数异常低。先查 chat template 一致性再查 parser 设置最后查反作弊是否误伤。论文里 SWE-bench 用 OpenHands 工具包temp1.0top_p0.95上下文 256K这些参数对不上分数就会偏。任务生成器产出大量无效任务。检查有效性门控的三个条件是不是都实现了特别是明显错误解失败这一条漏了的话脏任务会大量涌入。排查时有个通用原则先确认链路通最小请求能返回再确认格式对字段名匹配最后确认参数准温度、上下文、parser。按这个顺序走大部分问题十分钟内能定位。6. 把闭环跑起来从接入到长期编码的路径选择到这里配置、评测、排查都过了一遍。最后说下路径选择因为不同人的需求差别很大。如果你只是想验证 Ornith-1.5 的编码能力不想碰训练那直接走模型对话入口用 API 调 35B MoE 或 9B Dense 跑几个 SWE-bench 实例看补丁质量和测试通过率。这是最快的验证方式半小时能出结果。模型对话入口在https://taotoken.net/api对应的对话页选好模型 ID 就能开始。如果你要长期做编码 Agent比如接进 IDE 或者 CI 流程那 Coding Plan 更合适。它适合需要稳定调用、批量任务、长期运行的场景。配置上还是那三件套Base URL、API Key、Model ID但要注意并发限制和超时设置批量跑 SWE-bench 时单实例超时别设太短。如果你要复现 GRPO 训练那重点在数据质量和奖励设计不在模型规模。先用 9B Dense 把三阶段奖励跑通确认任务生成器产出的任务有效性、前沿难度、新颖性三个信号都正常再换大模型。训练侧的接入文档在https://taotoken.net/api对应的文档页里面有完整的参数说明。一个实用技巧把自我改进循环的四个验证动作做成监控指标每次训练周期结束自动跑一遍。有效性通过率、前沿难度分布、新颖性均值、作弊拦截数这四个数画成曲线你就能直观看到闭环是在进化还是在退化。这比盯着 loss 曲线有用得多因为自我改进的核心是数据质量不是损失下降。最后提醒一句反作弊保护在自训练里不是可选项。移除 Git 历史、禁网、屏蔽外部仓库这三步漏任何一步你的评测分数都会虚高而且训练出来的模型会学会走捷径。论文里专门强调这点是因为奖励作弊在自改进循环里会被放大——模型一旦发现捷径后续生成的任务和轨迹都会往捷径上靠。把门控做严短期分数可能低一点但长期才站得住。