一次生成还是多轮修补:两种工作流的真实产出效率对比
一次生成还是多轮修补两种工作流的真实产出效率对比用 4B 小模型生成一个能跑的单文件 Three.js 场景真正的分岔点不在提示词写得多漂亮而在第一次生成之后你做什么选择重新掷骰子还是拿着上一版代码打补丁。前者看起来干净后者看起来脏但在本地推理的算力账本上两者的成本结构完全不同。这篇文章不讲玄学只把两条工作流的步骤、计时段、返工判据摊开用仓库里能核对的事实模型卡说明、config.json、generation_config.json、chat_template.jinja、权重索引和第三方实测结论回答三个问题什么东西一次性就能过什么东西一定要返工以及返工时该在第几轮止损。一、先把两条工作流的步骤拆干净很多一次生成更快或多轮修补更稳的争论本质是计时口径不一致有人只算模型出字的时间有人把打开浏览器、肉眼验收、CtrlF 找变量名全算进去。为了让后面的账能对齐先定义轮round一轮 一次完整 decode 结束到产出可打开的 HTML 文件并且完成一次验收。验收包含是否黑屏/报错、相机是否可控、物体是否成组、动画是否在跑。在此定义下两条工作流拆成四个计时段计时段含义一次生成多轮修补T_prefill系统提示词 用户提示词 修补时上一版代码 诊断信息的前向固定短随代码量增长但可被前缀缓存命中D_thinkthink段落的解码 token存在模板默认开启通常可关闭D_code/D_patch场景代码或补丁的解码 token全量D_code只出D_patchT_review人或脚本验收的时间全量全量但可被静态检查压缩于是T_one T_prefill(P) D_think D_code T_review T_repair T_prefill(P C Δ) D_think D_patch T_review其中C是上一版完整代码Δ是一行到几行诊断信息第 214 行const box与第 97 行重名这种。这里有一个容易被忽略的事实T_repair里的T_prefill几乎不是线性增长的。这颗模型是混合注意力结构config.json 的layer_types给出 32 层里每 4 层才出现一层full_attention也就是 24 层linear_attention 8 层full_attention。线性注意力层的状态是常数大小只有 8 层全注意力层随长度累积 KV。按num_key_value_heads: 4、head_dim: 256、fp16 计算每 token KV ≈ 8 层 × 2K/V× 4 头 × 256 维 × 2 字节 32 KiB/token24 层线性注意力状态 24 × (16×128 32×128) × 4 字节 ≈576 KiB且与长度无关也就是说把一份 8000 token 的场景代码整份留在上下文里做修补KV 增量约 250 MiB 量级对 8 GB 显存 Q4_K_M实测文件 2,708,804,096 字节约 2.52 GiB来说完全放得下。多轮修补在这颗模型上是工程可行的而不是上下文撑不住只能重开。这是后文所有结论的物理前提。同时max_position_embeddings: 262144意味着你不需要为爆上下文做代码摘要压缩——摘要本身就会丢结构信息进而制造新的返工。二、耗时与返工率能把话说到什么程度仓库里能直接核对的事实只有三条但它们足够改变决策习惯。第一条一次成功率不是常数是随检查点移动的。README.md 的 10 月 27 日检查点说明写明one-shot success has improved substantially, along with overall scene quality紧接着一句是 Some scenes can still require another attempt or a correction。这句话的价值在于它把一次生成从信仰问题降级为概率问题——它承认剩余失败率存在并且没有说失败就代表前一轮作废。第二条失效类型是局部的。同一份 README 的 Known issues 明确写观察到的问题主要集中在 duplicate variable names而不是结构性问题。这条信息决定了修补路径的成本上限。重名变量意味着场景图建对了、材质对了、相机对了、动画循环也在跑只是某个const覆盖了另一个。补丁长度通常只有几行到几十行。第三条第三方实测显示同一个模型在不同宿主环境里结果可以完全不同。在一份覆盖 6 道前端题的横向实测中纯 CSS 山水画、分形烟花、五子棋、横版跑酷、3D 太阳系、诗词代码雨同一个 Qwen3.5 在 IDE 环境与 CLI 环境里出现了一次就崩和表现尚可的互换3D 太阳系那一题在 CLI 里只渲染出一个球事后诊断出的失效清单是 6 条可定位的局部问题Three.js 0.160 用传统 script 方式加载、PointLight强度过低导致行星全黑、太阳光晕用了BackSide、事件绑定发生在init()之前、sunMesh重复存储、以及用 2D 曲线去画 3D 轨道。这 6 条里有 5 条是单点可改的。如果把这道题交给重生成等于用一个随机过程去重新抽这 6 个失效点的组合交给修补等于按清单逐条消项。由此可以得到一个不该被绕过的结论返工率必须按失效类型分层统计而不是按题目统计。把环境加载失败MTP 导致的乱码真正的建模错误混在一个返工率里算得到的数字没有指导意义。顺便把最容易混进返工率的一类噪音排掉。社区一直在传LM Studio 里必须关闭 MTP仓库这边能对上config.json里保留了mtp_num_hidden_layers: 1的字段但 model.safetensors.index.json 的 723 个权重条目里没有任何mtp.*张量。运行时若按 MTP 路径去找一个不存在的预测头输出乱码或截断是可以预期的。所以打开就乱、重试也没用的轮次应该记进环境故障不能记进模型返工——否则你会错误地得出这模型一次成功率很低的结论然后去做大量无意义的重生成。三、成本模型什么条件下修补一定赢把上面的事实写成判据。设首次一次成型概率为p单次定点修补成功率为q全量代码解码量为D_code补丁解码量为D_patch。只靠重生成的期望解码成本E_reg ≈ D_code / p只靠单轮修补的期望解码成本E_fix ≈ D_patch / q切换条件化简为D_patch / D_code p / q → 该重生成 D_patch / D_code p / q → 该修补代入两类真实失效失效类型典型表现D_patch / D_codeq量级推论局部型重名变量、光照强度、事件绑定顺序、材质参数有画面但不对或控制台单条报错0.02–0.05高诊断明确了就基本能改对修补占绝对优势结构型黑屏、只有占位球、场景空整页无内容或只有一个几何体≈ 1等于重写低直接重生成这里的关键不是具体数值而是分母D_code的量级一个完整 Three.js 场景单文件通常包含几何构造、材质、光照、相机控制、动画循环、UI 覆盖层代码体量在数百到两千行、数千到上万 token 之间。任何一次重掷都要重新支付这个体量而修补只支付其中 2%–5%。再叠加一层人工成本修补轮的T_review是定向的我刚改的那一处好了没重生成轮的T_review是全局的重新检查所有约束。验收成本的方向和模型成本的方向是一致的都偏向修补。四、复杂度区间一次成型的边界划在哪仓库的画廊给了四类难度不同的参照物可以直接当分档样本看。单主体、单相机机位的场景一次成型概率最高。比如樱花盆栽这一档一个花盆、一株主干、若干花瓣实例、一片地面验收标准是像不像而不是对不对。同类还有 LGA 3647 插槽单一硬件件的结构还原和书桌、装订工作台室内静物 固定视角。它们的共同点是约束条数少、失效后果可辨认。变量重名这类问题在这里表现得很明显——页面直接白屏或某个物件消失一眼定位。多区域组合型就进入返工高发区。龙骑士海蚀柱这一档提示词里同时压进了平顶海蚀柱、四个外挑石台、中央拱顶孵化洞含沙巢与排烟口、木质平台与吊装架、之字形楼梯、水线船屋。这不是一个物体是六个功能区的空间关系任何一处坐标或层级写错整体轮廓就读不出来。最上面一档是动态与交互型。README 里的机场塔台例子要求顶部监视雷达持续旋转 旋转信标属于时间轴正确性问题而系统提示词又强制不引入 addons、相机控制必须写在 HTML 里等于把OrbitControls的实现责任交还给模型。这一档的典型失败不是报错而是能渲染但不对——动画跑得起来但轨道倾角错了拖拽能转但极角没有夹紧导致穿模。据此可以把分档和预期轮数对齐档位判据典型 prompt 形态预期轮数A 单主体≤1 个主几何体 环境a sakura bonsai in a ceramic pot1大概率B 多物件排布3–10 个语义物件固定机位室内工作台、硬件件1–2C 多区域组合≥3 个功能区 空间连接海蚀柱、运河船闸与中心岛2–3D 动态交互动画循环 相机控制 UI塔台雷达、可点击标签2–4注意一个反直觉点提示词越长p不一定越高。README 里运河船闸只给了一句话模型自由度极大但验收也跟着变主观龙骑士那段给到三段细节模型出错概率上升但每一处错误都可以对着原文逐条核对。前者的问题是没有标准后者的问题是标准太多。返工成本高的是后者但不可判定的是前者——这也是为什么一句话题目经常被误判成一次成功。五、组合切点在第几轮停止修补把所有证据收敛成可执行的规则只需要三个阈值。切点一先分清是模型错还是环境错。在统计任何返工率之前先确认三件事MTP 已关闭权重里没有mtp.*张量开了就是自找乱码、量化档位与显存匹配、CDN 可达。Q4_K_M 与 Q8_0 的权重体积差 1.65 倍2,708,804,096 vs 4,482,402,816 字节decode 的带宽压力差别明显但 README.md 对两者给的是同一套生成参数并没有给出两者一次成功率的对比——这个差异只能自己采样不能假设。切点二按失效清单条数决定动作。现象动作页面有内容报错 ≤1 条或存在重名变量修补单轮只回传诊断行页面有内容报错 2–3 条且互相独立修补一次给全清单禁止分三轮问黑屏 / 只有占位体 / 场景为空重生成先收缩 prompt 范围再跑连续两轮修补后同一指标如相机能否拖拽无改善立刻重生成不要赌第三轮切点三需要换解法时才动采样参数。仓库给定的区间是Temperature 0.6–0.8、Top P 0.90–0.95、Top K 20–40、Repeat penalty 1.0而 generation_config.json 的默认值落在保守端0.6 / 0.95 / 20 / 1.0。这意味着第一次生成应当用默认值贴近训练分布只有在重生成时希望得到结构不同的解才把温度推到 0.8 上界、top_k提到 40。repeat penalty保持 1.0 不要往上加——它压制的正是重复标识符调高反而会诱导模型换名制造新的重名冲突。修补轮还有一个上下文卫生问题模板层面就能处理。chat_template.jinja 对历史 assistant 消息是这样处理的如果消息里带reasoning_content会把它重新包进think.../think再拼进上下文并且在add_generation_prompt阶段只有当enable_thinking显式为false时才写入一个空的think\n\n/think块。也就是说一次生成默认是带思考的D_think是T_one里最不可控的一块修补轮应该显式关掉思考否则每一轮都在为重新想一遍整个场景付费而你需要它想的只是那三行补丁但要注意训练数据是带完整 thinking traces 的README 明确数据集包含 full thinking traces关思考属于分布外使用质量变化需要实测不能当成无脑加速开关。六、一套能自己跑的采样与验收流程上面所有判据都依赖两个可测量一次成功率p和补丁比例D_patch / D_code。它们都能用几十行脚本测出来不需要主观争论。先起服务参数严格照 README 的区间给llama-server \ -m ./Qwen3.5-4B-3D-Coder-Q8_0.gguf \ --port 8080 \ --temp 0.6 --top-k 20 --top-p 0.95 --repeat-penalty 1.0然后用curl的 write-out 直接拿到首 token 时间与总时长把T_prefill D_think和总时长分开看for i in 1 2 3 4 5; do curl -s -o out/run-$i.json \ -w run $i ttft%{time_starttransfer}s total%{time_total}s\n \ http://127.0.0.1:8080/v1/chat/completions \ -H Content-Type: application/json --data req.json python3 -c import json,sys djson.load(open(out/run-$i.json)) open(out/run-$i.html,w).write(d[choices][0][message][content]) done拿到 5 份 HTML 之后验收不要靠肉眼先用静态检查把局部型失效秒级筛出来。README 的已知问题就是重名变量这类问题在浏览器里表现为黑屏或物件消失但在静态检查里是一行报错for f in out/run-*.html; do # 1) 是否引用了不允许的 addons / 旧版 examples/js grep -nE addons|examples/js|OrbitControls $f echo $f: 违反系统提示词约束 # 2) 抽出 module 脚本做语法检查重名变量会在这里暴露 python3 - $f PY import re,sys,subprocess,tempfile,os sopen(sys.argv[1]).read() mre.search(rscript[^]*typemodule[^]*(.*?)/script, s, re.S) if not m: print(sys.argv[1], no module script); sys.exit() fd,ptempfile.mkstemp(suffix.mjs); os.write(fd, m.group(1).encode()); os.close(fd) rsubprocess.run([node,--check,p],capture_outputTrue,textTrue) print(sys.argv[1], OK if r.returncode0 else FAIL r.stderr.strip().splitlines()[-1]) PY done这一步把T_review从打开浏览器看图压缩到看一行输出而且是可复现的。只有通过静态检查的样本才值得进入人工审美评估——这才是一次生成工作流真正省时间的地方它省的不是 decode而是验收。最后是判据落地把这 5 次的通过数记成p把每次修补的 diff 行数除以原文件行数记成D_patch / D_code。当D_patch / D_code稳定落在 0.02–0.05、而p在 0.4–0.8 之间时纯重生成策略的解码成本是修补策略的 8–40 倍这时候多轮修补显得慢只是因为它把时间花在了人看得见的地方。一个 4B 模型的现实价值不在于它每次都对而在于它错得足够浅浅到一行 diff 能修浅到关闭思考后一轮补丁几十秒就能拿到浅到整份代码塞进 262144 的位置上下文里也不用做有损压缩。工作流的选择应该围绕这个特性来设计——把重生成留给结构性崩坏把修补留给局部失配把参数调整留给真的需要换解法的时候。剩下的都只是验收流程没做好而已。创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考