当一个大模型只有 35B 总参数、约 3B 激活参数,却能在数学推理、代码生成等任务上对标万亿参数模型,甚至在某些评测集上反超时,很多人第一反应是模型架构又有了新突破。但在上海交大相关研究中,真正的胜负手并不只是单一架构改进,而是一条数据闭环:让 AI 自己出题、自己评估、自己筛选,再把高质量数据喂回模型进行多轮迭代。这种“自我造题、自我迭代”的训练范式,正在重新定义小模型的上限,也让“35B 干赢万亿参数大模型”从口号变成了可复现的方法论。
接下来的内容会先拆解“35B 为什么能和万亿模型同台竞技”,再讲清楚“自我造题”和“自我迭代”的数据闭环,给出一套可以在本地复现的最小工程流程,最后补上推理侧 TTFT 偏高的排查思路和几个最常见的坑。这篇文章适合正在做大模型微调、数据合成、推理服务部署的工程师,也适合准备把大模型压缩到有限算力环境里的技术选型负责人。
1. 先搞清楚:35B模型凭什么和万亿参数模型同台竞技
1.1 参数总量、激活参数与推理成本要分开算
在大模型领域,“35B 干赢万亿”听起来像以弱胜强,但这里有一个容易混淆的地方:35B 总参数的模型不一定是稠密 35B 模型。更常见的是 MoE 架构,比如 35B 总参数、约 3B 激活参数。MoE 的全称是 Mixture of Experts,它把模型内部拆成多个专家子网络,每个 token 只激活其中的一部分专家,而不是让所有参数都参与计算。
所以对比模型能力时,需要同时看两个数字:
- 总参数量:决定模型容量和理论上限,也决定权重文件占用磁盘和显存的大小。
- 激活参数量:决定每个 token 前向计算需要的计算量,直接影响推理吞吐和时延。
万亿参数模型如果是稠密结构,前向计算时所有参数都要参与,训练和推理成本都非常高。而 35B-A3B 这种结构的模型,虽然也要把全部权重放进显存,但每次生成只激活约 3B 参数,单 token 计算量远低于万亿稠密模型。这也是小模型可以在推理成本可控的前提下,去挑战更大模型的原因之一。
1.2 为什么小参数模型能反超大模型:数据质量排在模型规模前面
参数规模决定表达能力的上限,但训练出来的模型能解决什么问题,更取决于训练数据的质量和覆盖度。如果一个大模型在训练时吃到的领域数据非常稀疏,或者训练轮次不够,它的能力可能并没有完全发挥出来。反过来,一个小模型如果吃到了高度聚焦、经过验证的高质量数据,完全可以在数学推理、代码生成这类结构化任务上做到专项领先。
这里的“结构化任务”特别适合用合成数据提升:数学题的步骤可以被规则验证,代码可以用编译器验证,逻辑推理可以被穷举或反例检查。因为验证成本低,模型生成的数据可以自动过滤掉错误样本,只保留正确且高质量的部分,再用于下一轮训练。
1.3 这项研究真正的价值:把模型变强的方式从“堆参数量”转向“堆数据效率”
堆万亿参数的路径,对绝大多数团队都不现实。训练成本、硬件投入、推理延迟、部署难度都会指数级上升。而“自我造题、自我迭代”的思路,核心是用一个小模型加上验证器,在有限算力下持续生产高质量训练数据,再把这些数据喂回模型,形成“模型变强 -> 数据变好 -> 模型再变强”的正向循环。
从工程角度看,这个循环的每一环都可以独立优化:生成模型的采样策略、验证器的严格程度、数据筛选的去重策略、训练的超参数配置。只要闭环本身是稳定的,模型规模反而变成了一个可以灵活选择的因素。
| 对比维度 | 万亿稠密模型 | 35B-A3B 这类 MoE 模型 |
|---|---|---|
| 训练成本 | 极高,需要大规模集群 | 中等,单机多卡可尝试 |
| 推理成本 | 极高,显存和算力压力大 | 较低,激活参数少 |
| 领域数据定制 | 成本高,迭代慢 | 适合自我迭代式快速定制 |
| 适用场景 | 通用底座、复杂长程任务 | 专项任务、私有化部署、边缘场景 |
2. “自我造题”到底是什么:从种子数据到合成数据闭环
2.1 三个常用技术名词的底层逻辑
在开源社区和论文里,这类方法有多个名字:Self-Instruct、Self-Play、Self-Refine。它们的底层逻辑是一致的:让模型基于少量种子数据生成更多数据,再用某种方式验证和筛选,把高质量数据放回训练集。
- Self-Instruct 强调“模型自己生成指令和答案”,适合文本指令数据扩展。
- Self-Play 强调“模型和自己对弈”,在数学、棋类、对抗博弈中更常见。
- Self-Refine 强调“模型自己生成、自己评价、自己修正”,适合错误分析和改写。
在实际工程里,这三者经常混合使用。比如先让模型生成 100 道数学题并写出推导过程,再用另一个模型或规则验证器判断推导是否正确,错误答案打回重写,或者直接丢弃。
2.2 一条可落地的最小数据闭环
先给出一条可实现的闭环流程,后续章节会围绕它展开。
def build_synthetic_dataset(seed_questions, generator, verifier, n_samples=4, temperature=0.7, max_attempts=3): samples = [] for question in seed_questions: for _ in range(n_samples): for attempt in range(max_attempts): prompt = build_prompt(question) response = generator.generate(prompt, temperature=temperature, top_p=0.9, max_tokens=1024) if verifier.check(question, response): samples.append({ "instruction": question, "output": response, "source": "self-instruct", "round": current_round, }) break # 超过 max_attempts 则丢弃 return samples这个流程的四个关键点是:
- 种子问题要尽量覆盖目标领域,避免生成数据塌缩到同一类题型。
- 采样温度不能太高,否则生成内容发散;也不能太低,否则多样性不足。
- 验证器是闭环的核心,规则、编译器、符号计算器、更强模型都可以。
- 每一轮新模型训练完后,可以重新生成下一轮数据,形成迭代。
这里要注意:如果原始材料没有给出明确版本和官方流程,落地前要先确认生成模型、验证器、训练框架之间的版本兼容性。
2.3 数据生成中的关键参数和质量控制
合成数据的质量,主要由采样参数和验证策略决定。
| 参数 | 常见设置 | 影响 |
|---|---|---|
| temperature | 0.3 到 0.9 | 越高多样性越高,但错误率也越高 |
| top_p | 0.8 到 0.95 | 控制采样候选范围 |
| max_tokens | 512 到 2048 | 太短答不完,太长浪费算力 |
| n_samples | 2 到 8 | 每条种子问题生成多少候选答案 |
| max_attempts | 2 到 5 | 生成失败后最多重试几次 |
质量控制除了验证答案正确性,还需要做格式统一和去重。格式统一可以要求模型按“思路-步骤-最终答案”的模板输出,方便后续解析。去重可以用 MinHash 或者基于嵌入向量的相似度计算,防止同质化数据在训练集中反复出现。
3. 用开源工具复现一个“自我迭代”训练实验
3.1 环境准备和依赖选择
这里按常见项目组合来准备,用于演示思路。实际项目要结合自己的包名、路径和版本调整。
- Python 3.10 或 3.11
- PyTorch 2.x,需要与 CUDA 版本匹配
- LLaMA-Factory,用于 SFT 和 LoRA 训练
- vLLM,用于推理服务和 TTFT 测试
- 模型:一个支持 MoE 的底座模型,例如 Qwen 系列的 MoE 版本
安装依赖时,建议先创建虚拟环境,再安装 PyTorch。如果使用国内镜像,可以配置 pip 的 index-url,避免下载超时。
python -m venv venv source venv/bin/activate pip install torch --index-url https://download.pytorch.org/whl/cu121 pip install "vllm" pip install "llamafactory"安装完成后,先用一个简单脚本确认模型可以加载:
from vllm import LLM llm = LLM(model="/models/your-moe-model", tensor_parallel_size=2) print(llm.generate("1+1="))3.2 种子数据准备与题目生成
种子数据不需要很多,几百到几千条都行。关键是覆盖目标任务的题型分布。以数学任务为例,可以准备包含不同难度、不同知识点的题目,存成 JSONL 文件。
{"instruction": "求解方程 3x + 5 = 20,并给出完整推导过程。", "output": ""} {"instruction": "计算 2^10 除以 17 的余数,要求说明每一步计算。", "output": ""}注意这里的 output 为空,是为了让生成模型自己补全。实际生成脚本会用 system prompt 和 instruction 拼出完整 prompt,再调用 vLLM 生成答案。
3.3 训练配置:LoRA/全参、学习率、上下文长度
在 LLaMA-Factory 中,SFT 训练通过 YAML 文件配置。以下是一个常见示例,模型路径和数据集路径需要根据实际环境替换。
model_name_or_path: /models/your-moe-model template: qwen stage: sft finetuning_type: lora dataset: round1.jsonl cutoff_len: 4096 learning_rate: 2.0e-4 num_train_epochs: 3 per_device_train_batch_size: 4 gradient_accumulation_steps: 8 lr_scheduler_type: cosine optim: adamw_torch output_dir: output/round1 lora_rank: 64 lora_alpha: 128这里有几个参数需要重点关注:
- cutoff_len:如果数学推导很长,建议不低于 4096,否则答案会被截断。
- per_device_train_batch_size 和 gradient_accumulation_steps:两者相乘得到全局 batch size,会影响训练稳定性。
- lora_rank:LoRA 的秩,控制微调参数量。任务复杂时适当增大。
训练启动命令一般是这样:
llamafactory-cli train configs/round1.yaml训练结束后,把 LoRA 权重和底座模型合并,或者直接加载 adapter,用于下一轮数据生成。
3.4 多轮迭代训练的执行顺序
第一轮训练完成后,把合并或导出后的模型作为新的生成器,重新执行数据生成、验证、筛选、训练流程。命令顺序可以用脚本统一维护。
# 第一轮 python data_loop.py --round 1 --model /models/your-moe-model --seed data/seed.jsonl --output data/round1.jsonl llamafactory-cli train configs/round1.yaml # 第二轮 python data_loop.py --round 2 --model output/round1/merged --seed data/seed.jsonl --output data/round2.jsonl llamafactory-cli train configs/round2.yaml每一轮的训练数据建议保留历史真实数据,再按一定比例混入新的合成数据,避免模型分布漂移。
3.5 评测:不要只看准确率,还要看推理耗时和鲁棒性
自我迭代最怕一件事:模型在训练集和评测集上分数很高,但一到真实场景就崩。所以评测要多维度看。
可以用 lm-evaluation-harness 跑常见任务:
lm_eval --model vllm \ --model_args pretrained=/models/output/round1,tensor_parallel_size=2 \ --tasks gsm8k,hendrycks_math \ --batch_size auto \ --output_path eval/round1除了准确率,还要看输出格式是否符合预期。很多模型在评测集上得分高,是因为评测题和训练题高度同源;换一个新题,就会暴露推理过程冗余、中间步骤跳步、最终答案错误等问题。建议保留一组从未参与生成的“留出题库”,每一轮都用同一组题做回归测试。
4. 推理侧的事实:35B MoE 为什么 TTFT 可能更高
4.1 TTFT 是什么,为什么用户很敏感
TTFT 是 Time To First Token 的缩写,指从请求发起到模型返回第一个 token 的时间。用户感知的“首字等待”,主要就是它。对于交互式应用,比如 AI 助手、对话机器人,TTFT 过高会让用户觉得系统卡顿。
一个常见的现象是:MoE 模型虽然激活参数量少,后续生成 token 的速度也不慢,但 TTFT 可能反而比同量级的稠密模型更高。这个现象在一些开源模型的问答里经常被提到,需要从推理机制里找原因。
4.2 MoE 架构下 TTFT 偏高的常见原因
TTFT 对应的计算阶段是 prefill,也就是一次性处理完整 prompt 并生成 KV cache 的阶段。MoE 架构在 prefill 阶段会引入几类额外开销:
- 路由计算:每个 token 都要经过 router,决定激活哪些专家,这个计算虽然轻量,但在 token 数量很大时会累积。
- 专家参数读取:虽然只激活少量专家,但不同 token 可能激活不同专家,gating 之后需要从显存读取对应专家参数。如果专家权重没有被完整放入显存,或者跨卡分布不均,就可能出现等待。
- 通信开销:当模型使用 expert parallel 时,token 需要路由到对应的 GPU 上执行专家计算,跨设备通信会显著增加 prefill 时间。
- 批处理排队:并发请求到达时,如果框架没有及时把请求组 batch,或者 batch 内 prompt 长度差异过大,长 prompt 会拖慢整个 batch 的 prefill。
4.3 排查 TTFT 问题的一般步骤
先确认瓶颈在 prefill 本身还是排队导致的,再逐项检查。
| 现象 | 常见原因 | 检查方式 | 解决方向 |
|---|---|---|---|
| 首 token 慢,后续 token 正常 | prefill 阶段 token 太多 | 统计平均 prompt 长度,观察 prefill time | 限制输入长度,使用 chunked prefill |
| 并发升高后 TTFT 明显上升 | 请求排队或 batch 过大 | 查看框架 queue 长度和 GPU util | 控制并发,调大 max_num_seqs,使用动态批处理 |
| MoE 模型 TTFT 高 | 专家参数分布不均或跨卡通信 | 检查 tensor_parallel_size 和 expert parallel 配置 | 增大并行度,确保专家权重完整驻留显存 |
| TTFT 和响应速度同时恶化 | 显存不足或权重换入换出 | nvidia-smi 观察显存占用 | 减小 batch size,或在更小模型上验证 |
在 vLLM 中,测试 TTFT 可以用一段简单脚本,打印每个请求的首 token 延迟,而不要只看平均生成速度。
5. 三个必须避开的坑:数据污染、模型坍缩和评估失真
5.1 模型自己出题,也可能产出重复或错误数据
现象是:生成脚本跑了一整天,得到上万条数据,但去重后发现有效样本只有几百条;或者数据看起来格式正确,答案却错误。
原因通常是采样温度设置太高、验证器太弱、种子问题太少。
检查方式可以是:
- 按 instruction 文本做精确去重,统计重复率。
- 随机抽样 50 条生成结果,人工检查正确率。
- 用验证器分别统计首轮通过率和最终通过率。
解决方案是提高验证器强度、增加种子问题多样性、降低 temperature,并对通过数据进行进一步清洗。
要注意验证器不是摆设。规则验证器最怕模型写“绕弯答案”,例如先给错误答案,再在解释里悄悄改口。因此设计验证器时,最好要求模型在最终输出中给出一个可机读的答案标记,用正则或符号计算器单独抽取并校验。
5.2 多轮迭代后模型坍缩
现象是:第一轮训练后效果提升明显,第二轮提升变小,第三轮分数反而下降,或者生成数据的多样性明显下降。
原因是模型不断用自己生成的数据训练,概率分布逐渐收窄,模型开始输出模板化答案,遇到新题型时能力减弱。这是典型的“模型坍缩”。
对策是每轮保留一部分原始真实数据,不要只依赖合成数据;同时在生成阶段刻意提高 temperature,扩大采样空间;还可以用另一个不同规模的模型做生成器,增加数据多样性。
5.3 测试集泄漏与评估集污染
现象是:模型在本地评测集上得分很高,上线后表现明显偏差。最常见的原因是生成数据时,模型见过评测题或相似题,评测结果虚高。
防止方法包括:
- 建立独立的留出题集,任何生成脚本都不得读取。
- 对合成数据做和评测集的重叠检测,删除重复或高相似样本。
- 每一轮评估都使用同一组 hidden test,不把测试集加入训练提示语。
可以将这些坑整理成一张速查表,方便团队评审时逐项对齐。
| 问题 | 现象 | 检查方式 | 处理建议 |
|---|---|---|---|
| 数据重复 | 去重后有效样本少 | 统计重复率 | 增加种子数据、降低 temperature |
| 模型坍缩 | 多轮迭代后分数下降 | 对比每轮生成多样性 | 保留真实数据、混合生成器 |
| 评估失真 | 评测高但线上差 | 检测测试集重叠 | 独立 hidden set、去重、隔离测试集 |
6. 从“35B干赢万亿”到大模型工程实践的可复用清单
6.1 环境检查清单
在做自我迭代实验前,先逐项确认环境。
- Python 版本和 PyTorch 版本匹配。
- CUDA 驱动和 PyTorch 的 CUDA 版本一致。
- 模型权重能正常加载,至少能生成一句完整回复。
- 验证器能跑通单条样例。
- 训练脚本能在 1 个 epoch 上跑完,确认数据和配置没有格式错误。
- 数据生成脚本的输出路径和训练脚本的 dataset 路径一致。
6.2 数据迭代发布前的检查清单
每一轮训练数据回流前,建议按以下清单走一遍。
- 数据量是否达到预期,格式是否符合训练框架要求。
- 是否完成去重和格式清洗。
- 是否用验证器随机抽检过正确率。
- 是否保留了真实种子数据,避免全量合成数据。
- 是否检查过合成数据与评测集的重复。
- 是否记录了本轮数据生成时用的模型版本和采样参数,方便回滚。
6.3 小模型项目的落地建议与扩展方向
35B 干赢万亿参数大模型,并不代表参数量不重要,而是说明在约束条件下,数据策略和训练策略可以带来更大的边际收益。实际项目选型时,建议把模型规模、推理时延、数据迭代速度和场景复杂度放在一起权衡。
下一步可以扩展的方向包括:
- 用奖励模型替代规则验证器,扩大可验证任务的类型。
- 在生成阶段引入多模型投票,提高答案稳定性。
- 使用树搜索生成中间步骤,把推理路径变成训练数据。
- 对合成数据做课程学习,按难度从低到高组织训练。
- 把 TTFT 与数据生成速度纳入同一套监控,避免训练迭代拖垮推理服务。
如果只做一件事,建议先搭建一条“10 条种子问题 -> 生成 100 条数据 -> 微调 -> 评测”的最小闭环,跑通后再逐步扩大数据量和模型规模。这个闭环跑通一次,比看再多参数对比都有用。