尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Reasoning Core: 用程序化数据与补全监督破解推理训练数据瓶颈

Reasoning Core: 用程序化数据与补全监督破解推理训练数据瓶颈 最近在做推理模型训练的同学大概率已经感受到一个共同的瓶颈不是模型结构不够强而是找不到足够好的推理训练数据。人工写推理链贵、慢、规模上不去全靠大规模生成式采样质量又不可控跑到后面模型会不断重复同一套错误模式。这个问题的本质在于我们缺少一种能把“推理能力”批量生产出来的数据工程方法。Reasoning Core 这篇工作给出的解题思路很有意思。它没有把重心放在模型结构上而是同时动了两刀用程序化数据生成解决“数据从哪来”的问题用补全监督解决“模型怎么学”的问题。这篇文章我会从这三个关键词——Reasoning Core、Procedural Data、Completion-Supervised——拆开讲清楚这套方法到底在做什么为什么它能同时缓解数据规模、标注成本、监督信号三个问题以及如果你想把类似思路用在自己的训练流程里应该怎么设计数据流水线、怎么写代码、怎么验证效果。整篇文章偏实践建议收藏后按章节跟进尤其适合正在做大模型推理微调、SFT 数据构建和 RL 训练前数据准备的同学。1. 为什么推理训练会卡在数据上先从一个真实的工程场景说起。假设你要训练一个数学推理模型。常规做法是找一批数学题人工写清楚每一步推理过程做 SFT。第一批 1 万条数据效果立竿见影第二批再来 1 万条提升开始变缓到了 5 万条以后你会发现几个问题同时出现人工写步骤的成本太高。一道稍微复杂的题写出完整的中间推理链可能需要 10 分钟以上折算下来一条高质量数据的成本并不低。数据风格会收敛。同一个标注员写出来的推理链换汤不换药多个标注员之间又存在风格漂移。数据规模增加但多样性跟不上。监督信号太“整”。标准 SFT 让模型预测整条推理链模型只需要学会“像人话一样说话”而不是真正学会“在关键位置做关键决策”。问题出在哪一步梯度信号并不会精确告诉我们。工程上更麻烦的是第三个问题。模型在训练时把整段答案当作一个序列去拟合如果推理链里有 20 步其中 5 步错了这 5 步的错误信号会被稀释到整段序列的 loss 里。结果就是模型学会了下一次写出“形状正确但细节不对”的推理过程俗称推理幻觉。Reasoning Core 这条路线想做的就是把推理训练从“学说话”变成“学补步骤”。它不再要求模型从零生成完整推理链而是把推理链拆好、遮住关键环节让模型只负责补全被遮住的那些步骤。同时被遮住的这些步骤来自程序化生成的推理核心天然可以被自动校验。两个机制叠加数据规模、成本、监督精度三个问题一起缓解。这个思路用一句话概括用程序批量造题用补全精确纠错。2. 三个关键词到底是什么意思在往下拆之前先把标题里三个核心概念讲清楚。这三个词其实是三层嵌套的关系不要混为一谈。2.1 Reasoning Core推理的“原子操作集合”Reasoning Core 可以理解为一组经过抽象设计的最小推理动作相当于把人类解题时的思维动作拆成积木块。常见的推理原子操作包括数值计算加减乘除、取模、四舍五入集合运算交集、并集、差集、子集判断逻辑判断与或非、命题真假模式匹配找规律、找公共项条件分支if-else 分情况讨论状态更新把一个变量代入下一步多步规划把一个大目标拆成子目标。这个集合的价值在于它定义了任务空间的“最小单元”而不是直接定义任务。有了这组积木我们可以像搭乐高一样组合出无穷多的推理任务并且每一步都是可控、可验证的。2.2 Procedural Data程序生成的训练数据Procedural Data 指的不是“按流程走出来的数据”而是通过代码、模板、规则批量产出的训练数据。举个例子。我们想造一批“三个人分苹果”的应用题。传统人工做法是写 100 道题每道题配步骤。程序化做法是# data/gen_apple_task.py import random def generate_task(): people random.randint(2, 5) # 参与人数 total random.randint(10, 100) # 苹果总数 per total // people # 每人数量整除 remain total % people # 剩余数量 question f{people}个人分{total}个苹果每人分到{per}个还剩{remain}个。 answer f每人{per}个剩余{remain}个。 return {question: question, answer: answer}一个循环下去几千道题几秒钟就出来了。而且我们知道 ground truth 就是per和remain不会出错。这就引出一个关键优势程序化数据天然自带监督信号。因为数据是由确定性代码生成的所以每一道题的标准答案、推理步骤都可以在生成时一并记录。这比从网上爬题、再人工标注可靠得多。2.3 Completion-Supervised补全式监督这是整篇工作里最值得品的一个设计。传统 SFT 是“完整序列监督”输入: 题目 输出: 完整的推理步骤 答案Completion-Supervised 是输入: 题目 部分推理步骤 中间有空缺 输出: 补全被遮住的推理步骤你可以简单理解为不是让模型默写整篇作文而是让它补出作文里被抠掉的几个句子。这样做有三个好处监督信号更精确。模型只需要对缺失的那几步负责loss 的梯度不会摊薄到整段文本上。训练效率更高。同一个推理链可以遮不同的位置生成多条训练样本数据利用率成倍提升。更接近推理的本质。推理本质上就是“在前置条件下推出下一步”。补全任务天然训练模型建立“条件 - 结论”的对应关系而不是训练模型背诵流畅文本。把三个概念串起来整套方法的逻辑就清晰了Reasoning Core 提供“积木”Procedural Data 用积木批量搭建“例题”Completion-Supervised 让模型在例题的关键位置反复练习“补全”从而学会真正的推理动作。3. 方法论拆解从推理核心到训练样本理解了概念再看整体的方法流程。一套完整的 Reasoning Core 训练流水线大致包含四个阶段。3.1 阶段一定义原子推理算子第一步是抽象出你的领域需要的原子推理算子。比如做数学推理算子可能是加减乘除、取模、比较大小做代码逻辑推理算子可能是变量赋值、循环、条件跳转做一般问答推理算子可能是事实检索、矛盾判断、因果链推导。这一步的核心标准是每一个算子必须可以独立验证。如果一个算子不能写出确定性校验函数它就不适合出现在 Reasoning Core 里。3.2 阶段二编制组合模板有了算子还需要模板来组合它们。组合模板决定了任务的复杂度和多样性。简单模板算子A(输入) - 输出三级模板算子A(算子B(输入)) - 输出条件模板如果 算子A(输入) 阈值执行 算子B否则执行 算子C在工程上模板可以写成配置化结构。每套模板内部再打开一些随机参数比如数值范围、变量数量、文本措辞这样同一套模板可以生成大量不重复的题目。3.3 阶段三执行生成并记录完整推理链这一步是程序化数据的关键生成题目时同时记录每一步算子的输入和输出。这些中间记录就是后续补全监督中的“被遮目标”。举个例子{ id: task_000001, question: 有35个球平均分给4个小组问每组几个球还剩几个, template: division_with_remainder, steps: [ {op: divide, input: [35, 4], output: 商8余3}, {op: interpret, input: [商8余3], output: 每组8个还剩3个} ], answer: 每组8个还剩3个 }有了steps字段训练时想遮哪一步就遮哪一步。3.4 阶段四构造补全监督样本最后一步根据训练需求把完整的推理链转换为“题目 部分步骤 空缺”的格式然后只对空缺位置计算 loss。这一步的转换逻辑可以写成通用函数后面我会给出参考代码。整套流程看下来不难发现这套方法最重的投入不在模型而在前期的算子设计和模板编写。一旦这两块搭好后面的数据生成就是批量执行而已。4. 程序化数据质量如何保证很多同学会担心程序批量生成的数据会不会很呆板、模板痕迹重模型学完只会套模板这个担心合理但可以通过设计来缓解。质量保证分三个层面。4.1 数值与逻辑正确性程序化数据的最大底气就是确定性校验。每个算子都配一个校验函数def check_divide(dividend, divisor, result): q, r result assert divisor ! 0 assert q * divisor r dividend assert 0 r divisor return True数据可以错但校验不能缺席。后续清洗时凡是校验不通过的样本直接丢弃。这样就保证了进入训练集的数据至少在“程序逻辑层”是绝对正确的。4.2 文本多样性数据“呆板”的问题根源不在程序化而在模板措辞单一。解决办法给同一道数学题配多套自然语言外壳。比如“平均分”既可以写成“分给”也可以写成“每组分到”还可以写成“要求各组一样多”。这些外壳可以在生成阶段随机选择甚至可以通过一个小的改写模型做二次扩写。但注意外壳改写不能改数字和逻辑关系否则会破坏程序校验的约束。4.3 难度分布控制程序化数据的另一个隐藏优势是难度可控。可以通过控制模板的嵌套深度、算子数量、数值范围来精确调控难度分布。比如简单难度单算子数值小于 20中等难度两个算子组合数值小于 100困难难度三个算子嵌套加条件分支数值小于 1000。训练时可以根据模型的当前水平做课程学习Curriculum Learning先易后难。这一点是纯人工数据很难做到的。5. 补全监督训练的原理与实现接下来是整篇文章最核心的部分补全监督到底怎么实现。5.1 监督机制对比先看传统 SFT 和补全监督在 loss 计算上的区别。传统 SFT 对整段输出做交叉熵question full_reasoning answer整个序列的所有 token 都参与 loss 计算。这带来的问题是模型为了降低 loss只需要把“常见的连接词、语气”学对就能拿到大部分分数真正决定推理结果的步骤反而被淹没。补全监督只对缺失位置的 token 计算 lossquestion partial_reasoning [MASK] answer[MASK]位置被遮住loss 只作用于被遮的 token其他位置都不回传梯度。这样训练信号完全聚焦在推理的关键步骤上。注意这里说的[MASK]不是静态的而是我们预先在数据里标注了哪些 token 是“推理关键点”。我们可以在数据处理阶段为每个样本生成一个 mask 数组标记哪些位置需要计算 loss。这比“整段输出但只对答案部分算 loss”更进一步——它对推理中间步骤也做了精确的位置级监督。5.2 为什么补全比完整生成更有效这里用一个类比解释。完整生成训练相当于让一个学生对着标准答案抄写一整篇解题过程。抄多了字迹越来越像但学生不一定真的理解每一步为什么这么写。补全训练相当于老师把解题过程的中间步骤抠掉几个空让学生自己补。补对了说明他真的理解了“上一步到下一步”的逻辑补错了老师能精准指出是哪一个空错了。对应到训练上完整生成loss 是整段序列的平均错误被稀释补全监督loss 集中在关键步骤错误信号清晰。还有一个容易被忽略的收益数据效率。一条包含 5 个步骤的推理链传统 SFT 只能作为一条样本。补全监督可以分别遮住第 1 步、第 2 步、第 3 步……生成 5 条不同的训练样本并且每条样本的监督目标都不重复。相当于把一条数据的训练价值放大了数倍。5.3 补全监督与 RL 的关系熟悉 RLHF/RLVR 的同学可能会问这和强化学习的奖励建模有什么区别简单说补全监督是密集的、过程级的监督。每一步都有一个明确的目标属于一种更精细的 SFTRL 是稀疏的、结果级的监督。模型自由探索整个推理路径最后只根据最终答案是否正确给奖励。两者并不冲突。Reasoning Core 这种程序化数据 过程级监督更适合作为 RL 之前的“预热阶段”先用补全监督把模型的基本推理模式打牢再上 RL 做探索和泛化。如果你的项目现在 RL 训练一直不稳大概率是因为 SFT 阶段没有建立好过程级的推理基础。6. 数据生成流水线的工程实现理论讲完进入工程实现。这一节我们写一套最小可用的数据生成流水线目标是用几十行代码生成“具备完整推理步骤、且可自动校验”的训练数据。6.1 环境准备以实际项目为准本文用一个通用配置做演示# Python 3.10 python --version # 安装依赖 pip install numpy pandas datasets数据生成阶段不需要 GPU纯 CPU 就能跑非常适合并行扩展。6.2 定义原子算子先定义几个最基础的推理原子操作。这里用“分配问题 剩余问题”作为一个简单场景。# data/ops.py 基础推理算子定义。每个算子都是纯函数输入输出均确定。 def op_divide(total: int, groups: int) - tuple: 整除返回 (商, 余数)。 assert groups 0 return divmod(total, groups) def op_compare(left: int, right: int) - str: 比较大小返回关系描述。 if left right: return 大于 elif left right: return 小于 return 等于 def op_summary(quotient: int, remainder: int) - str: 汇总结果生成最终答案。 if remainder 0: return f每组{quotient}个刚好分完 return f每组{quotient}个还剩{remainder}个每个算子都附带了断言或明确的行为约定。这就是“可验证原子操作”的工程含义。6.3 编写任务模板再编写一个模板把三个算子串起来生成一道完整的应用题。# data/template.py 任务模板组合算子生成完整题目与推理链。 import random from ops import op_divide, op_compare, op_summary TEMPLATE_TEXT [ 有{total}个苹果平均分给{groups}个小组每组能分到几个还剩几个, 把{total}本书平均放到{groups}个书架上每个书架放几本余几本, {total}个球要装进{groups}个盒子每盒数量一样多每盒几个剩下几个, ] def generate_sample(seed: int None): if seed is not None: random.seed(seed) total random.randint(10, 100) groups random.randint(2, 6) # 执行推理链同时记录每一步的输入输出 quotient, remainder op_divide(total, groups) step_compare op_compare(quotient, remainder) final_answer op_summary(quotient, remainder) # 生成步骤记录 steps [ {op: divide, input: [total, groups], output: f{quotient}余{remainder}}, {op: compare, input: [quotient, remainder], output: step_compare}, {op: summary, input: [quotient, remainder], output: final_answer}, ] question random.choice(TEMPLATE_TEXT).format( totaltotal, groupsgroups ) # 拼接完整推理链文本 reasoning ( f第一步计算平均分配{total}除以{groups}商{quotient}余{remainder}。\n f第二步比较商和余数{quotient}{step_compare}{remainder}。\n f第三步汇总{final_answer}。 ) return { question: question, reasoning: reasoning, steps: steps, answer: final_answer, }这里的关键点是steps字段就是补全监督的“挖空候选位”。每个 step 的 input/output 都记录在案后续想遮哪一步就从这里取。6.4 批量生成与校验有了模板批量生成和校验只是循环加过滤。# data/generate_dataset.py 批量生成训练数据并自动校验。 import json import random from template import generate_sample def validate_sample(sample: dict) - bool: 校验样本的推理链是否符合逻辑约束。 steps sample[steps] # 简单校验必须是3步推理且答案在最后一步 if len(steps) ! 3: return False if sample[answer] ! steps[-1][output]: return False return True def build_dataset(n: int, seed: int 42): random.seed(seed) samples [] for i in range(n): sample generate_sample(seedseed i) if validate_sample(sample): samples.append(sample) return samples if __name__ __main__: data build_dataset(1000) # 输出到 JSONL with open(reasoning_data.jsonl, w, encodingutf-8) as f: for item in data: f.write(json.dumps(item, ensure_asciiFalse) \n) print(f生成样本数: {len(data)})运行后得到reasoning_data.jsonl每行一个完整样本。到这一步数据流水线已经跑通了。6.5 从完整推理链构造补全样本现在做最后一步转换把完整推理链转成补全监督格式。# data/make_completion_samples.py 根据完整推理链构造补全监督样本。 import copy import json import random STEP_START_MARKER 第 def mask_step(sample: dict, target_step_index: int) - dict: 遮住指定步骤生成补全样本。 这里用最简单的方式把目标步骤的文字替换为 [MASK]。 实际训练中还需要在 tokenizer 层面对应生成 mask 数组。 masked copy.deepcopy(sample) reasoning_lines sample[reasoning].split(\n) # 定位目标步骤对应的行 # 演示用按行号定位实际工程中建议按 marker 精确定位 masked_lines [ line if idx ! target_step_index else f第{idx 1}步[MASK]。 for idx, line in enumerate(reasoning_lines) ] masked[reasoning] \n.join(masked_lines) masked[masked_step_index] target_step_index return masked def expand_with_masks(sample: dict) - list: 一条完整样本扩展成多条补全样本。 step_count len(sample[steps]) extended [] for idx in range(step_count): masked_sample mask_step(sample, idx) extended.append(masked_sample) return extended if __name__ __main__: with open(reasoning_data.jsonl, r, encodingutf-8) as f: lines f.readlines() all_samples [] for line in lines[:100]: # 先用 100 条做演示 sample json.loads(line) all_samples.extend(expand_with_masks(sample)) with open(completion_train.jsonl, w, encodingutf-8) as f: for item in all_samples: f.write(json.dumps(item, ensure_asciiFalse) \n) print(f补全样本数: {len(all_samples)})到这一步一条推理链被扩展成了推理步数条补全样本。假设原来有 1000 条推理链、平均 3 步就能得到 3000 条补全训练样本数据利用率是传统 SFT 的 3 倍。6.6 数据格式总结最终进入训练的数据格式建议统一为{ question: 有35个苹果平均分给4个小组每组能分到几个还剩几个, partial_reasoning: 第一步计算平均分配35除以4商8余3。\n第二步[MASK]。\n第三步汇总每组8个还剩3个。, target_reasoning: 比较商和余数8大于3。, answer: 每组8个还剩3个 }训练时模型输入为question partial_reasoning监督目标为target_reasoning。tokenizer 之后只对target_reasoning对应的 token 计算交叉熵即可。7. 补全监督训练的代码实现数据准备好了接下来就是用 HuggingFace Transformers 跑一个最小训练脚本。这里给出一个可运行的骨架核心是loss 只回传到目标区域。7.1 依赖安装pip install transformers datasets accelerate7.2 构建训练数据集# train/build_dataset.py 把 JSONL 转换为 HuggingFace Dataset。 import json from datasets import Dataset def load_completion_data(path: str) - Dataset: samples [] with open(path, r, encodingutf-8) as f: for line in f: item json.loads(line) samples.append({ prompt: item[question] \n item[partial_reasoning], target: item[target_reasoning], }) return Dataset.from_list(samples)7.3 训练脚本骨架# train/train_completion.py 补全监督训练最小示例。核心label 位置与 target 对齐。 from dataclasses import dataclass import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments, ) from build_dataset import load_completion_data def tokenize_function(tokenizer, examples): 把 prompt target 拼接并构造 label mask。 # 简单做法直接拼接最后在 loss 计算时通过 label 屏蔽 prompt 部分 texts [] for p, t in zip(examples[prompt], examples[target]): texts.append(p t) tokenized tokenizer( texts, truncationTrue, max_length512, paddingFalse, return_tensorsNone, ) labels [] for i, p in enumerate(examples[prompt]): # 记录 prompt 长度用于屏蔽 prompt 位置的 loss prompt_len len(tokenizer(p, truncationTrue, max_length512)[input_ids]) full_len len(tokenized[input_ids][i]) # target 位置标签为真实 idprompt 位置标签为 -100 label_ids [-100] * prompt_len tokenized[input_ids][i][prompt_len:] labels.append(label_ids) tokenized[labels] labels return tokenized def main(): model_name Qwen/Qwen2.5-0.5B # 以实际可用模型为准 tokenizer AutoTokenizer.from_pretrained(model_name) tokenizer.pad_token tokenizer.eos_token dataset load_completion_data(completion_train.jsonl) tokenized_ds dataset.map( lambda batch: tokenize_function(tokenizer, batch), batchedTrue, remove_columnsdataset.column_names, ) model AutoModelForCausalLM.from_pretrained(model_name) training_args TrainingArguments( output_dir./completion_sft_out, per_device_train_batch_size8, num_train_epochs3, learning_rate2e-5, logging_steps50, save_steps500, fp16True, remove_unused_columnsFalse, ) trainer Trainer( modelmodel, argstraining_args, train_datasettokenized_ds, tokenizertokenizer, ) trainer.train() if __name__ __main__: main()这段代码的精髓在tokenize_function里把 prompt 部分的 label 全部设为 -100只有 target 部分参与 loss 计算。这就是补全监督与普通 SFT 的唯一区别——监督位置被精确限定在推理步骤上。7.4 验证 loss 是否正确跑训练之前可以先人工构造一个样本验证 loss 是否真的只基于 target 计算# 伪代码用于理解 label mask 效果 labels torch.tensor([-100, -100, 5, 8, 3]) logits model_output.logits # 计算 loss loss_fct torch.nn.CrossEntropyLoss(ignore_index-100) loss loss_fct(logits.view(-1, vocab_size), labels.view(-1))只要ignore_index-100被屏蔽的 prompt 位置就不会进入 loss。这个机制是 PyTorch 内置的不用自定义损失函数。确认这一点后就可以放心训练了。8. 效果验证与评估维度训练结束后不能只看 loss 下降。补全监督的评估需要从两个层面看。8.1 生成能力评估在推理验证集上检查模型在完整生成模式下能不能一步步推出正确结果。这一步和普通评测一致用准确率、F1、步骤正确率都可以。推荐细化到最终答案正确率只看最终结果对不对步骤正确率拆解模型生成内容逐步判断每一步是否合理。这一步最好用程序化验证器完成因为验证器知道每一步的 ground truth。8.2 补全能力评估专门评估补全能力可以构造一个“挖空测试集”从测试集里随机遮住推理链的某一步让模型补全用程序校验补全结果是否正确。这个指标直接反映了“过程级推理”是否真的学会了。如果最终答案正确率很高但补全正确率很低说明模型大概率是背了答案而不是真正理解推理过程。8.3 对比基线评估补全监督方法时至少对比三组训练方式数据量预期特点完整 SFT同等规模输出流畅但过程错误难定位答案监督同等规模只学答案推理链泛化弱补全监督同等规模过程正确率高推理链更稳健注意这里不引用任何具体实验数字因为没有材料依据。但在自己的项目里这三组对比是成本最低、最能说明问题的实验设计。8.4 泛化能力测试程序化数据的最大质疑是“只会在模板内做题”。所以一定要做跨模板测试用模板 A 生成训练数据用模板 B同算子、不同措辞生成测试数据观察准确率掉多少。如果掉得厉害说明模型学的是文本外壳不是推理本质。这时需要增加文本外壳多样性或者引入一个阶段性的随机化改写。9. 常见问题与排查思路把这套方法真正落地时下面几个问题是高频出现的。问题现象可能原因排查方式解决方案训练 loss 下降但生成结果全错数据生成与模型 tokenize 不对齐监督目标错位检查训练样本里labels是否与输入对齐打印一条样本的 input_ids 和 labels修正 tokenize 逻辑确保 -100 只屏蔽 prompt 部分模型只会复述模板不会做题数据模板多样性不足跨模板测试观察效果是否骤降增加文本外壳变体调整算子的数值范围和组合方式补全训练后模型完整生成能力变差训练时只见过“补全”没有见过“完整生成”在训练集中混入 10%-20% 的完整 SFT 样本混合训练同时保留补全监督和完整生成能力数据生成速度慢校验函数太重或者单进程生成分析耗时集中在哪一步用多进程并行生成算子校验逻辑保持轻量程序化数据出现逻辑冲突模板参数随机范围没有约束好查看具体样本的 steps 是否自洽增加参数约束条件例如分母不能为 0、n groups模型在长推理链上容易崩步骤嵌套过深训练样本长度超过上下文窗口查看训练数据长度分布控制模板层数或先用短链训练再渐进加长这里额外强调一个容易被忽视的坑补全监督的 label 对齐问题。只要labels中 prompt 区域的掩码没设对模型就会悄悄把“题目内容”也当成监督目标来学。这种错误在 loss 上不一定明显因为 prompt 文本本身也是自然语言loss 照样会下降但推理能力基本学不出来。排查方法很简单训练前打印一条样本人工核对sample tokenized_ds[0] print(tokenizer.decode(sample[input_ids])) print(labels:, sample[labels])确认input_ids里 prompt 部分对应的labels全是 -100再开始训练。10. 工程建议与最佳实践最后给几条从工程视角提炼的建议。这些建议不针对特定模型而是针对“想把类似思路落到自有数据流水线上”的团队。10.1 先搭小闭环再扩大规模不要一上来就生成百万级数据。先用几百条数据、一个小模型跑通全流程算子 → 模板 → 生成 → 校验 → 补全 → 训练 → 评估。全链路跑通后再谈规模化。原因很简单数据生成、tokenize、训练、评估四个环节都可能出错小闭环能最快暴露问题。10.2 算子是资产模板是杠杆Reasoning Core 这类方法真正沉淀下来的资产不是某条数据而是那组精心设计的原子算子和模板库。建议把算子、模板、校验函数按模块管理纳入版本控制。后续换领域、换模型、换任务都可以复用这部分资产。一套好的算子和模板比几万条一次性生成的数据值钱得多。10.3 混合训练比单一训练更稳补全监督不是要替代全部 SFT而是作为 SFT 的一种增强。实际项目中更推荐的做法是60% 的程序化补全数据负责建立过程级推理能力20% 的完整推理链 SFT 数据保证模型能流畅输出完整推理过程20% 的通用指令数据防止模型在推理数据上过度拟合保持通用能力。混合比例可以按任务调整但这个思路能避免“只练数学题、忘了怎么说话”的尴尬。10.4 自动校验必须前置程序化数据的优势就是可校验。校验逻辑应该在数据生成阶段就嵌入而不是等训练完成后再做人工抽查。每条生成的数据都经过“算子级断言 完整链自洽检查 关键字段非空检查”三层校验。校验不过的宁可丢弃也不要带病训练。因为一条带病数据在补全监督下它的错误信号会被精确放大到关键步骤上危害比传统 SFT 更大。10.5 关注推理链的“可观测性”做推理训练日志里不要只记 loss。建议在评估阶段记录以下信息补全位置的正确率分算子统计不同难度模板下的正确率跨模板掉点幅度。这些信息能帮你快速定位模型是哪个环节出了问题。比如“除法算子补全正确率低”和“跨模板掉点严重”是两个完全不同的优化方向。11. 总结与下一步回到开头的问题推理训练卡在数据上Reasoning Core 给出的解法是把推理拆成可组合的原子动作用程序化数据批量构造任务再用补全监督把梯度信号精准作用在推理关键步骤上。这套方法的工程价值在于它把“高质量推理数据”从纯人工劳动变成了“算子设计 模板编写 自动校验”的工程流水线同时用补全监督提高了每一条数据的利用效率。下一步想深入实践的同学可以按这个顺序推进选定一个窄领域比如小学数学应用题、表格推理、代码逻辑推导设计 5 到 10 个原子算子编写 3 种以上组合模板跑通生成 校验 补全训练的最小闭环用跨模板测试验证泛化能力。如果这条路线在你的任务上确实有效再往多算子、多模板、更大规模上扩展。推理能力不是靠堆模型参数堆出来的而是靠设计数据结构和监督信号设计出来的。理解这一点比复现任何一篇论文都更重要。
返回列表