从手写 215M 到 Agentic RL,一本追着前沿跑的开源教材

发布于 · 3,331 字 · 约 8 分钟#Github 解读#Models原文链接
从手写 215M 到 Agentic RL,一本追着前沿跑的开源教材 封面图
  • 八章结构覆盖原理到强化学习 Agent 训练,前四章原理后四章动手实践
  • 803 行 Python 实现完整 LLaMA2 模型,包含 GQA、SwiGLU 等现代组件
  • 数据管道采用按行偏移索引加载避免内存溢出,教学取舍下不打包样本
  • 第六章切换至 Transformers+DeepSpeed 工业栈,明确区分教学与生产实现
  • 第八章引入 GRPO、Search-R1、ReTool,用强化学习训练 Agent 自我纠错并附沙箱安全机制

2024 年 5 月底,Datawhale 的 self-llm 项目收到太多同一种反馈。不少读者跟着「开源大模型食用指南」学会了部署和调用,然后跑到社区里问,这些东西到底是怎么训出来的,指南没讲。

两个月后,一个叫 happy-llm 的仓库上线,副标题一点不客气,「从零开始构建大模型」。

时间快进到 2026 年 8 月 8 日,这个仓库合入了它的第八章,讲的已经是 GRPO、Search-R1 和 ReTool,教你怎么用强化学习训练一个会查搜索、会写代码、还能看着报错自己改的 Agent。一本开源课本,硬是把课表追到了研究的最前排。

它先是一本课本

happy-llm 目前 33157 个 star,3143 个 fork,贡献者名单上有近 30 个名字。它是一本完整的中文 LLM 教材,八章结构,前四章讲原理,NLP 基础、Transformer、预训练语言模型、大语言模型一路铺过来。后四章全是动手,第五章用 PyTorch 裸写一个 LLaMA2 并完成预训练和微调,第六章切换到 Transformers 加 DeepSpeed 的工业栈,第七章做评测、RAG 和 Agent,第八章就是开头说的 Agentic RL。

在线版免费读,GitHub Pages 挂着,PDF 在 Releases 里自己下,v1.0.2 是 2026 年 1 月发布的。教材还配了整套课件 PPT,放在 HZAI-ZJNU 维护的独立仓库,这个署名正是指导专家朱信忠所在的浙师大杭州人工智能研究院。CCF 还拉上 Datawhale 和 GitLink,拿它做了一期带免费算力的普惠课程。

说真的,PDF 里那个水印挺有意思。团队在 README 里解释,预先加上 Datawhale 标志水印,是为了防营销号加水印后贩卖给初学者。开源教材被二道贩子包装成付费课,这事儿见得太多,他们选择先打预防针。

把它放进同类材料里看一眼。self-llm 是同门的「使用指南」,教你跑起来,happy-llm 教你造出来,两本书刚好接上。Karpathy 的 llama2.c 是这个项目的血亲,后面你会看到大量细节对得上,但那是英文视频加单文件 C 的形态。复旦邱锡鹏团队的《大规模语言模型,从理论到实践》更学术也更重,更新节奏以年计。happy-llm 占的位置很清楚,中文、免费、代码全可跑、还肯往前沿追。

803 行,一个 LLaMA2

全书最硬核的部分在 docs/chapter5/code/k_model.py,803 行 Python,一个完整的 LLaMA2。

配置类 ModelConfig 的 model_type 叫 Tiny-K,默认参数是 dim 768、12 层、16 头。这份骨架带着明显的 llama2.c 血统,参数命名、初始化策略都对得上,残差投影用 std 0.02 除以 sqrt 乘 2 倍层数的缩放初始化,词嵌入和输出层直接共享权重,hidden_dim 按 4 倍 dim 乘 2/3 再向上取整到 64 的倍数,和 LLaMA 原始实现一字不差。

该有的现代组件一个不少。RMSNorm 里专门写了 x.float() 再 type_as 的精度处理,RoPE 的 precompute_freqs_cis 用 theta 10000 预计算余弦正弦两张表,注意力层是 GQA,16 个查询头配 8 个 KV 头,repeat_kv 负责把 KV 撑回 16 份,前馈层是 SwiGLU 的三矩阵 w1 w2 w3。Flash Attention 没有手写,直接调 PyTorch 2.0 的 scaled_dot_product_attention,检测不到就退回手写的慢速版本并打一行警告。

实际训练时配置覆盖了默认值,dim 1024,18 层,词表 6144,序列长度 512。我按这组参数手算了一遍,每层注意力 3.15M,MLP 8.45M,18 层叠下来加上共享的嵌入层,正好 215M 出头。仓库发布到 ModelScope 的两个权重,happy-llm-215M-base 和 happy-llm-215M-sft,名字里的数字就是这么来的。权重共享这一项省了约 6M 参数,对单卡训练来说不是可有可无的优化。

训练脚本 ddp_pretrain.py 的循环写得很教科书。学习率是手写的余弦退火 get_lr,从 2e-4 衰减到十分之一,梯度累积 8 步乘 batch 64,有效 batch 撑到 512,bf16 混合精度,梯度裁剪 1.0,随机种子 42。每 1000 步存一次 checkpoint,每 20000 步再存一份带步数后缀的。训练日志接的是 SwanLab,国产实验追踪工具,它的作者 Zeyi-Lin 也在这个仓库的贡献者名单里。

数据管道里的小心思

数据侧有两个值得停下来说的细节。

一个是 dataset.py 的 PretrainDataset。一份几 GB 的 jsonl 直接 readlines 会把内存打爆,issue 区就有人报 tokenizer 阶段 OOM。这个类的做法是初始化时预扫描全文,把每一行的起始字节偏移量存进 _offsets 列表,取样本时 f.seek 到指定行再 readline,单条按需加载。这是数据库索引的思路,出现在教学代码里算超纲,但它确实解决了数据比内存大这个真实问题。

另一个是 deal_dataset.py 的切分。split_text 按 512 个字符一块切原始文本。字符不是 token,中文 512 个字 tokenize 之后大概率逼近 token 上限,边界处会硬切断语义。而且每个样本独立 pad 到最大长度,不做样本打包,padding 部分的 loss_mask 置 0 不参与损失,但算力是实打实烧掉的。这是典型的教学取舍,代码一目了然,代价是训练效率。你若拿这套代码去训正经东西,第一件事就该重写这里。

预训练语料用的出门问问开源的 seq-monkey,微调用 BelleGroup 的 3.5M 条中文对话,deal_dataset.py 负责把 from/value 格式转成 system user assistant 的消息结构。全中文数据配 6144 的小词表,再控制序列长度 512。整条流水线串起来,是这个样子。

Happy-LLM 第五章 215M 预训练流水线
Happy-LLM 第五章 215M 预训练流水线

看图就明白,预处理只做最粗粒度的切块,剩下的脏活全丢给训练循环和 loss_mask 去兜。

一条流水线,从设计之初就是给单卡用的。

第六章的急转弯

第五章让你逐行理解每个矩阵乘法,第六章立刻换挡。

pretrain.py 和 finetune.py 全部迁移到 Transformers 生态,分布式交给 DeepSpeed,目录里躺着 ds_config_zero2.json,微调部分讲 LoRA 和 QLoRA。翻译一下这个安排,手写是为了知其所以然,工业实践另起炉灶,教材没有假装手写代码能上生产。

这种坦诚我挺喜欢。不少教程写到一半开始模糊「教学实现」和「生产实现」的边界,读者真拿着玩具代码去跑业务。happy-llm 在第 5 章和第 6 章之间划了一条明确的线,线两边的代码风格、依赖栈、心理预期全都不一样。

最新一章,教模型自己改错

2026 年 8 月合入的第八章是全书保鲜期最短也最生猛的部分,四个专题,GRPO、OPD、Search-R1、ReTool。

GRPO 的示例以 GSM8K 为题库,grade_answer 从输出里抽 \boxed{} 算规则奖励,run_rollout_group 对同一道题采一组回答算组内相对优势,loss 可以在 importance_sampling 和 ppo 之间切换,同步版按 prompt 顺序跑,异步版用 asyncio.gather 并发整个 batch。Search-R1 教模型学会先搜再答,ReTool 更进一步,直接训一个写 Python 代码解决问题的 Coding Agent。

ReTool 目录里的 sandbox.py 值得单独讲。模型生成的代码要在本地跑,这个沙箱写了四道保险。BoundedSemaphore 限 8 并发,30 秒 wall-clock 超时后 os.killpg 杀掉整个进程组,子进程引导串里设 RLIMIT_CPU 做内核级兜底,输出写匿名临时文件再按 4096 字符截断,连 BLAS 线程数都压到 1,防止多个并发沙箱把机器打满。代码用 repr 内嵌进引导串,不落脚本文件,注释里写明是为了消灭注入面。

最狠的是它的结果哲学。注释原文写着,报错不修饰、原样回喂,论文中「自我纠错」的行为正是从看到 traceback 再改代码中涌现的。教材没有把报错藏起来糊弄,而是把报错当成训练信号。这个认识在 RL 训练里已经成熟,但写进中文教材还是头一回。

不过这一章的实践门槛变了。代码依赖 pytrio 0.2.6,模型采样、前向反向全在远端 TRIO 平台执行,本地只要一台能联网的 CPU 机器。代价有两个,一要注册 TRIO 账号,二要按量付费。学习与环境准备.md 里专门写了费用提示,第一次跑请保留单步小 batch 配置,确认链路再扩大规模。

这是全书唯一一道付费墙。

课本边上的读书笔记

这个项目还有个 Extra Chapter 机制,读者把自己写的 LLM 学习笔记 PR 进来,目前收了 7 篇,作者来自福州大学、同济大学、西安电子科技大学等高校,选题从「微调 0.6B 小模型有什么意义」到「用细粒度语义信息增强 RAG 检索」。README 说得直白,视 PR 的质量和价值决定合并或吸收进正文。

一本教材,长出了投稿通道。

这大概是开源课本相对纸质书最大的优势。笔记、课件、CCF 课程各自生长,主仓库只管正文质量。两位项目负责人宋志学和邹雨衡把关,社区供稿补充边角,书就不再是一锤子定稿的死物。

勘误页上写得明白

夸完了,讲问题。这本教材的缺陷,我挖到几条实打实的。

最扎眼的一条藏在文件名里。ddp_pretrain.py 叫 DDP,init_model 里包的却是 torch.nn.DataParallel。DP 是单进程多线程,通信开销和负载均衡都比真正的分布式数据并行差一截,PyTorch 官方早就不推荐了。教学代码求简单可以理解,但文件名和实现不一致,初学者照着名字去搜文档,学到的就是错的东西。

环境这块也有坑。第 2 到第 7 章要求 Python 3.10 或 3.11,第 8 章直接跳到 3.13,pytrio 锁死 0.2.6,官方的解法是让读者给每一章单独建虚拟环境。issue 区 2025 年就有人希望给出各依赖包的固定版本号,如今不少依赖仍是宽松约束,和环境碎片是同一个痛点的一体两面。

安全边界上,文档说得很直白,配套 sandbox.py 只能限制部分资源,无法提供可信隔离,请使用一次性容器、低权限虚拟机或专用沙箱服务,并移除环境中的 API Key 和云服务凭证。态度算诚实,但也意味着 ReTool 的实验环境你要自己再搭一层,跟着教程跑不等于安全。

人的问题更隐蔽。贡献者名单近 30 人,KMnO4-zx 一人 161 次提交,logan-zou 54 次,两人合计占全部提交的八成以上,教科书级的 bus factor 风险。而第八章作者正是 KMnO4-zx 本人,他把更新更快的 Agentic RL 内容放在个人仓库 agentic-rl-lab,README 明说那边更新频率更高。教材的第八章,实际上是那份活文档的定期蒸馏版。

最后是协议,CC BY-NC-SA 4.0,署名、非商业、相同方式共享。拿它做公司内训没问题,包成付费课卖就是违反协议,和 PDF 水印防的是同一拨人。

按保鲜期分层

拆到这里,我觉得 happy-llm 最值得抄走的不是那 803 行代码,是它对「教材过期」这件事的处理。

你想想看,一本 LLM 教材的不同部分,腐烂速度完全不一样。RMSNorm 和 RoPE 这些数学原理十年内不会坏,Transformers 加 DeepSpeed 的工程栈两三年一换,GRPO 和 ReTool 三个月就冒出新东西。多数教材把三种速度的内容混进同一套体系和同一份依赖,结果是前沿一过期,全书跟着陪葬。落到图上,就是给不同保鲜期的内容配不同重量的隔离措施。

按保鲜期分层的教材结构
按保鲜期分层的教材结构

happy-llm 的做法正是照着这个分层来的。慢的部分写进正文求稳,中等的部分每章独立环境隔离依赖冲突,最快的部分干脆引流到外部 lab 仓库,教材只保留一份蒸馏版。第八章用 Python 3.13 配锁死的 pytrio 版本,表面看是碎片化,其实是把最容易烂的一章装进了单独的保鲜盒。

写活文档的人都可以抄这个结构。内部培训材料、团队 wiki、开源教程,先问一句这部分内容能保鲜多久,再决定它放进正文、独立环境还是外置仓库。

至于什么人该读它。想搞懂 LLM 底层原理的工程师、想亲手训一个自己模型的学生,这是中文世界里目前最完整的一条路径。只想调 API 的不必来,前四章会闷死你。想直接上生产级 RL 训练的去 agentic-rl-lab,教材的定位是带你入门,不是替你打仗。

评论互动

© 2026 王若风的技术博客 · Powered by Astro