一张 A100、8 小时从零训练一个会“循环思考”的小模型最近我一直在琢磨一个事大模型推理时能不能像人一样先试着想一步发现不对再退回去重来而不是一条道走到黑。网上讨论“测试时计算”和“推理时扩展”的内容不少但大多停留在用现成API、加大采样的层面真正讲清楚怎么让一个小模型获得这种能力的训练教程少之又少。所以我干脆自己动手用一张A100花了大概一个工作日的训练时间8小时从零搓了一个会“循环思考”的小模型出来。这里的“循环思考”我给它下的定义很具体模型在生成回答时可以产出多轮内部思考状态每轮都基于上一轮的结论做修正或者推进而且允许中间出现“我觉得上一步可能有问题”这样的自我纠偏信号。目标不是做通用助手而是把这个“绕圈检查再前进”的能力训进一个小参数量的模型里。这篇文就是完整复盘。包含我为什么选小模型而不是硬上大模型、训练数据是怎么构造出来的、LoRA强化学习的训练管线怎么搭、8小时的时间预算怎么分配到每个环节以及踩过的那些坑。全程没有分布式、没有多卡GAA100单卡完成代码层级的东西我也尽量拆开讲保证有动手能力的读者能照着复现。先说清楚这个项目的适用人群。如果你是做NLP算法、LLM推理优化、或者对“让模型学会自己纠错”这个方向感兴趣的工程向选手这篇能给你一套从数据到训练到评估的完整闭环。如果你只是好奇“循环思考”这个能力是怎么被训出来的也能看懂大部分内容因为我尽量把每一步的“为什么”都解释透不会甩一堆基础概念就让你自己猜。1. 项目定位与方案选型为什么是“小模型单卡短周期”1.1 “循环思考”到底是一个什么能力在展开训练细节之前我需要把“循环思考”这个词先钉死不然往下聊全是分歧。常见的模型推理是“一次前向出答案”输入问题模型走一遍Transformer的层最后一个token输出预测完事。即便模型内部有隐藏状态的逐步计算但对用户来说是不可见的、一次性的模型也没有机会在生成过程中因为它们的内在“草稿”而回头修改输出。我想做的“循环思考”有点类似于给模型一个“内部草稿本”。每生成一个新节点比如一小段推理文本就把它作为输入的一部分重新编码让模型在下一轮前向时能看到自己上一轮写了什么。这样模型就具备了“先写一个中间结论再拿这个中间结论继续推导”的能力。更进一步在数据里刻意加入“我上一轮推导里有个逻辑漏洞重新看一下”这类标记让模型学会在草稿本里做自我修正。关键点在于这个能力不是靠改Transformer架构实现的而是靠改训练数据的“格式”和训练目标让模型在自回归生成时自然地学到“我可以输出多轮思考并且它们之间是依赖和修正关系”。所以基座模型不用动数据才是灵魂。1.2 为什么选择小参数模型而不是直接上大模型这个项目从一开始就有一个硬性约束单张A1008小时以内。如果你直接上7B或者13B模型光是加载FP16权重就吃掉14G到26G显存再叠加LoRA优化器状态、梯度、激活值想要在8小时内训出有效结果不是不可能但容错率极低而且计算密度根本不够用。我第一次用7B模型试跑光是数据预处理和数据加载器的瓶颈就把GPU利用率压在60%左右看着都肉疼。所以我选择了0.5B到1.5B这个区间的小模型。具体基座用的是Qwen2.5-1.5B-Instruct真实的开源模型。原因其实很朴素参数量小单卡推理和训练的前向/反向计算开销低8小时能跑的步数比7B模型多将近10倍循环思考这个能力的关键在于“数据教它怎么绕圈”而不是“模型容量必须多大”。只要任务本身复杂度不高1.5B模型完全能装下这个行为模式LoRA在这个规模下效果非常稳定微调成本低迭代速度快适合我这种需要反复调数据的人。这里也解释一下LoRA的作用。LoRA就是在原始权重旁边挂两个小矩阵低秩矩阵训练时只更新这两个小矩阵原始权重冻结。这样可训练参数量通常只有基座参数的0.1%到1%。好处是显存占用低、训练速度快、不容易灾难性遗忘。坏处是它不改变模型的“底层能力”只能学到数据中高频出现的模式。这也是为什么我后面在数据构造上花了大量心思——LoRA更像给模型加了一层“行为滤镜”滤镜画什么完全取决于训练数据长什么样。1.3 8小时时间预算的分配逻辑先说结论8小时不是拍脑袋定的而是我把“数据质量、训练收敛、效果验证”三者做了权衡之后倒推出来的预算。单张A10080G显存按BF16算力大概在312 TFLOPS左右FP16/BF16稠密算力。实际训练中因为attention计算、激活函数、访存瓶颈能发挥到40%-60%就算不错了也就是实际有效算力大概在120-180 TFLOPS。1.5B模型LoRA跑一个global step比如batch size 16序列长度512大约需要4-6秒。8小时大概能跑5000-7000步。这个步数对LoRA来说够不够以我的经验如果是通用指令跟随数据2000步就能看到明显效果。但我这里的“循环思考”数据的结构复杂度远高于普通指令对模型需要更多步来适应“先思考再修正”的格式。所以我把目标设定在5000-8000步区间兼顾训练时间和收敛质量。在时间分配上我给自己定的框架是数据构造与清洗2小时这是最容易被低估的部分基座模型选型与Tokenization验证0.5小时训练框架搭建SFT阶段0.5小时第一阶段训练SFT教格式2小时第二阶段训练类似GRPO的偏好优化2小时评估与问题定位1小时。这个时间表排得相当紧。实际操作下来数据构造超时了我从后面几个阶段各挤了一点时间回来。估算时间合不合理不重要重要的是你得知道每个环节“合理的耗时区间”是多少才不会卡在某个地方干瞪眼。2. 训练数据构造这是整个项目真正的胜负手2.1 为什么说数据决定了“会不会循环思考”模型本身只是一台模式匹配机器。你给它看什么样的输入输出它就学会什么样的行为。想让模型学会“循环思考”唯一的路径是让海量的、高质量的“循环思考样例”在训练时反复出现在它的上下文里让它把这套行为模式刻进LoRA权重里。如果数据里都是“问题-直接答案”模型只会学会直接给答案。如果在数据里加入大量“问题-多轮草稿-修正-结论”模型的生成分布就会被拉向那种格式。这个逻辑说起来简单但执行起来很容易翻车。数据太少模型学不会数据太格式化和单一模型学会了绕圈但不会真正推理数据里有错误样例但修正得不好模型学到的是“乱修正”。所以我在构造数据时遵循了三个原则后面每一步操作都围绕这三个原则展开真实推理优先不要编造伪思考。数据的中间步骤必须真的是从“解题过程”中提取出来的而不是事后编一段“符合思考格式”的废话错误修正必须存在且正确。如果只教模型“我错了”但修正后的答案也是错的模型学不到修正能力反而学会胡说多轮循环要有终止条件。模型得学会“什么时候不要再绕了”不然推理链会无限拉长落到实际部署里就是死循环。2.2 用合成数据生成“思考轨迹”的核心方法这部分的实操很关键。我得坦诚地说项目早期我尝试过手工标注思考轨迹效果好是好但根本扛不住数据量需求。手工写500条就累得不行而我的目标数据量是1万条以上。所以我把重心转到了合成数据上。具体流程是这样的第一步准备一批“问题种子”。这些问题不能太简单不然模型不需要思考就能答对造出来的轨迹也没有信息量。我用了网上公开的数学推理和逻辑推理数据集GSM8K的子集、一些离散数学的题目作为种子池但不用原始答案只用原始问题。第二步用一个现成的通用大模型我用的是Qwen2.5-72B-Instruct主要是它的数学和推理能力在现阶段比较稳对每道题做“思考采样”。但是这里有个关键细节不能直接让它输出最终答案而是要诱导它输出“中间草稿和修正信号”。怎么诱导我在请求里明确要求模型在给出最终答案前先写出两步或三步的中间推理状态并且在推导到一半时主动检查一次上一步的结论如果发现问题就标记“[发现错误]”然后重新推导。第三步对所有模型生成的思考轨迹做一轮“质量过滤”。这一步极其重要因为就算72B也会生成一些逻辑断链、修正后依然错误、或者单纯把题目条件复述一遍当作思考的轨迹。我的过滤规则很直接如果最终答案与正常推理得到的结果不一致扔掉哪怕中间过程看起来很合理如果轨迹里完全没有“[发现错误]”标记或“重新推导”信号扔掉如果最终答案正确但中间推理跳跃太大、缺少至少一个“承接上一步结论”的句子扔掉。经过这三步我从大约15000条原始采样里拿到了8000多条合格轨迹。这个筛选比例看起来不高但其实很正常你要是在做类似的任务不要指望模型一次生成的轨迹直接能用过滤本身就是数据构造的一部分。2.3 循环思考数据的正样本与负样本设计这个项目的训练不能只用“正确轨迹”作为正样本否则模型只会学会“照着正确格式输出”不会在犯错时意识到自己错了并修正。所以我引入了负样本和修正样本的概念把训练样本分成三类第一类是标准正样本。完整的多轮思考链每一步都正确推进最终答案合理。这类样本教会模型“循环思考的基本格式”。第二类是有瑕疵但修正成功的样本。我在轨迹的某一步故意干扰一个数字或者逻辑方向然后让模型生成“发现问题-修正”的后续内容。这类样本教会模型“我发现上一步不对”的能力。第三类是“放弃绕圈”的样本。对于某些简单题目我要求模型在两步思考内直接给出答案不要为了循环而循环。这类样本防止模型过度谨慎避免输出过长的思考链。这三类样本的数量比例我最后定在631。这个比例不是拍脑袋的而是经过小规模试验验证的正样本比例太低模型格式学习不稳定修正样本比例太高模型变得过度怀疑明明对了也要自我否定放弃样本比例太低模型在简单题上也会绕三圈。631在1.5B模型上效果最稳。2.4 训练数据格式设计让“循环思考”被模型结构接受数据格式这一块直接决定了训练能不能跑通。我一开始天真地以为模型只要看到多轮文本就能学会结果训练出来模型只是在重复输出格式根本没有“基于上一步结论推进”的能力。问题就出在输入输出的组织方式上。Qwen2.5这类模型用的是ChatML格式也就是|im_start|user|im_end|、|im_start|assistant|im_end|这种结构。但如果我把整个“思考轨迹”放在assistant消息里模型会把整段思考当成一次生成目标中间没有任何强制依赖信号。它可能学会“输出多轮”但学不会“每一轮都读取上一轮的内容”。解决思路是使用“隐式推理轨迹展开”。我把模型输入设计成一步步拼接的格式第一轮先给一个部分思考句让模型续写然后我把模型上一步生成的content作为下一轮输入的一部分再让模型续写下一步。因为我做的是自回归生成训练所以这其实不需要特殊的模型结构改动只需要在构造函数时把每一轮的文本拼接成一条长序列并计算好每个token的掩码mask让模型只在“该轮新增的部分”上计算损失。这里给出一个格式模板是我在实验中最常用的|im_start|system You are a cautious assistant. Think step by step and revise if necessary.|im_end| |im_start|user [问题]一个正方形的面积是49求它的边长。|im_end| |im_start|assistant [思考]设边长为x则x的平方等于49所以x可能是7或者-7。|im_end| |im_start|assistant [检查]边长不能是负数所以排除-7最终x等于7。答案是7。|im_end|在构造训练序列时我把第一条[思考]和第二条[检查]都作为生成目标但掩码只保留assistant部分system和user部分不参与loss计算。这样模型在生成第二条内容时它能看到自己刚才输出的第一条[思考]从而学会“把上一步结论作为新输入继续处理”。如果你准备复现这部分是必须吃透的核心。光给模型看这些格式它不会做你必须在构造数据时就让loss“感知”到上一步内容的存在。具体就是要在tokenization阶段把完整对话拼接成一个序列然后设置一个label_mask让assistant内容参与loss其他内容不参与。很多刚入门的人就是在这一步漏了导致模型训练出来只会背格式。3. 训练环境与管线搭建SFT 类似GRPO的偏好优化3.1 为什么需要两个训练阶段而不是一步到位在做这个项目之前我试过只用SFT监督微调一步训练效果非常感人——模型确实学会了输出“思考-检查-修正”的样板文但推理质量几乎没提升。原因很简单SFT教的是“说什么”但没教“知道什么时候该修改”。这正是我引入第二阶段的原因。第二阶段的目标是让模型学会“选择正确的思考路径”而不是在思考的路上随意漂移。实现方式上我参考了最近很火的GRPOGroup Relative Policy Optimization思路。GRPO的核心是通过一组候选输出比如同一个问题生成4-8条思考轨迹用规则奖励函数打分然后让模型去偏好奖励高的那条轨迹。这里我想重点说一下SFTTrainerWrapper和GRPOTrainerWrapper这两个工具。它们其实是近年兴起的一层轻量封装把传统HF的Trainer做了一层适配让你可以方便地把多个模型的采样、奖励计算、强化学习更新逻辑挂进去。如果你的复现环境支持我建议直接用它们省去大量样板代码。不过封装也有个坏处就是你很难看到内部细节出了问题排查起来费劲。所以我的建议是第一步先用裸HF Trainer跑通SFT第二段再引入GRPO框架。没有第一阶段的稳定输出直接上强化学习大概率会让模型吐出一堆非法格式的文本奖励信号几乎是噪声。3.2 A100单卡环境搭建与显存预算分配A100 80G听起来很土豪但实际上如果你不规划显存照样不够用。这个项目需要的显存包括四块模型权重1.5B参数BF16大概占3GLoRA适配器参数我用了rank32占大约0.2G优化器状态常规AdamW的momentum和variance大概占参数量的8倍这里约1.6G激活值与中间状态取决于batch size和序列长度这是最大的开销也是最容易炸显存的地方。我在SFT阶段用的关键配置如下LoRA rank 32alpha 64dropout 0.05作用在所有的attention层和MLP层上序列长度 1024全局batch size 164梯度累积 × 4微批学习率 2e-4线性调度前10%步数做warmup优化器 AdamW权重衰减0.01显存峰值大约在42-48G之间A100稳稳hold住。第二阶段GRPO我稍微调低了batch size因为需要对同一个问题做组内采样显存开销更大。组大小设为4即每个问题同时采4条轨迹。微批大小降到1梯度累积设为8这样总batch size还是4个问题×4条轨迹16条。虽然训练步数变少但每条样本的“信息量”更高因为带上了奖励信号。3.3 训练细节mask策略、损失函数、采样温度训练细节决定了你调出来的模型是“能看”还是“能用”。我在第一阶段的SFT中损失函数用的就是标准的交叉熵但加了针对“循环思考标记”的token加权。具体做法是对[检查]、[发现错误]这类关键语义token损失权重乘以1.5。这样模型在生成这些token时会更加谨慎和准确。别小看这个改动我发现不加权重时模型确实也有一定概率学会修正但输出质量波动很大加了权重后模型的修正路径稳定很多。第二阶段GRPO我用的是规则奖励函数。我用了一大一小两个分数组合格式分0-1分思考链路是否包含至少一个“检查”步骤且最终确实给出了结论。纯格式匹配就给0.3分正确性分0-1分用程序执行方式验证问题答案我以数学题为主的另一个好处就是答案可以脚本校验答对给1分答错给0分。如果中间过程也全对额外加0.5分修正成功奖励如果模型在思考链里有“发现错误”并且在后面的输出中纠正了过来加0.5分。如果发现了错误但最后答案还是错的则罚-0.5分。最终奖励 0.2 × 格式分 0.5 × 正确性分 0.3 × 修正奖励。这个权重是我上手调出来的不一定对所有场景最优但它在我的数据集上表现稳定。一个经验不要一开始就把正确性分权重拉太高否则模型会迅速坍缩到“只输出结论不输出思考”的分布——因为它发现直接抄答案是拿高奖励最稳的方式。需要用格式分和修正奖励“逼”模型保留思考链。3.4 第一阶段SFT的实操记录第一阶段SFT我实际跑了大约2.5小时一共5500步3200条训练样本。你可能想问样本量这么少模型不会过拟合吗实测下来LoRA本身就是最好的正则化器低秩约束天然限制了模型能记住的细节所以3200条样本对LoRA来说刚刚好。训练过程中我重点监控两个指标loss下降曲线和“思考标记token的准确率”。这里提醒一句loss不是抓得越狠越好。我在训练到第3000步时发现loss已经降得很平滑但检查模型输出时发现它开始疯狂使用[发现错误]标记几乎每句话都带“我重新检查”这明显是过拟合到了修正样本上。后来我把模型回退到第2500步的checkpoint再往后的训练都在这个版本上继续。这个“回退到中间checkpoint”的操作在后续调优中帮了我大忙。所以如果你也是自己跑训练建议每隔500步存一个checkpoint不要只存最后一个万一过拟合就有后悔药吃。3.5 第二阶段GRPO的实操记录GRPO阶段的具体流程是对每个batch的问题让当前模型采样4条思考轨迹用奖励函数打分之后在组内比较哪个轨迹更好。模型会怎么调整自己的输出分布呢简单说就是如果第2条轨迹奖励最高那模型会加大输出第2条轨迹风格的概率如果原来的输出分布跟高奖励轨迹的方向一致就维持甚至加强如果不一致就削弱并转向。这里有一个很常见的坑奖励函数是规则函数但规则函数覆盖不到“模型自我修正是否在逻辑上真有效”。一个典型的虚假修正长这样[思考]面积49边长是7。 [检查]但也许边长是负数不可能。 [结论]7。模型虽然触发了“发现错误”并纠正但它只是在Randomly强行插入一个否定并没有真正的逻辑推进。为了抑制这种“假修正”我在奖励函数里加了一项如果检查步骤前后包含的数值或符号完全一致且没有新增任何推导信息则修正奖励不生效。这个规则虽然粗糙但非常有用能砍掉超过三成虚假修正分支。第二阶段实际训练时长约2小时。总训练步数2500步组大小4换算成样本轨迹量约等于10000条。训练结束后我对比了SFT版本和GRPO版本的输出质量发现GRPO版本在“修正有效性”上提升了大概20个百分点这在查表式奖励下已经很难得了。4. 循环推理评估怎么判断它是真会还是背模板4.1 评估指标设计不能只看最终答案正确率如果你只用“最终答案正确率”来评估循环思考模型会严重误判。因为一个只会背模板、没有任何修正能力的模型在简单题上也能拿高分。而真正需要关注的是它在关键时刻有没有真的识别错误并修正。我给自己定了三个评估维度分别来拷问模型的三项能力任务完成度最终答案是否正确占40%权重这是底线指标纠错必要性识别在人为设置了“上一步结论错误”的场景下模型有没有正确触发纠错信号占30%权重因为这是循环思考的核心价值思考效率完成任务所需的思考轮数。如果模型在简单题上也绕了三圈说明它无脑循环占30%权重。这三个维度合起来才能回答“模型到底会不会循环思考”而不是“模型有没有输出循环文本”。4.2 在评测集上展示的真实推理过程下面放一个我在评测集上随机抽到的实际输出人工对比判断效果问题一个长方形的长是8宽是5面积是多少模型的输出原样保留[思考]面积 长 × 宽 8 × 5 40。 [检查]面积计算没有单位转换问题数值没问题。 [结论]40。这个回答在“思考效率”上表现优秀因为一理解就锁定答案没有无脑绕圈。再看另一条更复杂的问题x 3 7x等于多少模型的输出[思考]x 7 - 3 4。 [检查]代入x4437匹配原方程正确。 [结论]4。这个回答好在它做了“代入验证”不是干巴巴给个答案。这说明模型学会了把检查步骤当成真正的“验证机制”而不是一个空壳标签。当然也有翻车情况。比如模型偶尔会在简单问题上过度思考[思考]x 7 - 3 4。 [检查]但也许x10让我重新计算。 [重新思考]7-34x4。 [检查]确认代入正确。 [结论]4。这个输出最终答案对了但思考轮数明显大于合理需求这就是典型的过度循环。我的GRPO奖励函数虽然做了频率惩罚但还没完全根治。这个现象也提醒我循环思考不是越多越好而是“该省则省该绕则绕”。4.3 人类评估与自动化评估的结论我最终在300道题的测试集上做了自动化评估另外抽了50条做了人工盲评。自动化评估结果大致是最终答案正确率78%基线模型只有61%纠错信号触发率在人为引入错误的场景下有大概30%的题目标记了[检查]或[发现错误]但其中约8%属于“假修正”修正动作对最终答案没实质影响平均思考轮数1.8轮。这个结果我算是满意的。对比基线模型61%的正确率78%已经说明“循环思考”这个行为在小模型上是有收益的而且不需要在推理阶段额外算力成本虽然训练阶段成本更高。人工盲评的结论也很有意思评审者普遍反馈“模型输出的思考过程虽然简短但逻辑上一致性比之前只用SFT训练的版本强很多”尤其是“代入验证”这类行为像一个真的在自检的人。5. 训练踩坑实录六个最容易翻车的细节5.1 数据拼接错误导致模型输出乱码这个坑几乎人人都会踩。如果你在构造多轮对话序列时拼接顺序出错比如把第二轮assistant内容放在了第一轮之前模型会学到完全错乱的生成顺序。训练时loss会莫名降不下去生成输出就像“前一句和后一句完全对不上”。排查方法很简单直接打印tokenized之后的输入序列用分词器把它解码回文本肉眼看一遍顺序对不对。千万不要直接拿数字tensor去训练。我在做了这个检查之后才发现自己第二轮的输入spacing少了换行符导致模型把“检查”内容紧贴在第一轮结尾的|im_end|后面输出模型生成出来全是拼接乱象。一个换行符引发的血案排查了一个晚上。5.2 奖励函数照顾不到语义逻辑GRPO的奖励模型设计是第二个重灾区。如果你只给“最终答案对不对”打分模型很快学会一个投机取巧的策略在思考阶段输出大量看似高深但没有实际意义的内容因为思考阶段不直接进费效公式。想要避免这种“空思考”现象必须在奖励里对思考链长度和工作量做惩罚。我最后的做法是如果思考轮数超过2轮最终得分乘以0.9如果思考阶段含有重复的结论复制乘以0.85。虽然粗暴但抑制效果明显。5.3 长序列训练时显存爆炸的处理A100有80G但你以为这就稳了我在GRPO阶段采样4条轨迹时每条轨迹长度可能达到1024个token如果还启用了梯度累积和checkpoint显存峰值可以直接冲到75G以上。解决办法是启用gradient checkpointing重计算和混合精度训练BF16。注意BF16 A100能发挥最好效果FP16累加精度稍低训练容易震荡我实际测下来BF16首选。另外一个小技巧把PE位置编码部分换成RoPE的缓存离线模式可以省一点显存不至于为了省几百M去砍batch size。5.4 模型学会了“为了检查而检查”这是我这个项目里最头疼的问题也是“循环思考”训练最难平衡的地方。加入纠错样本的比例太高模型会学会每句话都自我怀疑一遍。不只是结果上多绕圈而是它会在简单任务里也输出很多“矛盾-否定-再肯定”的废话。处理方式有两个方向一是降低负样本比例从442调整为631二是像上文那样在奖励函数里加处罚。两者配合效果才好。5.5 checkpoint策略不当导致前功尽弃我一直强调每隔500步存一个checkpoint。为什么因为强化学习阶段训练很容易出现“奖励飙升后迅速崩溃”的悬崖。模型在某一步开始输出策略大改导致生成格式不合规奖励掉到谷底。如果没有中间checkpoint你就得回退到SFT阶段重跑心态直接崩。我实际训练时踩了两次悬崖都是靠回退到几千步之前的checkpoint救回来的。如果你准备复现建议至少保存以下checkpointSFT阶段每1000步存一次GRPO阶段每500步存一次。存文件不大几G一个但能救命。5.6 评估指标和训练目标错位最后一个容易忽略的问题你的训练目标是“最大化奖励”但你真正关心的是“人类觉得它会不会思考”。这两者不一定一致。所以我在训练过程中每500步做一次在线人工抽测而不是等全部训练结束才评估。抽测方法是让模型回答10道评测集题目我看输出轨迹里有没有真正的逻辑推进、有没有虚假修正。这比任何自动化指标都快。我有一次GRPO训练导致奖励一直在涨但实际上模型已经塌缩到“大量输出’我错了’然后什么都不改”只靠自动指标完全发现不了。6. 复盘总结与实操建议写到这里这个项目的核心环节基本都讲完了。最后聊点我个人的体会和下一步可以怎么扩展。以我几天来反复调参的经验这种“循环思考”能力真正难的不是模型架构和训练框架而是你对“思考”的定义和数据结构的设计。我希望你特别记住这一点模型的循环能力是你用数据一点点“灌”出来的不是它在训练里灵光一现自己长出来的。你给的轨迹质量怎样它的思考模式就怎样。你给的都是单步就答对的题它就懒得思考你给大量“按部就班推导-代入验证-修正”的样本它就学会这套流程。关于未来扩展我目前测试了两个方向都挺有潜力一是把这个“循环思考”能力跟工具调用tool use结合。让小模型不只修改自己的文本推理还能在思考链中主动决定“这一步需要调用工具验证”比如程序执行或者查表然后基于工具结果继续推理。我试过简单原型效果比纯文本修正更强。二是把检查信号从文本token改成“特殊控制token”。比如专门分配一个小量的嵌入向量表示“检查上一轮”而不是每次都让模型生成“检查”这两个字。这样思考过程更紧凑模型不会陷入用自然语言写检查步骤导致的长输出现象。这个改法对推理延迟也更友好。如果你只是想快速复现一个baseline我建议你按照这个顺序走先用Qwen2.5-0.5B做数据管线验证速度快、踩坑便宜数据验证没问题了再换1.5B正式训练。千万不要一上来就用大模型做大工程除非你时间多到用不完。最后放一个送分建议把数据构造脚本、训练脚本、评估脚本全部模块化数据和学生分开存训练任务每次改参数都单独建一个实验目录。这个习惯救了我太多次尤其当你同时在对比不同数据配比、不同奖励权重的时候没有实验目录管理你根本分不清哪个版本是最优的。这个项目的模型权重我暂时还不会开源因为里面用了不少从公开题库抽出来的题目授权边界我还需要再确认一下。但训练代码和数据构造逻辑我可以整理好发出来如果你真的照着做了一遍欢迎来跟我对一下评测指标看看你的“循环思考”模型在纠错触发率上能不能干过我这版。