MiniMind 训练 8 阶段全景:从 Tokenizer 到 Agentic RL 的能力流水线
MiniMind 训练 8 阶段全景:从 Tokenizer 到 Agentic RL 的能力流水线
一个 64M 小模型能学会从「词语接龙」一直进阶到「多步用工具解题」,靠的不是某一个神奇算法,而是八个阶段、层层递进的训练流水线。每一个阶段都解决一个具体问题,每跳过一个,能力天花板就立刻下降。
GitHub jingyaogong/minimind 是过去两年小模型训练圈子里最出圈的开源教学项目之一:58,427 Star / 7,594 Fork / Apache-2.0 / Python 3.10+,描述就一句话:" Train a 64M-parameter LLM from scratch in just 2h!"(2 小时单卡从零训出一个 64M 参数模型)。但很多 Star 它的人是被"快速训好一个对话小模型"吸引进来的,真正值钱的部分却是它完整的训练阶段图谱——9 个独立 trainer 脚本,覆盖从 Tokenizer 重训到 Agentic RL 的全部路径,并附带 OpenAI 兼容推理 API、Web Demo、Tool Call 评测脚本、LoRA 合并脚本、模型转换脚本,是"大模型从 0 到 Agent 是怎么一步步炼成的"的最佳开源教学参考。
本文按作者在 README 中给出的能力递进顺序,逐阶段回答四个问题:解决什么核心问题?没有它会怎么样?MiniMind 是怎么实现的(脚本入口/数据格式)?典型坑和排错线索。读者按文章顺序一步步跑,就能在单卡 3090 上完成从 "2 小时得到可对话 Zero 模型" 到 "做出具备 Tool Call + Reasoning + Agent 轨迹能力的对齐模型"的全过程。
本文提纲
- 一张总表 + 一张图先把 8 个阶段定位清楚(含"最小 2 小时路径 vs 完整最佳效果路径")
- 阶段 0:Tokenizer(词表 6400 / BPE + ByteLevel / 特殊模板 token)
- 阶段 1:Pretrain 预训练——学会「词语接龙」(CE on all tokens)
- 阶段 2:Full SFT 监督微调——学会当助手,MiniMind-3 已混入 Tool Call + Reasoning
- Pretrain vs SFT 核心差异对照表 + 常见误区:为什么"先学语言再学听话"不能反过来
- 可选阶段 3a:LoRA——低成本领域适配(知道自己叫 MiniMind、学会垂直知识)
- 可选阶段 3b:Knowledge Distillation 蒸馏——黑盒(好答案做 SFT) vs 白盒(CE + KL 学分布)
- 可选阶段 3c:DPO——偏好对齐(RLHF 的"无 Reward Model 版")
- 可选阶段 3d:RLAIF——PPO / GRPO / CISPO 三条强化学习路线对比
- 可选阶段 3e:Agentic RL——优化整条多轮工具调用轨迹(不是单轮回答)
- 脚本与数据格式快速索引 + 仓库代码地图
1. 一表一图先定位:8 阶段 + 两条路径
阶段总表:每阶段「解决什么问题 / 没有会怎样」一句话
| 阶段 | 解决的核心问题 | 没有它会怎样 |
|---|---|---|
| Tokenizer | 文本如何数字化(切词→id) | 无法训练,模型看不懂也输出不了人类文字 |
| Pretrain | 会不会说人话、有没有基础知识 | 只会乱码或胡言乱语,连正确的中文句子都拼不出来 |
| Full SFT | 会不会当助手、听指令、按对话格式走 | 会续写但不会对话;你问它"你好",它可能接着写"……今天的天气不错"而不是回你 |
| LoRA | 如何低成本适配某特定领域 / 个性 | 只能全参微调,显存/时间成本高 10~100 倍,容易过拟合毁通用性 |
| Distillation | 如何从大模型学能力(teacher→student) | 64M 这种小模型的能力上限会非常低,永远达不到基座知识密度 |
| DPO | 如何让回答更符合人类偏好(风格/安全/礼貌) | 可能答得对但粗鲁、不安全、说话方式和产品要求不符 |
| RLAIF | 如何在线探索并持续优化(PPO / GRPO / CISPO) | 能力停留在 SFT 天花板,不会在高难任务上"越玩越强" |
| Agentic RL | 如何学会稳定的多步工具调用与解题 | 不会稳定 tool_call:会用格式但经常忘记查、查错、或者中间卡壳 |
两条路径 + 总体流程架构图
MERMAID_BLOCK_0
- 最小可用路径(约 2 小时 / 单卡 3090):Tokenizer → Pretrain → Full SFT → 得到一个已经能对话的 Zero 模型
- 完整效果路径:在 SFT 之后,按需组合 LoRA / 蒸馏 / DPO / RLAIF / Agentic RL 做能力增强与对齐
增强路径之间不是严格串行的:LoRA 和蒸馏都可以挂在 SFT 基座上并行做;DPO 既可以直接接 SFT,也可以接蒸馏后的 student;RLAIF 一般在 DPO 之后(有了对齐基线再做在线探索);Agentic RL 通常放在最后(要求模型已经具备稳定的 tool_call 格式能力,再优化轨迹级奖励)。
2. 阶段 0:Tokenizer——文本与数字的桥梁
一句话定义:Tokenizer 是 LLM 的"词典 + 切分规则",把自然语言字符串切成离散的 token id 序列喂进模型,推理时再把 token id 解码回字符串。
为什么不能绕开
LLM 是数学函数,它吃的是向量、吐的是向量,不吃"汉字"。没有 Tokenizer,你手里的文本和模型参数之间就没有办法建立任何连接。
MiniMind 的设计
- 词表大小:6400 个 token——刻意精简,远小于 Qwen/Llama 的 15 万级词表。小词表带来两个训练侧的直接好处:embedding / lm_head 两层参数占比大幅下降(这两层参数量 = hidden_dim × vocab_size,vocab 小 20 倍,这两层就省 20 倍);64M 这样的 Tiny 模型里,省下来的参数可以放到 Decoder Layer 去,让推理层更深。
- 分词算法:BPE (Byte Pair Encoding) + ByteLevel。BPE 保证词频高的片段不被切碎、ByteLevel 兜底任意字节(包括生僻字、emoji、乱码字符),两者组合是 LLaMA/GPT 家族的标准范式。
- 特殊模板 token:预留
<tool_call>、思考标签、对话角色分隔等特殊 token 序列。MiniMind-3 已经把 Tool Call 和 Reasoning 样本在 SFT 阶段就混进了主训练,所以<tool_call>这种模板标记必须在 Tokenizer 层就有稳定 id,不能后面临时加。
为什么不建议重训 Tokenizer
这是作者在 README 里非常强硬的一条建议。原因很直接:
- 旧权重全废:词表一变,embedding/lm_head 的维度对应关系全变,Pretrain 好的权重直接报废。
- 旧数据全废:所有 Pretrain/SFT 数据的 token 化结果全变,等价于数据集重做一遍。
- 旧评测全废:同一 prompt 在新旧 Tokenizer 下 token 序列不同,perplexity、准确率等评测结果不再可比。
MiniMind 主线固定使用 minimind_tokenizer,trainer/train_tokenizer.py 脚本保留给你想了解"Tokenizer 是怎么训出来的"做教学演示,不建议在已经跑了 Pretrain 后换 Tokenizer。
常见坑和排错
- 特殊模板 token 没加进词表 →
<tool_call>被切成多段 → SFT 里学不到正确格式:先看train_tokenizer.py里 special_tokens 列表是否包含你要用的标记。 - 英文空格/中文标点切分和直觉不一致 → 用
tokenizer.decode(tokenizer.encode(s))跑往返一致性测试,看 round trip 是否有损。 - 句子长度超过
max_seq_len时的截断点不友好(从中间把一个词切断):预处理阶段先按语义 chunk,不要直接等长截断。
3. 阶段 1:Pretrain(预训练)——学会「词语接龙」
一句话定义:在海量无标注连续文本上做无监督因果语言建模(Causal LM)——给定前文,预测下一个 token。
在学什么
三个层次依次被模型吸收:
1. 语法与语言规律:主谓宾、中文量词、英文时态、标点使用。
2. 常识与世界知识:"秦始皇是中国历史上第一位皇帝"这种事实,是通过无数出现过的上下文统计规律被编码进参数里。
3. 上下文统计关系:相邻段落之间的指代、因果、举例关系。
本质是高质量的续写能力。
训练方式
- 损失函数:Cross Entropy(对全部 token 做下一个 token 分类)。
- 数据格式:纯文本 jsonl,一行一段连续文本。
{"text": "如何才能摆脱拖延症?治愈拖延症并不容易,但以下建议可能有所帮助。"}
- 训练脚本:
trainer/train_pretrain.py(9.6 KB) - 产物:
out/pretrain_768.pth - 对应代码文件:
model/model_minimind.py(18.7 KB)+dataset/lm_dataset.py(11.2 KB)
结束后模型能做什么 / 不能做什么
能做:续写自然语言、会作诗、会写一小段看起来像人话的段落、常识性填空("秦始皇是___"大概率接"中国历史上的第一位皇帝")。
不能做:区分 user/assistant 角色、按指令对话。你给它一句"你好",它可能续写为"你好,请问你叫什么名字?我叫小明,今天的天气不错……",而不是回你"你好!很高兴认识你。"——因为它学的是续写不是对话。
类比
读了万卷书的人,满腹经纶,但从没上过班、没跟人打过交道——会写文章,但不会做客服。
常见坑和排错
- Perplexity 下不去而且 tokenizer 也没报错:先查数据里是不是有大量的非文本二进制垃圾(爬取数据时常见),看
lm_dataset.py里 token 统计分布里<unk>是不是太多。 - Loss 剧烈震荡:检查 batch 中不同样本的 seq_len 是否差异过大(10 vs 2048 混 batch 会毁稳定性),可用分桶 batch。
- 跑了几轮感觉生成"胡言乱语":先不要怀疑架构,拿 10 条训练集里的文本喂进去 greedy 生成 20 token,看能不能接对——如果连训练集都接不对,说明训练根本没收敛,检查学习率和精度。
4. 阶段 2:Full SFT(监督微调)——学会「当助手」
一句话定义:在高质量的指令/对话数据上继续训练(参数全量更新),让模型适应交互格式、角色结构、任务行为模式。
在学什么(四个东西一次学完)
- 对话格式:
user / assistant / system / tool等角色结构,让它明白"轮到谁说话了"。 - 指令跟随:听懂问题 → 按格式回答,不胡续写。
- 任务模式:问答、翻译、推荐、摘要、工具调用模板等。
- 风格与知识补充:当 SFT 数据量很大时,也相当于一种 mid-training——除了格式化,还能塞新知识。
MiniMind-3 SFT 的特别之处(重点)
当前主线 sft_t2t 的训练数据中已经混入了三种能力:
- ~10 万条 Tool Call 样本(从 Qwen3 蒸馏而来)——做完 Full SFT 就已经会按 <tool_call>...</tool_call> 模板输出结构化工具调用。
- Reasoning 思考链样本——通过 open_thinking 开关在推理时控制是否显式输出思考标签内容(DeepSeek-R1 的思路:训练时显式看 CoT,推理时可以选要不要展开)。
- 统一 chat_template——不再训一个纯对话模型又训一个 reason 模型又训一个 tool-call 模型,一条 chat template 管所有能力,省三条独立模型链路。
这意味着 MiniMind-3 的 SFT 做完就具备"对话 + 基础 Tool Call + Reasoning"三种能力——不再是传统教程里"SFT 只教礼貌对话"那种效果。
训练方式
- 损失函数:还是 Cross Entropy,但只计算 assistant 回复部分的 token loss,user instruction 和 system prompt 部分被 mask 掉。非常关键的实现细节:如果不 mask instruction 部分,模型会花很多容量去"复述指令"而不是学答案。
- 数据格式:标准多轮对话 jsonl。
{
"conversations": [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!"}
]
}
- 训练脚本:
trainer/train_full_sft.py(9.6 KB) - 产物:
out/full_sft_768.pth - 格式控制:SFT 前先把全部
conversations走一遍chat_template拼字符串,再定位assistant在拼接文本中的 span,只有 span 内 token 的 label 不是-100。
类比
书读完了,现在开始上岗培训:学会礼貌回答、按工作流程办事、把用户的问题对应到自己的职责范围。
常见坑和排错
- 训练好但一聊天就"续写 user 说的话":99% 是 mask 逻辑写错了,把 instruction 也算进 loss 了。打印一条样本的 label 序列,检查 user token 位置是不是
-100(PyTorch CE 忽略索引)。 - Tool Call 格式不稳定:检查 SFT 数据里 Tool Call 样本的
<tool_call>标签前后有没有被 Tokenizer 切碎。如果<、tool_call、>被切为三段,模型学到的格式就会飘。 - Reasoning 标签和答案的边界没划清:CoT 样本里
</think>和最终答案之间必须有稳定的分隔符,否则模型会"把推理写进答案里"。
5. Pretrain vs SFT 核心差异对照表
这是所有大模型训练教程里最重要的一张对照。很多团队把"多塞 SFT 数据"当万能药,其实从原理上就搞错了。
| 维度 | Pretrain | Full SFT |
|---|---|---|
| 训练目标 | 学语言与知识(会说人话、有常识) | 学交互格式与任务(会听话、会按格式做) |
| 数据形态 | 连续文本(书籍/网页/代码/论文/百科) | 多轮对话 / 指令对 / 工具调用模板 |
| 监督信号 | 全部 token 都要预测下一个 token | 主要预测 assistant 回复 token;instruction 部分 mask |
| 是否必须 | 是,绝对不能跳过 | 是,不做就不能对话 |
| 典型 Loss | CE on ALL tokens | CE on RESPONSE tokens only |
| 数据质量侧重点 | 语言干净、去重、无乱码 | 角色对齐、输出格式合规、正确答案比例高 |
| 数据量对比 | 通常 GB~TB 级海量文本 | 通常 MB~GB 级(万~百万条对话) |
| 失败表现 | 输出胡言乱语/乱码/非中文 | 答非所问/续写指令/分不清用户和自己 |
| 替换代价 | 极高——重做 = 全流程重来 | 较高,但还能复用 Pretrain 权重 |
| 正确关系 | 地基 | 盖房子 |
黄金法则:Pretrain 打地基,SFT 盖房子。没有 Pretrain,SFT 很难训出像样的模型(地基是空的);只有 Pretrain 没有 SFT,模型不会"听话"——它会续写文章,但永远不懂你问完问题它要回你。
6. 可选阶段 3a:LoRA——低成本领域适配
一句话定义:Low-Rank Adaptation(低秩适配)。在原权重旁边加两个薄的低秩矩阵 A×B,不冻结主体权重,只训练新增的少量参数。
作用
- 用很少算力做垂直场景适配:医疗问答、法律检索、让模型"知道自己叫 MiniMind 并能自我介绍"等。
- 不破坏基座模型的主体权重:做完 LoRA 随时可以抛弃适配器回到主基座,也可以随时把 LoRA 合并进基座(
scripts/convert_model.py)。
适用场景清单(什么时候选 LoRA,不要选 Full SFT)
- 你想让模型在自我介绍里说"我叫 MiniMind,一个小模型"——涉及 persona/自我认知,改动很小,LoRA 足够。
- 你想给模型补一个垂直专业领域的知识小语料(几百到几万条)。
- 显存/时间有限,跑不动 full fine-tune。
- 你要同时维护多个行业版本的同基座模型——每个版本存一套 LoRA 权重(几十 MB)比存全量 checkpoint(几 GB)便宜多了。
训练方式
- 基座:
full_sft_768.pth冻结,不更新。 - 只更新 LoRA 分支:新增的 A/B 低秩矩阵。
- 脚本:
trainer/train_lora.py(10.2 KB),配套model/model_lora.py(2.7 KB)。 - 合并:
python scripts/convert_model.py(8.1 KB)把 LoRA 权重合并回完整模型,合并后的文件和正常 SFT 全量文件大小相同,推理零额外开销。
LoRA vs Full SFT 取舍速记
| 维度 | LoRA | Full SFT(再训一轮) |
|---|---|---|
| 更新参数量 | <1% 总量 | 100% 总量 |
| 显存需求 | 低(同 batch 下约省 30~50%) | 高 |
| 适合数据量 | 小~中(几百~几十万条) | 大(百万条以上) |
| 是否损坏通用性 | 几乎不 | 很容易——垂域数据一塞就把通用对话能力冲没 |
| 是否可"撤销" | 是,丢 adapter 即还原 | 否,只能回滚 checkpoint |
| 产品多版本成本 | 极低(每版几十 MB LoRA 文件) | 极高(每版全量几 GB+) |
常见坑和排错
- rank 设太高(>64):LoRA 的低秩特性被破坏,相当于在学全参,反而不如直接 SFT。推荐先从 4/8/16 试。
- alpha 比例不匹配:常见设置
alpha = 2 * rank;设太小等于没加 LoRA,设太大直接把基座冲毁——合并后推理时 hallucination 明显增加。 - 把 LoRA 用在 Pretrain 阶段:LoRA 适合适配/对齐风格和格式;学语言和海量知识是 Pretrain 的主场,别用 LoRA 塞百科。
7. 可选阶段 3b:Knowledge Distillation(蒸馏)
一句话定义:让小模型(student)向大模型(teacher)学习,把大模型的能力迁移到小模型参数里。
两条路线
路线一:黑盒蒸馏(MiniMind 主线 SFT 里已大量用)
- 学什么:只学教师的最终答案。
- 数据来源:用 Qwen3 等强模型生成高质量问答;Tool Call 那 ~10 万条样本也是 Qwen3 蒸馏出来的。
- 本质:把"好答案"当作 SFT 数据跑一次 Full SFT。
路线二:白盒蒸馏(trainer/train_distillation.py,13.7 KB)
- 学什么:不只学答案,还学教师每个 token 的概率分布(logits)。
- 损失函数:
CE(student, gold) + KL(teacher_logits || student_logits),CE 保证答案是对的,KL 保证"对的那些备选 token 也跟老师一样"。 - 价值:能传递更细粒度的"软偏好"——比如老师对两个候选词的概率是 60% vs 30%,纯 CE 只会让学生记住那个 60% 的,对 30% 那个不敏感;加 KL 后学生能学到"那个 30% 也是靠谱备选"这一隐式信息,在 OOD 场景泛化更好。
什么时候选哪条
- 没有 teacher logits(拿不到教师模型推理环境,只有 API 能拉文本答案):黑盒蒸馏即可。
- 能本地跑 teacher 模型(比如 teacher 也是开源的,例如自己训的 1B 版本要 distill 给 64M student):白盒蒸馏的收益稳定大于黑盒,值得跑
train_distillation.py。
8. 可选阶段 3c:DPO——偏好对齐(RLHF 的无 Reward Model 路线)
一句话定义:Direct Preference Optimization。直接用"同一问题的好回答 vs 差回答"的偏好对来训模型,不需要单独训一个 Reward Model。
在学什么
让模型对同一问题,P(chosen) 更高、P(rejected) 更低——在不需要外部 reward 信号的前提下做偏好对齐。更偏价值观/风格/安全对齐,对"做对题"的直接提升有限。
数据格式
{
"chosen": [
{"role": "user", "content": "Q"},
{"role": "assistant", "content": "好回答"}
],
"rejected": [
{"role": "user", "content": "Q"},
{"role": "assistant", "content": "差回答"}
]
}
技术属性
| 属性 | DPO 细节 |
|---|---|
| 训练范式 | Off-Policy:静态偏好数据可以反复用,不需要在线采样。 |
| 需要的模型 | Actor(当前模型)+ Reference Model(参考模型,固定不更新,用于算 KL 偏离惩罚)。 |
| 优点 | 实现简单、训练稳定、显存低;不需要训练 RM 模型、不需要采样 rollout、没有 GAE/优势估计。 |
| 局限 | 不做在线探索。它不会让模型"看到自己没有见过的解题路径并越玩越好"——它只能把你已经给的偏好对压进参数。对"做对题"提升有限,更偏风格与价值对齐。 |
- 脚本:
trainer/train_dpo.py(12.2 KB) - 产物:
out/dpo_768.pth
DPO 用好了能看到的变化
- 语气更礼貌、更像你的产品要求(产品要求"简洁 3 句"输出就真的短了)。
- 面对有害/诱导问题拒绝率更高且更一致。
<tool_call>标签格式更稳定(如果你把"格式正确的 tool call"放 chosen、"缺标签/漏参数的放 rejected",DPO 能显著修格式问题)。
别拿 DPO 当万能药
如果你想让 64M 小模型的数学准确率从 20% 提到 80%,直接塞一堆"答对的/答错的"偏好对给 DPO,通常不会有你期望的提升。知识和推理能力的提升,靠 Pretrain + 蒸馏 + RLAIF;DPO 只负责"同一个能力水平下,选更符合你偏好的那种输出方式"。
9. 可选阶段 3d:RLAIF——PPO / GRPO / CISPO 三条 RL 路线
一句话定义:用可自动计算的奖励信号在线采样 + 在线优化策略,而不是靠人逐条标数据。AI(奖励函数)给 AI(策略模型)反馈,故称 RLAIF(Reinforcement Learning from AI Feedback)。
奖励信号来源(三类,可组合)
- Reward Model(RM):如
InternLM2-1.8B-Reward这种预训练好的打分模型,输入一段对话返回一个 -3.0~+3.0 的连续分数。 - 规则函数:答案是否等于 ground truth(数学题的
gt字段)、<tool_call>标签是否配对、JSON 是否 schema-valid(代码是否通过 AST parse / 是否能在沙箱中跑通)、工具返回 200 还是 error。 - 环境反馈:代码执行 exit code = 0 / tool 调用返回 200 / 浏览器动作成功定位到元素。
DPO vs RLAIF 核心区别
| 维度 | DPO | RLAIF (PPO / GRPO / CISPO) |
|---|---|---|
| 数据来源 | 静态离线偏好对 | 在线采样一批新回答 |
| 有没有探索 | 没有,只看已有的 chosen/rejected | 有,每次采样策略都可能走出新路径 |
| 奖励怎么给 | 隐式的(偏好对比本身就是奖励) | 显式的打分函数 / RM 分数 |
| 范式 | Off-Policy(静态数据可重用) | On-Policy(每一轮更新前都重新采样当前策略) |
| 更擅长 | 风格、礼貌、安全、格式对齐 | 正确性、难任务上越玩越好、tool-use 探索 |
| 实现难度 | 低 | 高(采样、rollout、优势估计、KL 约束、mask 等) |
9.1 PPO(Proximal Policy Optimization)
经典 RLHF 路线:三网(Actor + Critic + Reference)架构。
- Actor:当前要训练的生成模型。
- Critic:估算每个状态的 value(长期价值),和真实回报差算出 Advantage。
- Reference:固定不更新的 SFT 模型,算 KL 散度约束 Actor 别跑太偏(防止为了拿奖励疯狂说 RM 喜欢但人类讨厌的话)。
- 损失核心:裁剪概率比
clip(π_new/π_old, 1-ε, 1+ε),防止一次更新过激把策略冲崩;+ KL 惩罚项。 -
GAE(Generalized Advantage Estimation):把回报平滑分摊回每一步,降低 Advantage 的方差。
-
脚本:
trainer/train_ppo.py(26.8 KB,是所有 trainer 里最大的,因为要维护 Actor + Critic + GAE + rollout)。 - 优点:经典、理论成熟、业界用了很多年。
- 缺点:三网络训练慢、显存高;64M 小模型上 Critic 估不准 value,reward 信号提升很慢。
9.2 GRPO(Group Relative Policy Optimization)
DeepSeek-R1 路线的基础,现在的主流首选:把 PPO 的 Critic 网络整个去掉,用"同组平均分"做 baseline。
同一问题生成 N 个回答,每个回答的优势:
Advantage_i = (Reward_i - mean(R_group)) / std(R_group)
没有 Critic,不需要训价值网络。
- 优点:单网络更稳定、训练速度和显存占用都比 PPO 好一大截;小模型上尤其吃香,因为 64M 的 Critic 价值估计根本不准,不如不用。
-
风险:退化组——N 个回答全是错的、奖励全 0 → 分子分母都接近 0 → 梯度接近 0 → 什么也学不到,整轮浪费。GRPO 的 N 一般要设到 8~16,就是为了降低"全错"的概率。
-
脚本:
trainer/train_grpo.py(19.6 KB),通常比 PPO 收敛更稳更快。
9.3 CISPO(Clipped Importance Sampling PO)
GRPO 的一个 loss 变体,修复 PPO/GRPO 里 clip 截断梯度的问题:ratio 被 clip 截断之后,CISPO 保留 log π 的梯度路径,不让 clip 操作把重要性采样的梯度全切断。在 GRPO 脚本里设 loss_type="cispo" 就启用。
CISPO 在一些难任务上比 vanilla GRPO 稳定,属于"免费再试一次"的配置。
小模型做 RL 的特殊问题:奖励稀疏和全 0 陷阱
64M 模型在高难度任务(例如 24 点、代码题)上,很可能生成的 8~16 个回答全部答错,奖励全是 0 → GRPO 优势全是 0 → 梯度全 0 → 这一轮等于白跑,几轮下来模型毫无进步。
MiniMind 的应对策略:
1. 连续型 Reward Model,不用 0/1:用 InternLM2-1.8B-Reward 这种返回 -3.0~+3.0 连续分的 RM,就算都答错也能区分"更差的"和"没那么差的"。
2. 难度必须匹配模型能力边界:不要一上来就给 IMO 数学题,先从"小学 2 位数加减"这类 64M 有一定概率做对的难度喂起,让 RL 在有正梯度的区域先 warm up,再逐步提难度(课程学习)。
10. 可选阶段 3e:Agentic RL——优化整条多轮工具调用轨迹
一句话定义:不再优化"单轮回答的好坏",而是优化整条多轮交互轨迹 τ 的好坏:用户问题 → 思考 → <tool_call> → 工具执行结果 → 再思考 → ... → 最终答案。
与普通 GRPO 的区别(关键)
| 维度 | 普通 GRPO(R1 式) | Agentic RL |
|---|---|---|
| 优化对象 | 单轮回答 y | 多轮轨迹 τ(多个 message) |
| 奖励结算时机 | 回答一生成完就打分 | 整轮轨迹结束(最终答案给出或超时)才统一结算 |
| 交互 | 无,纯文本生成 | 有真实或模拟的工具执行(工具返回 200/404 影响后续生成) |
| 数据文件 | rlaif.jsonl |
agent_rl.jsonl |
| 需要的额外模块 | 奖励函数即可 | 需要 rollout_engine.py(工具模拟器 + 轨迹控制) |
奖励构成(拆开 5 项分算,可加权)
R(τ) = w1·R_answer(是否命中 ground truth)
+ w2·R_tool(工具调用是否合法/是否有返回)
+ w3·R_format(格式有没有对,tool_call 标签合不合规)
+ w4·R_rm(Reward Model 分数)
- w5·R_unfinished(没在预算内拿到最终答案的惩罚)
一个常见的错误是把所有奖励压到最后("答对就给 1,答错就给 0"),导致模型学不到"怎么拿到正确答案的路径"。把 tool / format 等过程性奖励拆出来,可以让模型在全答错的时候也知道"至少我工具调用的格式是对的"往哪儿走。
脚本与架构
- 训练入口:
trainer/train_agent.py(32.1 KB——是整个仓库里最大的 trainer)。 - Rollout 引擎:
trainer/rollout_engine.py(10.3 KB),负责在 RL 采样阶段把"生成 tool_call → 模拟或真实调工具 → 把工具结果塞回消息 → 继续生成"这条轨迹跑通。Rollout 和 Learner 通过消息解耦,你可以把 rollout 换成真实的工具后端(搜索、浏览器、数据库)。 - 评测脚本:
scripts/eval_toolcall.py(15.3 KB)——端到端测 Tool Call 准确率、格式合规率、解题成功率。
什么时候你需要 Agentic RL
- 你的场景要稳定地调多步工具(不是查一次就完了,是查搜索→读网页→填表→再查搜索→汇总)。
- 你已经有了可靠的 ground truth 测试集(每道问题知道正确答案、也知道哪些中间步骤是必须的),奖励函数定义得出来。
- SFT 阶段已经把 Tool Call 的格式打稳了(不然 Agentic RL 的前几万轮都在修格式,学不到解题)。
11. 脚本与数据格式快速索引 + 仓库代码地图
最后把 MiniMind 整个仓库按"训练者视角"重新整理成一张可查找的索引,读者随时可以定位代码。
Trainer 脚本(9 个,按训练阶段一一对应)
| 文件名 | 大小 | 作用 | 对应阶段 | 产物 |
|---|---|---|---|---|
trainer/train_tokenizer.py |
14.2 KB | 在新数据上训练 BPE Tokenizer | 阶段 0 | minimind_tokenizer.json |
trainer/train_pretrain.py |
9.6 KB | Causal LM 预训练 | 阶段 1 | out/pretrain_*.pth |
trainer/train_full_sft.py |
9.6 KB | 全参数监督微调(对话 + Tool Call + Reasoning) | 阶段 2 | out/full_sft_*.pth |
trainer/train_lora.py |
10.2 KB | LoRA 低秩适配 | 3a | LoRA adapter + 可合并 |
trainer/train_distillation.py |
13.7 KB | KD(黑盒 SFT 或白盒 CE+KL) | 3b | out/distil_*.pth |
trainer/train_dpo.py |
12.2 KB | Direct Preference Optimization | 3c | out/dpo_*.pth |
trainer/train_ppo.py |
26.8 KB | PPO Actor+Critic 三网 RL | 3d | out/ppo_*.pth |
trainer/train_grpo.py |
19.6 KB | GRPO + CISPO 单网络 RL | 3d | out/grpo_*.pth |
trainer/train_agent.py + rollout_engine.py |
32.1 + 10.3 KB | Agentic RL 多轮轨迹优化 | 3e | out/agent_*.pth |
其他配套脚本
| 文件名 | 大小 | 作用 |
|---|---|---|
scripts/web_demo.py |
22.1 KB | Gradio Web Demo,打开浏览器聊天 + 看 token |
scripts/serve_openai_api.py |
10.8 KB | OpenAI 兼容 HTTP API,可接 Open WebUI / LobeChat |
scripts/chat_api.py |
1.7 KB | 最小 Python Chat API 示例 |
scripts/convert_model.py |
8.1 KB | LoRA merge / 模型格式转换 / 权重裁剪 |
scripts/eval_toolcall.py |
15.3 KB | Tool Call 端到端评测脚本 |
eval_llm.py |
5.5 KB | LLM 通用 benchmark 评测主入口 |
数据格式示例(训练者必须对齐的 6 种 JSONL)
| 数据文件 | 1 行长什么样 | 对应阶段 |
|---|---|---|
| Pretrain jsonl | {"text":"...连续文本..."} |
Pretrain |
| SFT jsonl | {"conversations":[{"role":"user","content":"Q"},{"role":"assistant","content":"A"}]}(支持多轮 + tool/system) |
Full SFT / LoRA / Distill(黑盒) |
| KD 白盒 | SFT 数据 + 另一个文件存 teacher logits(或同时 forward teacher) | Distillation(白盒) |
| DPO jsonl | {"chosen":[...],"rejected":[...]} 每条各是一段对话(同 Q 两答) |
DPO |
| RLAIF jsonl | 问题集合(每问采样 N 答,奖励函数打分) | PPO / GRPO / CISPO |
| Agent jsonl | 问题集合 + 工具后端定义 + ground truth | Agentic RL |
理解了这 6 种数据格式 + 9 个 trainer 脚本之间的对应关系,你就把 MiniMind 的训练全链路掌握了。剩下的事情只是:准备数据、选合适的脚本、调超参、跑、checkpoint、评估、按评估结果决定"要不要再加一段 LoRA / 要不要补 DPO / 要不要上 GRPO"——这就是大模型训练的完整流程。
作者: itech001
来源: 公众号:AI人工智能时代(the-ai-era)
网站: https://www.theaiera.top/
关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top
本文首发于 AI人工智能时代,转载请注明出处。

浙公网安备 33010602011771号