Jasaxion一只大雄

风打,碎琉璃; 打不碎的,是那阳光漫地。The wind strikes, shattering the glazed glass; Yet unbroken remains the sunlight spilling across the earth.

[基模杂谈]代码预训练数据管线经验杂谈

Jasaxion / 2026-09-28


主页

随着蒸馏实验的不断发展,现在越来越多的研究发现数据产生的价值越大越模型架构等,把数据做好模型能力有稳步的提升。代码数据预训练的来源和流程,优化路径包括:去重、模型打分、合成数据与过程数据融合,助力模型性能提升。

写在前面:显卡负责计算,数据负责决定算什么

这篇文章起源于我之前在 JD 参与 JoyAI-LLM-Flash 预训练过程中的一些经验记录。这里不展开未公开的数据配方和内部实验,而是把这段时间关于代码预训练的思考,与公开论文、数据集和工程实践放在一起,重新梳理一遍。

我越来越认同一句不太严谨、但很有工程现场感的话:一个好的基座模型,离不开“数据 + Infra”。显卡当然重要,不过把同一份样板代码训练十遍,显卡只会认真地帮你算十遍,不会主动弹窗提醒:“老板,这个我是不是昨天见过?”

严格说,模型能力是数据分布、模型结构、训练目标、计算预算、优化策略和评测共同作用的结果。本文不打算证明架构不重要,而是讨论一个更实际的问题:当模型和预算大体确定以后,我们还能怎样通过数据,让每一份算力花得更明白?

我的关注点也因此从“又收到了多少 TB”逐渐转向几件事:收进来的究竟是什么;模型实际看了多少次;样本是否对应想要的能力;涨分来自有效学习,还是碰巧把考卷也收了进来。

一、误区:TB、token 和“训练过”不是一回事

代码数据讨论最容易发生的误会,是大家都在说“规模”,却根本没在数同一种东西。

资产实际问题常见误读
抓取与存储字节下载、解压或存储了多少数据?把压缩体积、源码字节、重复出现的字节混为一谈
文件条目与唯一内容某文件出现在哪些仓库?有多少不同正文?把目录清单条目当成已下载且唯一的源文件
唯一语料 tokens去重、筛选后有多少可用内容?忽略 tokenizer、数据版本和过滤范围
累计训练 tokens经过采样和重复,模型一共看了多少?把多轮训练消耗当成独立新数据
有效监督 tokens多少位置实际计算了训练损失?把 padding、仅作上下文的内容也算成等量监督

例如,Seed-Coder 的 GitHub 文件语料约有 1T unique tokens,但整个预训练累计消耗 6T tokens,还包含代码相关网页、数学相关网页以及后续阶段的数据。Phi-1 的约 7B-token 语料也不意味着只训练 7B:论文报告多轮训练后累计略超 50B tokens。

把 unique tokens 和 consumed tokens 混用,会同时误判数据覆盖、重复次数和训练成本;把所有输入位置与 loss positions 混用,又会把两种长上下文配方比较成苹果对梨。

本文后面出现的数字,尽量说明它是“原料池”“训练子集”还是“累计消耗”。跨论文的 token 数如果没有统一 tokenizer,就先当量级参照,不急着算精确增长倍数。

二、经典 The Stack 三代,不只是越来越大,也是在重新定义“可用”

2026年代码数据的主线是”去掉人的手工规则,加上可验证的信号“。

流水线已经收敛成一个共同栈:抓取–>精确去重–>跨语言近去重–>最少量规则前置–>模型打分/分类器筛选–>分阶段配比–>仓库级打包+FIM;

而真正拉开差距的三件事是:合成数据的形态(改写型 vs 教科书型vs可验证型) 、软件演化过程数据(commit/PR/issue) 、以及 midtraining的时机与配比。

开源代码数据:Stack 三代

版本时间原始规模训练切分语言关键变化
Stack v120226.4TB≈200B Token358首次把“许可合规的大规模代码”做成公共品;opt-out 机制
Stack v2202467.5TB≈550B Token600+基于 Software Heritage, SWHID 溯源;但内容需二次获取
Stack v32026.07113.7TB /
224M 仓库 /
约 439 亿文件
≈4.9T Token
/ 15.9TB
/173 M 仓库
713(train)
/ 770(full)
直爬 GitHub、内容内联、跨语言去重、修掉v2的去重缺陷

Stack v1:给公开代码贴上来源、许可和退出入口

The Stack 最初论文介绍的是约 3.1 TB、30 种编程语言的宽松许可源码集合;后来 v1 系列扩展,才出现我们熟悉的 6.4 TB、358 种语言等回顾口径。不能把后续版本的规模直接贴到最初那篇论文上。

它的基本思路可以这样理解:

image

这里有两个经常被省略的细节。

第一,GHArchive 是仓库发现线索,不是源代码正文仓库。论文从事件记录中取得约 2.21 亿个仓库名,实际下载约 1.37 亿个仓库;全量获取与最终许可子集,显然不是同一个统计对象。[1,§3]

第二,许可分类不是一次运行后永久正确。v1 数据卡记录,早期被归入 permissive 的 MPL、EPL、LGPL,后来因属于弱 copyleft 被调整出相应许可范围。[2] 这个历史很值得记住:自动识别和人工政策都可能变化,保留许可证据与版本,比只保留一个布尔值 ​is_safe=true 更重要。

v1 也不只是发布数据。它在 350M 模型、Python 子集上比较近去重方案;宽松许可设置下,HumanEval pass@1 从 10.99 到 13.94,MBPP 从 11.60 到 15.94。[1,表5–6] 这支持“在该设置下去重改善效果”,却不能直接推出今天任何规模、任何语言都应使用相同阈值。

v1 的意义可以概括为:公开代码不再只是一个巨大的下载目录,而开始成为带有来源和治理机制的研究资产。

Stack v2:从独立软件档案里取数据,但档案不等于训练集

The Stack v2 借助 Software Heritage(SWH)的软件归档图。SWH 使用内容寻址结构组织文件、目录、版本与快照,适合去重存储、追踪来源和定位历史软件对象。[3][4]

不过,SWH 保存历史,不等于 The Stack v2 把全部历史都拿来训练。 StarCoder2 论文明确写道,它为主源码提取选择主分支的最新 revision。档案馆里有历年报纸,你去借最新一期,并不等于把档案馆搬回了家。[3,§2.1]

v2 的核心流程是:

image

数据卡报告约 3.28B 个唯一文件、67.53 TB,来自约 104.2M 个 GitHub 仓库。[4] 相比 v1,语言识别和文件树许可传播也更系统:不仅看文件扩展名,还使用 go-enry 等工具;许可信息通过目录结构关联到文件。[3]

v2 的一个现实门槛是内容访问。公开数据集主要给出 SWHIDs 等标识,正文需要按 Software Heritage 的批量访问安排获取。 [4] “拿到了数据集”可能只是拿到了一叠提货单,提货本身还需要授权和工程工作。

这也解释了为什么 v2 的不同数字总让人困惑:

Stack v3: 正文更容易拿到了,但“开箱可读”不等于“无条件可训”

BigCode 社区发布 The Stack v3,这是迄今最大的开放代码数据集,包含114 TB 原始数据、 15.9 TB 处理后数据、约 5T 去重tokens,涵盖 770 种编程语言和2.24亿仓库,完全开放且无限制许可。相比2024年的v2(68 TB raw /550B tokens / 618种语言),V3 在规模、语言覆盖和使用便利性上大幅提升,并重新爬取了截至2025 年8月的最新 commit。

数据全集: https://huggingface.co/buckets/HuggingFaceCode/stack-v3-full

2026 年 7 月出现的 The Stack v3 重新直接抓取 GitHub 默认分支快照;官方说明抓取于 2025-08-07 完成,不包含完整 Git 历史。训练版把 UTF-8 正文放进 ​files[].content,按仓库分组,使用上明显更方便。[6]

初版约 4.9T tokens;截至本次核查,官方 v3.1 修订已将其更正为约 3.6T。 Changelog 的原因是分区错误造成精确重复文件泄漏,而不是发现了四分之一代码“质量不好”。

固定修订 ​1f61b735bc0a5698345ce2196730f24bfa467f33 的训练统计为:

统计项该修订报告值
仓库记录172,823,131
保留文件条目2,267,483,994
源码字节11,501,524,769,560,约 11.50 TB
编程与标记等语言类别713
估算 tokens3,611,282,968,225,约 3.61T
用于估算的 tokenizerQwen/Qwen3-Coder-Next-Base

以上是官方统计,不是本文下载全库后重算。该修订 README 开头仍残留 15.9 TB,而版本对照表与结构化统计已更新,因此这里采用结构化统计,并把旧数字作为初版历史记录。[6]

算法层面做了去重,不代表分布式落盘、分区和拼接以后,产物里就一定没有重复。 验收最终产物,不要只验收流程图。

v3 还需要分清两种发布物:

image

官方对 full 报告约 113.7 TB、约 224M 仓库、43.9B 文件条目,但其中约 28.3B 是 stub:二进制、超大文件、无法识别语言等对象只留下了清单信息。[6] 所以“439 亿条目”不是“439 亿份下载即用、彼此唯一的源码”。同样,按仓库分组只描述组织方式;经过过滤与去重,依赖和文件不一定完整。

近去重方面,v3 在所有语言上共同处理,使用 MinHash-LSH 与 Jaccard 估计复核;候选阈值报告为 0.7,簇代表按 stars、forks、宽松许可、仓库较早创建的顺序选择。[6] 这里的“跨语言”是跨语言分区检查文本重复,不等于自动判断 Python 和 Java 是否实现了同一算法。

v3 相比v2优化了什么?

真正值得继承的不是“一代比一代大”的单向故事,而是:来源治理、内容可得性、过滤可重建性和产物质量,都在成为数据集的一部分。[1–6]

三、代码数据源:GitHub、SWH、Common Crawl

我曾经很喜欢“GitHub 是活的当下,SWH 是历史,网页是人类对代码的解释”这种概括。它有画面感,但一旦写得太满,就会误导实现。

代码数据来源于GitHub、Software Heritage、 Common Crawl,它们其实是同一批代码的三种视角: GitHub 是活的当下, Software Heritage 是死的全历史,Common Crawl是人类对代码的解释。三者供的不是同一种东西,因此也不能互相替代。[3][4][32]

KMind Zen

三个数据源的能力归属(token 占比为 RefineCode 口径)。注意 token 量与能力数量是反相关的:GitHub 供了78%的token 但只撑起基础代码能力,SWH 只占12.5% 却撑起了整个可审计与合规维度。

维度GitHubSoftware HeritageCommon Crawl
本质活的平台死的档案人类的解释
提供的资产默认分支源码、issue / PR / commit、star / fork / 许可、CI 状态全量版本历史、SWHID 永久标识、已去重的 Merkle 图、跨 forge(GitLab / PyPI / npm / Debian)教程、官方文档、博客、Stack Overflow 问答、API 参考
不可替代之处唯一的天然过程监督来源:改了什么、为什么改、改完过不过 CI唯一能回答“两年前这个文件长什么样”,因此也是唯一能做干净时间切分与作者级 opt-out 的路径唯一的自然语言 ↔ 代码大规模对齐语料
缺什么没有稳定标识(force push / 删库即失效);许可元数据噪声大;无法回溯历史内容分发受法务约束;函数数据集快照有滞后(v2 用的是 2023-09-06 的图)候选占比极低(约 3%)、噪声极大;代码片段常不完整、不可执行
Token 占比(RefineCode)755B(78.4%)120B(12.5%)71B(7.4%)

三者存在重叠:同一份 README 可能出现在 GitHub、SWH 和网页抓取中。所谓“多源”,可能真的是多种知识,也可能只是同一本说明书换了三个快递箱。

OpenCoder 的 RefineCode 给出了一个不错的量化例子。论文表 2 中的来源是:[7]

来源tokens
GitHub Code755B
Jupyter Notebooks11B
The Stack v2120B
Processed Common Crawl13B
Processed SkyPile3B
Processed FineWeb55B
Processed AutoMathText3B

合计约 960B。13B、3B、55B 相加是 71B,但它是三个网页子来源的合计。FineWeb 上游来自 Common Crawl ,也不意味着直接来源列可以随意合并;上游和当前数据产品是两个维度。

755B 占得多,并不能证明 GitHub“只提供基础能力”;SWH 的可审计性首先是数据治理属性,不是模型吃下某种 token 后自动学会的一项技能。要讨论来源的边际价值,需要固定预算的替换消融。

许可与 PII:开放数据不等于免检数据

v3 的数据库许可为 ODC-By,原始源码仍需遵守对应许可证;​no_license 表示流水线未识别出许可,不是作者主动放弃版权。full 还明确未做 PII 脱敏;train 虽经 StarPII 扫描,官方也说明检测并不完美。[6]

因此,许可政策、退出请求、密钥和个人信息风险,不能等质量评分器打完分再决定。模型认为代码写得漂亮,与我们是否应该处理、训练或再分发它,是两个问题。更稳妥的做法是保存原始许可文件、路径适用范围、识别器版本和所有来源关联,并按使用场景审查。

四、代码数据流水线

这里总结了预训练代码数据的几个过程:采集、精确去重、近似去重、语法过滤、质量打分、配比调度、打包拼接。

image

做什么典型代价2026 年的默认做法
采集直接爬 GitHub 默认分支 / 用 SWH 档案 / 从 CC 抽代码网页存储与带宽;v3 原始 113.7 TB直接爬 + 内容内联(v2 只存指针,被吐槽“数据集在哪儿”)
精确去重按内容哈希折叠,每个文件只存一份几乎免费必做,覆盖率最高收益最大
近去重MinHash + LSH 聚类,每簇留一个代表CPU 与 shuffle;是流水线最大瓶颈之一跨语言全局聚类 + Jaccard 复核(v2 是按语言分别做)
语法过滤Tree-sitter 解析,剔除语法错误文件便宜作为规则前置的一部分,不做深度语义检查
质量打分LLM 标注小样本 → 蒸馏小打分器 → 全语料推理一次推理全语料;1.3B 打分器是主流折中只滤最差的一档(10% 量级),不做“只留 1% 精品”
配比与调度决定各源在各阶段的采样权重需要小模型消融,一次可信消融是 10⁴ GPU-day 量级三阶段:通用 → 中期(高质量/仓库/合成)→ 长上下文
打包拼接、FIM 注入、去污染低依赖拓扑拼接 + 结构感知 FIM + 多层去污

关键是把“算特征”和“做决定”分开。某个文件的模型分数已经花钱算完,阈值从 0.4 调成 0.5,通常不该再把整个模型推理跑一遍。换一个仓库配比,也不应该重新爬 GitHub。Seed-Coder 明确强调模块可单独运行,便于增量扩展与避免全流程重算。[5,§2.1]

至少应记录:输入快照与文件清单、处理代码版本、tokenizer、规则与评分器版本、随机种子、输出摘要,以及每阶段文档数、字节数和 token 数。按语言、来源、长度、仓库类型分桶保存排除样本,比一个漂亮的总保留率更能帮助排障。

DataTrove 官方 MinHash 示例有一句非常朴素、却很重要的警告:最后重读输入删除样本时,输入来源和任务划分必须与生成签名时一致。[30] 如果删除索引基于旧分片的行号,中间却换了输入顺序,那么一个完全正确的去重算法,也能很高效地删错文件。

所以我理解的 Infra,不只是“跑得快”,还包括:能够证明这一轮究竟处理了什么,失败后怎样恢复,参数改变后哪些东西需要重算。 这和最终模型分数一样,是数据资产可信度的一部分。

五、流程 1:去重

精确去重先解决“同一份内容被搬了多少次”

代码世界的重复来源很多:fork、镜像、vendored 依赖、复制的工具脚本、生成代码和不同来源的重复收录。精确内容哈希适合作为第一道基线,但“算法简单”不等于“几乎免费”:全量读取、解压、哈希、shuffle、结果回写和溯源关联都要花成本。[7][30]

还要区分原始字节哈希和规范化后的哈希。统一换行、剔除注释、修改空白,对查重可能有帮助,但不应该悄悄把规范化文本当成原始证据;Python 缩进更不是普通装饰。建议保留不可变原文,另存用于检索的视图与变换版本。

去重是代码数据流水线里最容易被低估的一环。直觉上它是个算法问题(用什么哈希、多少band),但2025-2026年的证据一致指向另一个结论:检测算法已经收敛到一个性价比点,真正決定下游效果的是保留策略——删多少、留哪一份、大簇怎么处置。

MinHash-LSH 的阈值,不是想象中的门禁线

把文档切成 shingle 集合后,Jaccard 相似度为:

$$ J(A,B)=\frac{|A\cap B|}{|A\cup B|}. $$

理想的独立 MinHash 下,单个签名位置相同的概率等于真实相似度 $s$。LSH 把签名分成 $b$ 个 band,每个 band 有 $r$ 行;至少一个 band 完全相同,就把这对文档召回为候选:

$$ P(\mathrm{candidate}\mid s)=1-(1-s^r)^b. $$

FineWeb 的公开参照是词级 5-gram、112 个 hash、14×8 分组。[8] 在这个固定配置下:

真实 Jaccard 相似度 $s$候选命中概率,近似值
0.7056%
0.7577%
0.8092%
0.8598.8%

这里变化的是文档对的真实相似度,不是把删除阈值从 0.75 调到 0.85。若另有候选复核阈值,固定候选集下提高阈值,通常会保留更少重复边,而不是删得更多。

需要分别记录四件事:shingle 怎么定义、LSH 怎么召回、候选如何复核、复核后的边如何聚簇。FineWeb 的这版方案直接用 LSH 匹配进行传递聚类;不能把另一个方案的 Jaccard 复核步骤强行写进它的方法。[8]

聚簇还有一个隐藏坑:A 像 B、B 像 C,不保证 A 同样像 C。连通分量不是一个“任意两点都超过阈值”的朋友圈。大簇里可能是真正泛滥的模板,也可能有桥接样本造成链式合并。看最终删除率之前,先抽查边、簇和代表。

minhash_hit_probability_redrawn

命中概率随相似度陡峭上升。这意味着阈值的选择比哈希函数的数量更敏感:从0.75提到 0.85,命中率从 77% 跳到98.8%,被判为重复的文件量差出一个量级。

太容易相似了

文件级还是仓库级,也是代码特有的陷阱,为了保结构而在仓库粒度去重

代码比文本多一个维度:文件不是独立的,它们属于仓库。于是出现了一个诱人的想法——为了保留仓库结构,就在仓库粒度去重。

OpenCoder 的 Python 实验给出了很有说服力的局部证据。相同原始池中约有 4.858 亿文件、1103 万仓库;文件级去重后保留 32.74B tokens,仓库级保留 99.47B,约为前者三倍。仓库级结果再做文件级去重,还能删除约 68B tokens,即 68.4%。在对应 1.5B 模型的 HumanEval/MBPP 实验中,文件级方案更好。[7,§6.1、表9、图8]

故此为了保持结构而牺牲去重,等于把去重作废。

原因并不难理解:两个仓库整体差异很大,不妨碍它们都拷贝了同一个公共依赖。只看整仓库相似度,局部重复会被其他文件稀释。

但结论不是“仓库级上下文没用”,而是“仅用仓库作为判重单元,不足以控制文件冗余”。我会把实现拆成三层:内容存储去重、仓库版本关系保存、训练曝光权重控制。

完全相同正文可以共用存储,但每个 ​repo/commit/path 关联仍应保留;近重复文件则不能随便替换成另一仓库的代表,否则 API 版本和依赖可能错位。更微妙的是:磁盘上只存一份,不代表训练时只看一遍。如果打包时按一百个仓库关联展开,同一依赖仍可能出现一百次。

因此,“文件去重后恢复仓库”是一条设计方向,不是一条无损定理。可以限制重复内容参与 loss 或限制采样,但重复上下文本身仍消耗算力,也仍影响其他位置的预测。需要看实际训练曝光,而不只是存储压缩率。

image

文件级完成去重后,在打包时再重建仓库结构,两者应该解耦。

去得越干净,一定越好吗?FineWeb 的答案是“不一定”

FineWeb 曾尝试跨全部 crawl 全局去重,老快照被删掉大量内容,最终留下的数据在同预算训练中却不如每快照独立去重。作者检查发现:经常出现的正常内容被削掉后,广告、关键词列表等相对更容易被放大。 [8]

FineWeb2 则按自然语言跨快照去重,并保留簇大小,随后依据不同簇大小的质量过滤率重新分配重复权重,称为 rehydration。[9] 它不是“N≥1000 一律删除”,也不是“最大的簇训练最多”。其权重依据语言和质量统计变化,而不是一个全局神奇数字。

这两项工作告诉我的不是“重复好”或“重复坏”,而是:去重改变了采样分布;删掉什么与留下什么,同样重要。 删除重复和有意识地重复高价值数据并不冲突,前提是后者是可解释、可测量的选择,而不是文件复制留下的偶然结果。

六、流程 2:质量过滤,规则管底线,模型给信号,实验做裁决

从手工规则走向模型,不等于把人类判断从系统里删除

质量过滤是 2025-2026年变化最剧烈的地方。

2023-2024 年的主流是“人写规则“:StarCoder 的长行/字母占比/编码数据过滤, DeepSeek-Coder 的分语言规则,OpenCoder 的130+条手工规则带自定义权重ß。

2025年之后,头部团队不约而同地改成“用模型打分“。

image

规则的优势很实在:便宜、可控、可解释。长行、乱码、明显生成标记、大块编码数据,都适合先用规则处理。缺点也明显:表面特征容易与真正想要的质量错位。[3][5][7]

Seed-Coder 举了两个很好的例子:一个温度处理函数注释齐全,却出现 ​temp < 0 and temp > 1 这种不可能条件;另一个看似大量硬编码数字的数组,实际上用于 LED 图案显示。[5]

image

前者不是“逻辑错误无法量化”——约束分析和边界测试就可能发现。真正困难的是,为任意真实项目廉价地取得完整规格并验证。后者也不是错误代码,而是告诉我们:脱离使用场景,看起来像垃圾的数字表,可能正在认真工作。

因此,模型评分的价值是补足规则难以表达的软判断,不是给代码颁发“所有输入下都正确”的证书。

Seed-Coder 的“只滤 10%”,但其量大

Seed-Coder 从常见语言抽取 222,066 个文件,让 DeepSeek-V2-Chat 按可读性、模块化、清晰度和可复用性评分。 再把分数归一化,用一个 Llama 2 结构的 1.3B 预训练模型加回归头,训练一轮,扩展到全量评分。[5]

随后过滤最低约 10% 的文件,得到约 1T unique tokens、89 种语言。但在它之前,去重、基础处理与语法检查已经让原始数据体量减少约 98%。两个阶段的计数单位还不完全相同,不能直接相乘得出精确总保留率。[5,§2.2.1]

所以准确的经验是:“对已经处理过的语料,再保守地去掉低分尾部”,而不是“原始 GitHub 九成都是好东西”。

模型偏差也没有消失。Seed-Coder 自己发现,网页评分容易偏爱格式整齐的电商、颜色页面与文档,而低估杂乱但有信息量的论坛,因此还需要分类别调整阈值和采样。[5,§2.2.3] 人工规则少了,人类对目标、标签、类别和评测的选择仍在。

Stack-Edu 与 MIRA:足够好的筛选,可能根本不是同一种“好”

Stack-Edu 的目标更偏向教育性,因此筛选较为激进。它从 StarCoder2Data 的 15 种主要语言中,用 Llama3-70B-Instruct 生成教育性评分,并训练 15 个语言专用 StarEncoder 分类器,每个使用 50 万样本。最终从约 450B tokens 中保留约 125B,仅约 28%。[10]

但这个 28% 不能与 Seed-Coder“保留约九成预处理后文件”直接比较。 两者的筛选目标、原始数据分布、统计分母和训练阶段均不同。更重要的是,Stack-Edu 在 SmolLM2 中的效果实验也并非“仅用这 125B tokens 从零训练”:相关消融是从已经训练 3T tokens 的检查点出发,再进行 200B-token annealing;其中 Python HumanEval 从 20.7 提升到 25.6,C++ MultiPL-E 从 16.7 提升到 24.8。[10,表2]

因此,这里的结论不是“保留比例越低越好”,而是​筛选强度应与数据目标和训练阶段匹配。

2026 年的 MIRA 进一步讨论来源感知 rubric:不同数据组先明确该评什么,再做教师打分、学生蒸馏和组内选择。Qwen2.5-Coder-14B 的实验中,25B-token 的 MIRA-Group 在四类任务宏平均上为 64.20,50B raw mixture 为 63.83;但 SWE-Multi 是 36.33 对 40.00,仍有退步。[11,表1]

“半量追平”因此只在该宏平均与后续统一 SFT 设置下成立,不能翻译成所有能力不降、总成本减半。更有意思的是,MIRA-Global 甚至不如同预算随机选择:不同来源的分数未经校准放到一把尺子上,可能比没有这把尺子还糟。

我会怎样给评分器验收?

基于以上证据,我更关心四类检查,而不是先决定评分器一定要多大:

Tree-sitter 也一样:解析成功不是编译成功,错误恢复产生的树不意味着语法合法;解析失败也可能来自新语法、DSL 或解析器不支持。将失败单独分桶,比把它们一律判成低质更可控。

这一节的结论是: “质量”不是样本固有的单个分数,而是样本、目标、上下文和预算之间的关系。 [5][10][11]

七、流程 3:数据类型,commit、PR、issue:把静态结果变成修改能力

静态仓库是软件开发的终态:它记录了结果,却丢掉了规划、调试、返工、重构的过程。2025- 2026年最有价值的新数据源,几乎都来自“把过程找回来“。主要是:commit/PR/issue(重建) —— 的“过程数据” 。

静态仓库快照记录“现在是什么”,演化记录补充“从哪里变来”。但 commit 和 PR 仍是压缩后的结果,不是人类完整的思考录像:失败尝试、临时搜索和被放弃的方案经常没有留下来。

更合理的目标,是重建“意图—旧代码—变更—验证”的对应关系,而不是看到一个 commit 就宣布拥有了推理过程。

commit:从续写下一行,到决定下一刀改哪里

利用 commits 并非 2025 年才开始。2023 年的 OctoPack/CommitPack 已把 commit message 与代码变化用于 instruction tuning;CommitPackFT 选择那些更像自然语言指令的消息。[12] 人类程序员确实在不断贡献指令对,只是有时写得很认真,有时只留下一个足以让后人沉默的“fix”。

Seed-Coder 将这条路线扩到持续预训练:从 140K 个筛选仓库收集 74M commits,仓库门槛包括至少 100 stars、10 forks、100 次提交和 100 天维护活动;去重与预处理后形成约 100B-token 语料。[5,§2.2.2]

commit 变更预测样本示意

输入是 commit message、变更前 README、目录结构及 BM25 检索的五个相关文件,目标是修改路径和代码变化。相比静态续写,它更贴近定位与编辑,但论文没有给出“仅加入 commits、其他全部不变”的完整收益归因,所以不能把最终 SWE 分数单独记到它名下。

PR:先保证修改能重放,再讨论修改是否正确

PR 通常比单条 commit 多一些意图与评审语境。Clean-PR (arXiv 2602.07457, ICML 2026)是目前比较扎实的仓库级编辑数据工作。它从1640万条原始 PR(8.6TB、27.4万个仓库)出发,过滤后只有18.59% 合格——也就是说原始 PR 流的噪声率超过 80%。关键工程决定是:用 Search/Replace 编辑块替代脆弱的 unified diff,并做往返校验,最终得到202万个编辑块、覆盖12种语言。用在 Qwen2.5- Coder-32B 上:先mid-training,再做 agentless 对齐 SFT, SWE-bench Lite +13.6%, Verified +12.3%。[13,表2–4]

注意计数单位:不是 202 万个编辑块;一个训练实例平均包含 4.3 个 Search/Replace blocks。

Clean-PR 的核心工程动作是往返重建:

image

SEARCH 唯一、区域不重叠、重放结果一致,解决的是“训练目标是否忠实表达真实改动”。它没有自动证明项目可编译、测试全绿或 bug 真正被修好。[13,附录A.4]

简言而之:格式有效、行为验证、评测独立。

mid-training 与 SFT,不是非此即彼

PR数据的最佳落点是 mid-training,不是 SFT

Clean-PR 先做编辑数据 mid-training,再用定位文件、细粒度定位和补丁生成等分步骤样本做 SFT,还加入错误检索产生的干扰上下文。[13] 后一步很像告诉实习生:“文件出现在你面前,不代表它有罪。”

论文在 Qwen2.5-Coder-32B 与简化 Agentless 协议下报告:[13,表6]

训练条件SWE-bench Lite pass@1Verified pass@1
原 Qwen-Coder-32B-Instruct10.7%18.3%
Base + 本文 SFT,无 mid-training11.3%17.6%
Base + StarCoder2-style 17.4B + SFT15.7%20.4%
Base + Clean-PR 17.7B + SFT24.3%30.6%

相对第一行,提升是 13.6、12.3 个百分点。它是两阶段训练的组合结果,不是“mid-training 取代 SFT”的证明。17.7B 是语料规模,论文 mid-training 跑两轮,也不应直接当累计训练量。

这篇更有决策价值的局部消融,是 Python 条件下只用 PR 描述与增加关联 issue 的比较:Lite 20.4→22.3,Verified 25.7→27.8。[13,表8] Issue 提供了增量上下文,但 PR 描述本身已经能形成有效监督。

issue:需求视角很重要,但没有垄断“为什么改”

唯一把“需求”和“代码变更“配上对的天然语料

Comnmit 和 PR 给你的是改动本身,issue 给你的是改动的理由。这是它不可替代的地方:一条 issue 里天然含有复现步骤、报错日志、期望行为、以及维护者与报告者之间的多轮澄清,这是“自然语言需求–>代码变更“ 这一配对唯一的天然来源,纯代码语料里根本不存在。今天所有SWE 类任务的题面都是 issue,这不是巧合。

Issue 的优势通常是用户视角:复现步骤、异常日志、期望行为以及维护者的追问。它能补上开发者一句“修复边界情况”背后到底是哪种边界。

但 commit message、PR title/body、review 也可能解释原因。自然语言需求与代码变化并不只存在于 issue,软件工程任务的题面也可能是从 commit 回译、从变异生成,或由真实问题启发而合成。[12][13][17]

把数据源对象和训练产品分开,思路就清楚了:

训练产品内容最低需要验证什么
编辑样本描述 + before + edits能忠实重建目标状态
可执行任务题面 + 基线环境 + 隐藏测试任务可运行、测试有效、规定范围内无回归
交互轨迹观察、定位、编辑、工具调用与反馈终态结果、过程记录与模仿目标有效

三类产品都可以使用 commit、PR 和 issue;样本形态决定适合 CPT、编辑 SFT、agent SFT 还是 RL,而不是来源的名字决定训练阶段。

从真实任务到合成环境:SWE-Gym、SWE-smith 与 SWE-Mirror

SWE-Gym 为真实历史问题配环境和测试;SWE-smith 反过来在能运行的仓库里注入缺陷;R2E-Gym 从 commits 回译题面并收集或生成测试。[15][17][41] 这些路线都在解决同一个昂贵环节:让一段代码修改从静态文本,变成今天还能运行、还能给反馈的任务。

更全面的 Agent 打镜像的过程,可以参考文章:基模杂谈swe-环境构建与长程轨迹挖掘

SWE-Mirror 选择复用已有环境,把真实问题的核心逻辑移植到相似目标仓库:[18]

image

它最终报告 60,671 个验证任务,但不能称每个缺陷都在目标仓库历史中真实发生过:真实的是问题来源,迁移后的任务有合成成分。

最强 32B 模型的 SFT 使用 12,456 条轨迹,其中 6,431 来自 Mirror,6,025 来自 SWE-rebench。在其框架、轮数与上下文设置下,Verified 从 6.2% 到 52.2%,即提升 46.0 个百分点。[18,§3、表6] 这是混合轨迹与完整训练评测方案的结果,不是“给 issue 加一个验证器就涨 46 分”。

更值得借鉴的是验证边界。除了 F2P(失败转通过)和回归检查,作者还检查异常与 flaky 状态;同时对一小批成功镜像任务做人类语义审核,结果并非全部与源问题一致。[18,§2.4] 测试绿了,仍需要问:“它验证的还是不是原来那件事?”

这一节我最想留下的经验是:演化数据的价值来自关联、重建和验证,而不只是数量。任务数、成功轨迹数、编辑块数和 tokens,也必须各算各的。

执行化还会把数据工程变成供应链与隔离问题。安装脚本、测试和依赖都来自不可信代码,不应直接在带生产凭据的宿主机运行。建议使用可销毁、最小权限、受限网络和资源配额的环境,固定镜像摘要、base commit、依赖来源与测试命令,保留失败日志。容器是载体,不是“安全且可复现”的证明;未锁定的依赖和外部服务,足以让昨天通过的任务今天失效。这是工程防护建议,不是对上述论文执行环境的安全认证。

小结:三者对照

commit 和PR是语料,issue 是题库。

八、流程 4:合成数据,不是“改写型打败教科书型”的排行榜

合成数据至少有三条可以叠加的轴:是否锚定真实来源、是否教学化表达、是否经过外部可执行检查。

路线主要解决的问题最容易引入的偏差
改写型可读性、冗余、自包含性与表达噪声接口漂移、过度规范化、抹掉真实依赖
教科书/练习型概念讲解、示例密度与难度组织风格单一、题型窄、远离工程长尾
执行验证型实现与测试是否一致、修复能否闭环测试 oracle 错误、易验证任务偏好、环境成本

一个样本可以既是基于真实代码的改写,又带讲解,还经过测试。将它们排成单一优劣榜,反而会遮住真正的设计变量。[14][19][21][22]

SwallowCode:先筛,再改,改得漂亮也可能改错接口

东京科学大学的 SwallowCode(arXiv 2505.02881,2025-05,V4 于2026-03)是改写范式在代码上的代表作,也是少见的开放权重 +开放数据+开放prompt的完整工作流。它的口号是 transform-and-retain(改造并保留), 而不是 filter-out(过滤丟弃)。

SwallowCode 来自 The Stack v2 的 Python 子集,最终约 16.1B tokens。它的流程不是“任何低质量代码都不丢”,而是先用 Python 语法检查、pylint 和注释规则过滤,再执行两阶段改写:[19]

image

SGCR: 按风格指南重写命名、结构与表达

SCOR: 改善自包含性、冗余与实现

SwallowCode 真正值得关注的地方,不只是“把代码写得更漂亮”,而是它代表了一种不同于强过滤的数据策略:对于已经通过基础质量门槛、但表达或实现质量一般的代码,不直接丢弃,而是尝试通过改写把它转化为可用训练数据。 这与“只保留极少数高质量样本”的路线形成鲜明对比。在代码这种对数据量需求很大的领域,这种 transform-and-retain 思路尤其有吸引力,因为它试图提升已有数据的利用率,而不是单纯缩小数据池。

论文中的主实验也说明,这种改写在特定设置下能够带来明显收益。作者使用 Llama-3.1-8B 进行 50B tokens 的持续预训练,其中代码占 16%,即 8B tokens,其余为多语言文本。在相同训练预算下,与 Stack-Edu 数据条件相比,SwallowCode 在 HumanEval 上提升 17.0 个百分点,在 HumanEval+ 上提升 16.1 个百分点。[19,§3] 因此,这项工作的证据更准确地支持这样一个结论:经过针对性的质量改写,原本不够理想的代码数据可以变得更有训练价值。

但这里不能进一步推导成“改写总比过滤好”。论文同时报告了一个很重要的负结果:在 SGCR 风格改写之后,MBPP 性能反而下降了约 10 个点。[19,§3.3.1、附录I] 作者分析发现,问题并不一定出在代码逻辑本身,而是模型在追求风格规范时,会把题目要求的函数名改成更标准的 snake_case。代码本身可能更整洁了,但外部调用接口已经发生变化,因此无法再满足原来的评测规格。

这个现象揭示了改写型数据一个非常关键的风险: “代码质量变好”与“代码仍然忠实于原始规格”是两个不同的目标。 命名更规范、结构更清晰,并不意味着样本仍然保持相同的 API、函数签名和行为约束。如果只检查改写后的代码是否“看起来更好”,却不验证接口和语义是否保持不变,就可能把原本有效的数据改坏。

因此,从工程上更值得继承的不是“尽可能改写”,而是把两个验收维度分开:一方面评估风格、可读性、自包含性和冗余;另一方面必须单独验证函数签名、接口约定和可执行行为是否与原样本一致。换句话说,改写可以提高数据质量,但前提是不能破坏规格忠实性。

教科书路线不是“纯合成”,Phi-1 的最终成绩也不是只靠预训练

Phi-1 经常被概括为“用高质量教科书数据训练小模型”,但这个说法容易把它的数据构成和训练阶段过度简化。它的预训练数据并不是全部由合成教材组成:模型首先使用约 ​6B tokens 的筛选真实代码与 StackOverflow 内容​,在此基础上再加入 ​不足 1B tokens 的合成 Python 教材数据​;预训练结束后,又使用约 180M tokens 的合成编程练习 进行微调。[14]

因此,Phi-1 的效果不能简单归因于“合成教科书”。从结果也能看出不同阶段的作用:Phi-1 base 在 HumanEval 上约为 ​29% ​,经过后续练习数据微调后才达到 ​50.6% ​。换句话说,最终性能来自一套组合策略,而不是某一种数据形式单独奏效:先筛选真实数据,提高基础语料质量;再用教学化合成数据集中组织概念、解释和示例;最后通过练习式微调,让模型更适应实际编程任务的输入与输出形式。

教科书式数据真正擅长的,是提高单位 token 的“学习密度”。相比直接堆积原始代码,它可以有意识地把一个概念的定义、解释、代码示例和典型用法组织在一起,使模型更容易建立清晰的知识关联。这也是为什么教学化数据即使规模不大,也可能产生较高的训练价值。

但这种优势并不意味着真实代码可以被教材完全替代。真实软件工程中的很多信息天然难以通过“写一本好教材”覆盖,例如稀有 API、历史兼容逻辑、跨文件与跨模块依赖、特定框架约定,以及大量不规则的边界情况。教材通常倾向于展示清晰、典型和自包含的例子,而真实代码分布恰恰包含大量不整洁、不典型却实际存在的长尾模式。

因此,Phi-1 更值得借鉴的并不是“合成数据优于真实数据”,而是:真实数据负责提供分布覆盖,筛选负责提高原料质量,教学化合成负责提高知识密度,练习数据则进一步完成任务对齐。 教学性值得增强,但不应以牺牲真实工程分布为代价。

合成数据比例与训练效率的适用边界,“30% 合成、5–10 倍提速”

《Demystifying Synthetic Data in LLM Pre-training》研究的是英文网页数据与改写、问答、教科书式合成数据的混合,实训规模到 3B 参数、200B tokens,核心评价指标主要是验证损失。[20]

论文发现,在较大训练预算下,某些约三分之一改写数据、三分之二真实网页的混合,可以用更少训练量达到相近验证损失。“5–10×”来自 scaling 结果及其外推,描述的是训练样本效率潜力,不是 GPU 吞吐直接提升五到十倍,也不能等同于把数据生成、验证和失败重试都算进去后的端到端代码训练成本下降。

论文还观察到,33% 教科书式合成的混合优于 67%;但 Phi-4 的训练配方中又包含较高比例的合成与重写数据。[20][23] 这并不矛盾,因为两者的原料、教师模型、策展方式、模型规模、训练预算和评价目标都不同。更重要的是,该论文正文中“约 30% 较优”的概括,与部分精细比例实验并不完全一致;在缺少完整原始 run 表的情况下,不应把 30% 当成通用最优比例。

可验证合成:验证器本身也需要验证

UnitCoder 将真实代码提取、测试生成、执行修复和解释性改写串成闭环;KodCode 则同时生成问题、解答与测试,并通过执行结果和分支覆盖进行筛选。[21][22] 这类工作说明,数据改写和可执行验证并不是两条互斥路线,而是可以组合使用。 但它们的主要实验集中在后训练阶段,因此不能直接用来证明某种预训练合成比例就是最优方案。

需要特别区分的是:覆盖率高不等于测试正确。 branch coverage 达到 100%,只能说明测试走到了所有分支,并不能证明这些测试准确表达了原始需求。一个没有分支的 ​return x + 1​ 很容易达到满覆盖;如果真实需求其实是 ​x + 2,而生成的测试也理解错了需求,那么答案和测试完全可能一起通过,却同时偏离正确规格。

UnitCoder 还暴露出另一个容易忽略的问题:验证链路本身也可能引入评测污染。论文说明,其测试生成器使用 BigCodeBench 的函数和测试进行训练,随后又使用 BigCodeBench 评估下游模型。[21,§4.1] 即使训练时屏蔽输入函数的 loss,也不能据此认为上游生成器完全没有接触过评测信息。这不足以判断污染具体贡献了多少分,但足以说明:去污染不能只检查最终训练集,还要追溯 teacher、verifier、测试生成器和种子数据。

因此,可验证合成真正需要的是分层验收,而不是一个“测试通过”布尔值。除了执行通过率,还应分别记录测试 oracle 的可靠性、覆盖率、误杀与漏检、接口保持率,以及样本从原始代码到测试、改写和最终训练样本的完整谱系。

模型坍塌:关键在递归数据如何进入下一代

所谓“模型坍塌”,主要讨论的是多代模型反复消费前代生成数据时会发生什么。已有研究表明,如果每一代都用合成数据替换原始数据,生成误差会逐代累积,原始分布中的低概率和长尾模式也更容易消失;保留部分真实数据可以明显减轻这种退化。[24]

但这不能简化成“用了合成数据就会坍塌”。后续研究进一步区分了不同的数据更新方式:如果真实数据和历代合成数据都持续累积,并在下一代训练时共同使用,实验中可以保持稳定;如果总训练数据量固定,只从不断扩大的历史数据池中抽取有限子集,则仍会出现较慢的渐进退化。[25] 因此,​完全替换、固定比例混合和历史累积,本来就是不同的训练过程,不能用同一个“模型坍塌”结论概括。

一个直观但不严格的比喻是:真实数据像底片,合成数据像修图稿。修图本身并不可怕,危险的是每一轮都扔掉底片,只拿上一轮已经压缩过的信息继续生成下一版。反过来,始终保留底片和历史版本通常更稳健,但不断累积数据也意味着存储与训练计算可能随之增加。

对数据工程而言,更重要的不是争论“合成数据有毒”还是“合成数据安全”,而是记录真实来源是否仍被保留、合成样本来自哪一代模型、各代数据如何混合,以及长尾能力是否持续退化。模型坍塌首先是一个递归数据管理问题,而不是对单轮合成数据的统一判决。

九、流程 5:仓库与长上下文,内容、顺序、位置适配

仓库级训练至少包含三个不同变量:窗口里装了哪些内容;这些内容如何排序;模型是否适应这么长的位置跨度。它们经常一起改变,因此看到分数上升,不能自动宣布某一个是唯一主因。

一般采用拓扑拼接,但仓库内的拼接策略可能被高估了

Granite:长上下文扩展是一套组合配方

IBM 在 Scaling Granite Code Models to 128K Context(arXiv 2407.13739)里给出了目前最完整的配方:用import建 DAG –> 破环 –> 拓扑排序,文档与构建文件置顶、依赖文件次之、 非连通文件按目录树 DFS 排列;<4096 token 的文件降采样到 10%;RoPE $\theta$ 从8K/100K阶梯升到 128K/10M。只花 4B token(原预训练的 0.1%),长上下文任务最高+38%,短上下文只掉约1%。这套配方已开源为 IBM data-prep-kit 的 repo_level_ordering 变换(可在 SORT_BY_PATH 与 SORT_SEMANTIC 间切换)。

Granite 的 128K 上下文扩展并不是只调一个 RoPE 参数,而是建立在已有 3B/8B 代码基座之上的一整套数据与位置适配方案。[26] 在仓库级数据组织上,作者根据 import 关系构建文件依赖图,对其中的环进行处理后得到可排序的 DAG,再按拓扑顺序组织代码;文档和构建文件被优先放置,不连通文件则结合目录遍历进行安排。与此同时,训练还调整了长文档采样分布,并修改 RoPE 的基频参数。

这里有一个容易写错的概念细节:流程是先建立有向依赖图,再处理其中的环,使其变成 DAG,而不是“先建立 DAG,再破环”。两种说法看起来接近,但后者在定义上已经自相矛盾。

image

拓扑拼接是工程上合理的默认,但别指望它带来质变。真正决定长上下文效果的是位置编码的扩展方式。不同的拼接策略收益几乎一样,主要收益来自 RoPE ABF ($\theta$ 1e4 –> 5e5),且只用了1B token(实际有效72M)就追平数百 B token 的竞品。

论文在特定 RepoQA 设置下报告了明显提升,但需要注意,这一结果来自仓库组织、长度重采样和位置编码适配共同作用。因此,严格来说,它能支持“这套组合方案有效”,却不能单独证明收益主要来自依赖排序,也不能把效果全部归因于 RoPE 参数调整。[26]

IBM 官方的 data-prep-kit 也提供了 ​repo_level_order 变换,支持基于路径、语义等方式组织仓库级数据。[31] 对工程实践而言,更值得复用的是:明确记录输入结构、排序规则、长度分布和位置适配,并通过对照实验拆分各环节贡献,而不是直接照搬某一组 RoPE theta 参数。

项目级补全:先建立便宜而可靠的项目级上下文组织

《On Pretraining for Project-Level Code Completion》在 OpenCoder-1.5B 上研究 Python 单行补全,并将上下文从 4K 扩展到 16K,对比了多种项目级上下文组织方式。[27] 在统一推理 composer 的条件下,file-level 数据配合 RoPE 适配训练,in-project EM 已达到 45.2;使用 Path Distance 组织仓库级数据后提升到 48.8。相比之下,只修改 RoPE theta 而不进行相应训练,结果仅为 9.8。[27,表3]

论文系统比较了 15 种 repository context composer,即不同的仓库级上下文构造/拼接策略。
比较的策略不只是简单的“文件排序”,而是包括例如:

具体来说,他们把 OpenCoder-1.5B 的上下文从 4K 扩展到 16K,比较不同 composer 后,在 ​inproject​ 上各 repository-level composer 的 Exact Match 大约在 45.2–48.8 之间,最好与最简单策略只差约 3.6 个点。甚至 File-level + RoPE 长上下文适配 本身就已经达到很强的结果,因此作者认为 RoPE adaptation 是主要驱动因素,context composition 本身的贡献相对次要。

这组结果首先说明:长上下文能力不能靠“改一个 theta”直接获得,位置适配本身需要训练。 在完成这一基础适配之后,不同合理仓库组织策略之间的额外差距反而相对有限。这里更准确的结论是:应先建立一个足够强的 file-level + 长上下文适配基线,再判断更复杂的仓库级组织到底带来了多少增益;这并不意味着真实依赖关系或仓库结构没有价值。

成本口径也需要谨慎。论文脚注中的 72M tokens 对应的是一个特定的 file-level 适配实验,并不是所有仓库级训练都只使用了 72M tokens,更没有计入 OpenCoder 基座此前的预训练成本。[27] 因此,把结果概括成“72M tokens 打败数百 B tokens”会把已有基座的能力当成免费前提,容易高估这一步训练本身的贡献。

另外,还必须区分 training composer 和 inference composer。论文发现,在统一推理布局下,即使训练阶段使用反转顺序或加入部分无关上下文,与正常训练组织方式的差距有时并不大;但如果推理阶段本身也采用带干扰的上下文布局,性能会明显下降。[27] 因此, “训练时排序差距有限”不能被解释成“推理时上下文怎么塞都一样”。 训练组织和推理检索仍然是两个需要分别控制的变量。

OctoLong:从文件排序走向依赖可达性,跨仓库拼接

OctoLong 把问题从“仓库里的文件应该怎么排”进一步推进到“真正相关的依赖能不能进入上下文”。它利用 AST、语言服务器和包管理器递归追踪跨仓库依赖,构造依赖密度更高的长上下文。[28] 相比单纯用长文件填满窗口,这一路线更关注上下文的有效性:调用点所依赖的定义、包实现和关联逻辑,是否能够同时出现在模型可见范围内。

image

不过,需要区分能够构造多长的数据和​模型实际训练到多长的上下文。OctoLong 的数据采集主要围绕 Python 展开,虽然可以生成百万 token 甚至更长的依赖上下文,但论文中的主要训练窗口仍为 128K。完整训练流程包含约 50B tokens 的长上下文阶段,其中约 6.2B tokens 来自跨仓库代码,之后还包括模型合并以及约 10B tokens 的 SFT。[28]

因此,常见的“约 12% 跨仓库数据”只描述 50B-token 长上下文训练阶段内部的组成,不能直接理解为整个训练流程只增加了 12% 的成本。更有说服力的是论文给出的等规模替换实验:在 8B 模型上,将跨仓库数据替换为规模匹配的控制语料后,多项长程代码任务以及部分短代码指标都会回退。[28,表4、附录表9] 这说明收益并不只是来自“多训练了一些 token”,​依赖相关内容本身具有额外价值。不过,与官方 Qwen3-8B 相比,完整模型在部分 pass@1 指标上仍然较低,因此也不能把这种数据组织方式理解为对所有代码能力都单调提升。

把这一结果和前面的项目级补全实验放在一起,更合理的工程顺序是分层验证:先完成长上下文的位置适配,建立便宜而可靠的强基线;再通过等规模对照证明相关内容和依赖密度是否真正带来增益;最后才比较更复杂的文件排序与上下文组织策略。

十、流程 6:FIM:改变的是序列组织,不是预测范式

Fill-in-the-Middle(FIM)的核心,是把原始代码切成 prefix、middle 和 suffix,再重新排列,使模型利用左右两侧上下文恢复中间内容。虽然它常被称作一种训练目标,但实现上仍然可以沿用标准的自回归 next-token prediction,并不要求更换模型架构。[29]

1
2
3
4
原文:PREFIX | MIDDLE | SUFFIX

PSM:PREFIX → SUFFIX → MIDDLE
SPM:SUFFIX → PREFIX → MIDDLE

实际训练通常还需要专门的 sentinel token,不同模型的具体格式也并不完全兼容。上面的 PSM/SPM 主要描述内容重排方式,而不是完整的输入模板。

1
2
3
4
5
6
<fim_prefix>
def add(a, b):
<fim_suffix>
a + b
<fim_middle>
    return

FIM rate 控制的是“多少样本被改写”,不是“挖掉多少内容”

FIM rate 最容易被误解。一个常见的 ​0.5​ 通常表示:​约一半训练样本被转换为 FIM 形式,而不是每个样本都挖掉 50% 的中间内容。完整配置还需要另外指定 PSM/SPM 比例、切分单位、缺口跨度、结构化与随机掩码比例、哪些 token 计算 loss,以及在哪些数据来源和训练阶段启用。

原始 FIM 工作采用先按字符位置切分、再重新 tokenize 的方式,因此缺口可以落在词或 token 内部,更接近真实编辑器光标的位置。[29] 这里的“字符级切分”只描述切分位置,并不意味着模型使用字符级词表。论文同时保留 prefix、suffix 和 middle 区域的训练 loss,并建议混合使用 PSM 与 SPM,而不是只固定一种排列。

对于 FIM rate,原始实验在特定模型规模和训练预算下观察到:提高到 0.9 时,左到右建模能力没有明显下降,而 1.0 开始出现退化。[29] 这只能说明该实验设置下 FIM 可以占很高比例,不能进一步推出“0.9 对所有模型和任务都安全”。不同代码模型也采用了不同配置,例如 Seed-Coder 在 regular 阶段使用 0.5、continued 阶段降到 0.1,并采用 SPM;DeepSeek-Coder、StarCoder 等则分别使用自己的 PSM/SPM 配方。[5][29][33]

因此,FIM rate、排列形式和阶段调度都应视为需要实验确定的超参数,而不是固定行业规则。

结构化 FIM:让缺口更像真实编辑,但不能只剩结构化缺口

随机 FIM 可以覆盖任意位置,但很多随机缺口并不像真实代码编辑。Structure-Aware FIM 因此利用 AST,将缺口尽量对齐到函数、语句或其他语法子树,使补全任务更接近实际代码块编辑。[34]

但结构化并不意味着应该完全放弃随机缺口。该工作使用约 70% FIM,其中主体采用 AST 对齐,同时仍保留约 10% 的随机 FIM;对于不支持解析或解析失败的代码,也可以回退到随机切分。[34] 作者的消融进一步表明,如果只保留确定性的 AST 模式,模型容易适应这些规则化缺口,却在随机位置补全上明显变差。[34,§7]

这说明两类缺口覆盖的是不同分布:结构化 FIM 提高语义和编辑场景的真实性,随机 FIM 则保持对任意光标位置的覆盖。 真实 IDE 中的用户编辑位置并不会总是恰好落在一个完整 AST 节点边界上,因此二者更适合互补,而不是互相替代。

2026 年的 Function-Aware FIM 又进一步把“挖哪里”升级为“哪些函数值得挖”。它根据函数复杂度和可推断性筛选目标,同时引入教师生成的 rationale、候选实现和 judge 筛选,并继续结合 agent 后训练。[35] 因此,它带来的提升不只来自函数级 mask 本身,还混合了数据选择、合成、蒸馏和后训练信号。其主要实验集中在 Python,跨语言效果仍需要单独验证。

image

最后,FIM 数据管线还需要一个非常基础但不能省略的验收:经过切分、重排和逆变换后,是否能够逐字节恢复原始文件。 尤其在 Tree-sitter byte offset、Unicode、中文注释和 tokenizer 边界同时存在时,字符索引与字节索引一旦混用,就可能静默地产生错误训练样本。对模型而言,这些错误不会被识别成“数据工程 bug”,它只会把它们当成正常代码认真学习。

十一、流程 7:多语言与低资源:先测响应,再决定配额

代码预训练天生是多语的,但不同语言对规模的响应完全不同. Scaling Laws for Code: Every Programming Language Matters (arXiv 2512.13472)做了1000+次实验、 约336,000 H800卡时, 模型0.2B-14B、数据 1Ttoken, 是目前这个方向最系统的工作.

image

《Scaling Laws for Code: Every Programming Language Matters》没有把多语言训练简化成“哪种语言多喂、哪种语言少喂”,而是分别研究单语言缩放、跨语言迁移、多语言配对和预算分配。[36] 这几组实验共同说明:不同语言对参数、数据和辅助监督的响应并不相同,因此平均分不能直接替代语言级决策。

单语言缩放:先看每种语言如何响应参数和数据

论文分别对 Python、Java、JavaScript、TypeScript、C#、Go 和 Rust 做单语言训练,在 10 档模型规模和 6 档 token 预算下形成 420 个实验,并用类似下面的 scaling law 拟合验证 loss:

$$ L(N,D)=\left(\frac{N_c}{N}\right)^{\alpha_N} +\left(\frac{D_c}{D}\right)^{\alpha_D}+L_\infty. $$

其中 ​N​ 表示模型参数量,​D 表示训练数据量,拟合结果描述模型和数据继续增加时,预测损失还能下降多少。作者观察到,不同语言的缩放行为存在明显差异,例如 Python 对规模增长更敏感,而 Rust 在其实验分布下更早出现收益趋缓。[36,§3]

但这不能直接解释为“Rust 更简单”或“Python 就应该获得更多预算”。验证 loss 同时受到 tokenizer、数据来源、模板代码比例和翻译语料风格等因素影响,不同语言的绝对 token loss 也未必可以直接横向比较。决定下一批 token 投向哪里,需要结合缩放曲线、当前数据规模和实际任务指标,而不能只看某一个指数。

低资源语言:辅助语言能否比重复数据更有价值?

论文进一步固定 128B tokens 总预算,对比两种方案:一种是 64B 目标语言数据训练两遍,另一种是 64B 目标语言加 64B 辅助语言。[36,§4]

这个对照回答的是一个很具体的问题:当新的目标语言数据已经不足时,加入其他语言,是否比重复现有数据更有效? 它并没有证明辅助语言优于同等规模、全新的高质量目标语言数据;如果后者能够轻易获得,“低资源”问题本身也会弱很多。

跨语言迁移还具有明显方向性。A 能帮助 B,并不意味着 B 对 A 有同等增益;语法、类型系统、标准库和生态越接近,可能共享更多结构,但这种关系仍需要通过实际实验确认。由于论文中部分迁移表格与正文解释存在不完全一致的地方,这里更适合保留“迁移具有方向性”这一结论,而不是把某个精确矩阵直接转化成部署比例。

随机混合与程序配对,是两种不同的训练信号

把多种语言随机混在训练集中,与把​同一程序的不同语言实现放在一起,提供的监督并不相同。前者主要共享统计与编程知识,后者则显式暴露不同语言之间的语义对应关系。

论文的多语言配对实验表明,这种对齐监督确实可能改善整体表现,但收益并不会平均落到所有语言上。例如在表 3 的 7B 设置中,报告的五语言平均分从 32.46 提升到 33.79,但 Python 从 34.15 降到 26.22,而 Java 则明显提高。[36,§5、表3]

因此,平均分上涨不能代替逐语言验收。 配对数据可能增强跨语言迁移,也可能改变模型对主力语言的能力分布。与此同时,代码翻译本身还需要检查惯用写法和执行语义;语法能够编译,并不意味着生成的是符合目标语言生态习惯的实现。

配额优化:先定义约束,再求最优分配

在最后的配额实验中,论文使用两个 1.5B 模型、各 400B tokens 进行验证,其中包括 350B 代码和 50B FineWeb-Edu。基线将代码预算在七种语言之间均分,优化方案则在总预算不变的前提下重新分配各语言 token。[36,§6]

这一实验说明,​语言配额本身可以成为优化变量,而不是默认均匀采样。但它仍然是特定模型规模、数据池和预算下的受控结果,不能直接外推到任意多万亿 token 的训练。论文不同章节使用的规模范围和部分统计口径也并不完全一致,因此工程上更适合继承优化思路,而不是机械复制某组比例。

对于真正的低资源语言,更稳妥的决策顺序是:先统计 unique 数据量和重复率,再检查过滤器是否对某些语言产生系统性误杀;随后测量辅助语言的有向迁移和配对收益,最后在主力语言最低质量约束下优化预算。SQL、Assembly 以及其他更低资源或领域化语言,也不能直接从这七种通用编程语言的实验得到现成答案。[36,Limitations]

另一项《A More Data-Hungry Regime》也发现,在特定代码训练设置下,更高的 ​D/N​ 比例可能继续带来收益,但超过一定范围后性能仍会下降。[37] 因此, “代码更吃数据”描述的是最优预算可能向数据侧移动,而不是数据越多越好。 增加 token 的前提仍然是数据具有足够的信息增量,而不是用重复和噪声把配额填满。

十二、流程8:配比与时机:比例和阶段都需要单独验证

“代码应该占多少”看似是一个比例问题,实际上至少包含四个不同维度:通用模型中代码占多少、代码内部合成数据占多少、不同类型数据在什么阶段引入,以及各阶段最终累计曝光了多少次、对应什么学习率。把这些变量压缩成一句“代码放 30%”,通常会掩盖真正起作用的因素。

Cohere 的《To Code, or Not To Code?》在 470M 模型、200B-token 预算下测试了六档离散代码比例,并发现约 25% 代码时,其非代码综合目标表现较好;但代码专项任务往往偏好更高的代码占比。[38] 这说明代码比例本质上存在任务间权衡,而不能据此推出“25%”或“25–40%”是所有通用模型都适用的固定甜点。尤其该实验并没有覆盖连续比例空间。

比例之外,数据在什么时候出现也可能影响结果。《Midtraining Bridges Pretraining and Posttraining Distributions》v2 的相关代码实验表明,在 70M/160M 模型设置下,目标数据较早引入时可以承受更高权重;如果较晚引入,同样的高权重反而可能损害性能。[39] 但这一现象同时受到累计目标数据曝光量和学习率日程影响,因此不能直接外推成“大模型也存在完全相同的最佳时间窗”。

从 Seed-Coder、OpenCoder、Phi 以及这些受控实验来看,更稳妥的理解是:训练阶段划分首先是一种分布调度方式,而不是固定的三段式模板。 广泛、稳定、成本较低的筛选代码或改写数据可以较早参与训练;而稀缺、昂贵、强任务绑定的数据,例如工具调用轨迹、交互式修复记录或高成本验证样本,是否更适合后置,则需要单独实验确认。[5][7][14][23][39]

工程上,比复制某个比例更可靠的做法,是建立一个小规模二维对照:至少比较“较早/较晚引入”和“较低/较高权重”,同时固定后训练协议。最终不仅报告域内收益,还应同时记录通用能力回退、目标数据累计曝光量、学习率位置和总训练成本。否则,很难判断真正有效的是“引入时机”,还是某个条件只是让模型看到了更多目标数据。

十三、流程 9:去污染与评测:从样本隔离到评测协议控制

代码数据与公开评测之间存在多种潜在重叠路径。除题面和参考答案外,测试用例、题解、相关 issue、修复 patch、镜像仓库,以及由教师模型生成的改写或变体,都可能重新进入训练数据。因此,代码去污染不应只针对最终训练文件做一次字符串匹配,而应同时考虑数据来源、变换过程和评测协议。

语义重复与字面去污染的局限

《Soft Contamination Means Benchmarks Test Shallow Generalization》检查了 OLMo 3 的部分预训练数据和全部微调数据,并通过 embedding 检索候选,再进行语义标注。在其 top-100 候选检查设置下,77.5% 的 CodeForces 题目至少存在一个被判定为语义重复的样本。 [40,§3–4]

这里需要注意统计口径。77.5% 的分母是 benchmark 题目,而不是全部训练样本或全部重复样本,因此不能将其解释为“n-gram 方法漏掉了 77.5% 的污染”。同时,这一比例还受到候选召回范围、embedding 模型和语义标注标准的影响。

该结果更直接支持的结论是:仅依赖字面匹配不足以发现改写、翻译和语义等价形式的重叠。 但语义检索同样只是候选发现机制,而不是能够保证数据完全无污染的判定标准。

13.2 去污染需要覆盖数据生成的多个阶段

更稳妥的做法,是在不同阶段分别控制可能的泄漏来源。

  1. 来源阶段: 检查 benchmark 仓库及其 fork、镜像、题面、答案、测试和 patch,并将与评测直接相关的来源排除或单独标记。
  2. 变换阶段: 对原文、翻译、改写、回译题面、生成测试和衍生轨迹保留统一的 lineage,使同一来源的衍生样本在数据划分时保持一致。
  3. 最终训练集阶段: 再进行 hash、n-gram 和语义相似度检查,以发现经过拼接、重写或二次生成后重新出现的评测内容。
  4. 评测阶段: 固定 base model、harness、工具 schema、上下文长度、交互轮数、采样次数和测试可见性,避免把推理配置变化误认为模型本身的能力变化。

Clean-PR 同时采用仓库排除、源码哈希、patch 子序列匹配和 issue 相似度检查,正是因为不同方法覆盖的泄漏路径并不相同。[13,附录A.6–A.7] 但这些措施只能说明当前数据集进行了哪些去污染处理,并不能据此证明原始 base model 的历史预训练数据也完全不含相关内容。

时间留出需要明确时间戳的定义

时间切分可以降低公开 benchmark 长期暴露带来的风险,但软件仓库中的“时间”并不是单一变量。同一个任务可能同时包含 issue 创建时间、issue 最后修改时间、PR 创建与合并时间、commit 时间,以及数据实际被抓取或首次观测的时间。

SWE-bench 的构建过程表明,如果题面截断位置处理不当,后续评论中的修复信息可能被带入任务;SWE-rebench 则通过持续收集较新的 issue 和修复,降低固定评测集长期公开造成的暴露风险。[16][41]

因此,自建留出集最好同时保存多个时间戳。仅按 issue 创建时间切分,可能把多年后补充的答案仍归入早期数据;仅按仓库名称隔离,也无法处理 fork、文件复制和跨仓库镜像带来的内容重叠。

更可靠的方案通常需要组合使用内容级去污染、仓库或血缘级隔离,以及时间戳。同时,语义相似本身并不等价于泄题。常见算法和通用实现模式天然会在不同仓库中重复,因此语义检索更适合作为候选发现步骤,再结合来源和任务语义进行复核。

评测配置本身也必须版本化

pass@1、Exact Match、BLEU、验证 loss 和软件工程修复率衡量的是不同能力,不能直接横向替代。即使模型权重不变,增加采样次数、扩大上下文长度、使用更强的检索器,或者向模型暴露更多测试信息,都可能显著改变最终结果。[17][27][28]

因此,一个可比较的实验至少应报告:使用的 base model、训练数据版本、unique tokens 与累计训练 tokens、后训练设置、推理预算、评测切分以及具体 harness。对于 agent 或软件工程任务,还应记录工具接口、最大交互轮数和测试可见性。

换句话说,评测结果并不只由模型权重决定,而是由模型、数据、推理配置和评测协议共同决定。 如果这些条件没有被完整记录,不同实验之间的分数就很难进行严格比较。

十四、如果重新搭管线,我会按什么顺序投入?

第一步,先建立可追踪、可复现的基线。
首先明确任务范围与许可政策,冻结原始数据快照,并保存内容、路径、仓库与版本之间的映射关系。在此基础上,使用稳定 tokenizer、基础规则、精确去重和简单采样,跑通一套可复现的训练与评测流程。[5][30] 后续任何复杂模块,都应相对于这一基线衡量净收益。

第二步,优先消除明显冗余和数据实现问题。
先校准文件级近去重,检查跨来源、跨分区重复,分析异常大簇和最终样本的重复曝光,并统计不同语言的保留率。[6–9] 这些问题通常比高级语义去重更基础:如果分区、loader 或打包过程本身仍在重复数据,继续增加复杂过滤器很难得到可信结论。

第三步,再评估质量评分与过滤强度。
规则过滤、模型评分和随机基线应在尽量一致的来源与训练预算下比较,同时关注低资源语言和合法异常样本的误删情况。公开工作中的 10%、28% 等保留比例,只能说明对应数据源和目标下的实验选择,不能直接作为新项目的默认阈值。[5][10][11]

第四步,将结构化数据与合成数据拆开验证。
编辑重建、可执行任务、教师轨迹、仓库级上下文和 FIM 分别引入了不同监督信号。更稳妥的做法是一次控制一个主要变量,先确认单项增益,再研究组合效果。[13][18][19][35] 尤其当数据选择、蒸馏、mask 策略和后训练同时变化时,不能把最终提升全部归因于其中某一个模块。

第五步,在扩大训练规模之前,先扩大证据。
小模型和数据切片适合筛选方向,但去重收益、长尾覆盖和 scaling 行为仍需要更大规模实验确认。最终比较时,应明确区分​等训练 tokens、等训练计算量和端到端总成本,因为这三种口径回答的是不同问题。[8][19][37]

与其给出一组固定参数,更合理的是把公开实验结果作为参考点,并明确哪些量仍需要在本项目中重新验证:

决策可参考的公开实验本项目需要重新验证的量
近去重FineWeb 的词级 5-gram / 14×8;代码数据采用过不同配置分词方式、候选召回、复核精度、簇结构、最终重复曝光
文件与仓库组织OpenCoder 文件级对照;仓库 manifest 保留局部重复、版本一致性、依赖完整度、仓库级任务收益
质量评分Seed 的 1.3B 回归器、Stack-Edu 教育分类、MIRA 来源感知teacher 偏差、尾部误差、来源校准、可用数据量、真实增益
过滤强度Seed 预处理后约删除 10% 文件;Stack-Edu 约保留 28% tokens同预算随机基线、重复次数、能力覆盖、保留率敏感性
合成比例网页改写中约三分之一是已研究设置之一分母定义、生成器、难度、多样性、验证率、端到端成本
过程数据commit 编辑预测;Clean-PR 的 mid-training + SFT重建正确性、测试质量、检索误差、harness 匹配、污染
长上下文file-level + 位置适配、路径排序、依赖组织逐层对比有效监督量、相关内容密度、长短任务权衡、训练成本
FIMPSM/SPM 联合、单一排列、随机/AST/函数级 mask 均有实例格式兼容、FIM rate、mask 定义、光标分布、L2R 回退
多语言重复基线、辅助语言、平行配对、语言配额优化有向迁移、token 效率、主力语言下限、尺度稳定性
调度时机与权重联合实验,而非只看最终比例累计曝光、学习率位置、域内收益、通用能力回退
去污染内容、仓库、时间和合成 lineage 的多层控制候选复核、误杀/漏检、teacher/verifier 污染、新题泛化

论文之外的工程实践也有参考价值。例如 OpenCoder 的公开经验强调,规则阈值需要通过反复抽样检查校准,并优先在小模型上完成较多消融后再放大;其他预训练实践也反复指出,HTML 解析、数据格式和低 perplexity 的合成语料都可能产生与下游收益不一致的结果。[42] 这类材料更适合作为工程经验,而不能与独立受控实验等量看待:同一个结论被多次转述,并不会增加独立证据数量。

最后,成本比较也不应只看生成价格。更完整的口径至少包括:

$$ C_{\mathrm{total}}=C_{\mathrm{collect}}+C_{\mathrm{process}} +C_{\mathrm{generate}}+C_{\mathrm{verify}} +C_{\mathrm{train}}+C_{\mathrm{evaluate}}. $$

其中生成和验证成本都应包含失败重试,复用成本也只有在数据确实被后续多次使用时才适合摊销。每百万“生成 tokens”的单价较低,并不等价于每百万“去重后、验证通过、最终可用 tokens”的成本较低,更不能直接推出单位下游收益更低。[19][30]

因此,数据管线的投入顺序更适合遵循一个原则:先解决可观测、可复现和明显冗余,再逐步增加评分、结构、合成与复杂调度;每增加一层复杂度,都需要对应的受控证据说明它带来了什么额外收益。

结语:好管线不仅生产数据,也生产对数据的解释

回头看,我对代码预训练数据的理解,已经从“尽可能多地收集、尽可能彻底地清洗”,转向更关注一组更具体的问题:为什么要收这类数据,为什么要删掉另一类,哪些重复是有害的,哪些重复是必要曝光,以及最终为什么相信性能提升确实来自这些数据决策。

The Stack 三代说明,规模之外还需要考虑内容可得性、许可治理与产物质量;OpenCoder 和 FineWeb 表明,去重本身会改变数据分布;Seed-Coder、Stack-Edu 和 MIRA 说明,质量判断必须依赖目标与来源;Clean-PR 和 SWE 系列展示了从静态文本到可执行任务之间不同程度的重建与验证;SwallowCode、FIM 及其结构化变体则进一步表明,改写和数据组织能够提高有效监督,但同时也可能引入接口漂移、分布偏移和新的验证成本。[1–19][29][34][35]

这些工作并没有收敛出一套可以直接复制的统一配方。更有价值的是它们提供了一套分析框架:一项数据操作究竟补充了什么能力,改变了哪些变量,引入了什么成本,是否存在更简单的对照,以及最终评测是否仍与训练过程保持足够独立。

因此,“数据 + Infra”更适合被理解为一种研究与工程方法,而不是替代模型研究的口号:让数据来源、处理过程、训练暴露和评测协议都能够被追踪、复现和修正。训练系统负责把梯度计算出来,而数据工程真正需要回答的问题,是这些梯度是否来自我们想让模型学习的信号。

术语速查

术语本文中的含义
unique / consumed tokens独立语料中的token量 / 经采样重复后累计训练消耗
manifest / lineage数据清单与版本映射 / 原始、变换、合成和训练样本的血缘关系
SWHID平台无关的软件对象标识;不是许可凭证或无限下载保证
MinHash / LSH估计集合相似度的签名 / 高效召回可能相似对象的索引方法
Jaccard / shingle集合交并比 / 用于比较的连续片段,须说明字符、词或其他单位
rehydration去重后利用重复簇等信息重新分配训练重复权重
scorer / rubric质量评分模型 / 评分维度与标准;不等于功能正确性证明
round-trip verification编辑表示应用回旧代码后,能否精确重建目标版本
F2P / P2P / P2F指定测试的失败转通过 / 通过保持通过 / 通过转失败
test oracle决定输出或行为是否符合要求的判断依据,不只是测试执行器
CPT / mid-training / SFT持续预训练 / 基础与后训练之间的过渡训练 / 监督微调;需跟随论文定义
FIM / PSM / SPM中间填空数据变换 / 前缀-后缀-中间 / 后缀-前缀-中间
AST / 依赖图语法结构树 / 文件或程序对象之间的静态关系近似
RoPE / theta旋转位置编码 / 基频参数;调整参数不等于完成训练适配
EM / pass@1 / BLEU字符串精确匹配 / 单样本通过率 / 文本重叠指标,不能互换
百分点 / 相对提升25%−20%=5个百分点;(25−20)/20=25%相对提升

附录:整体流程路线与建议

如果从头搭一条流水线,按这个顺序做:

  1. 精确去重(内容哈希)
    去掉完全重复文件和镜像副本,先消除最明显的数据冗余。
  2. 文件级 MinHash 近去重
    识别轻微改写、格式变化、注释变化导致的近重复代码。
  3. 语言识别 + Tree-sitter 语法过滤 + License/PII
    保证代码语言正确、语法可解析,同时过滤许可风险和敏感信息。
  4. 训练质量打分器
    抽样约 20 万条让强模型打分,再训练轻量 scorer 扩展到全量数据。
  5. 过滤最低质量档,保留 70%–90%
    去掉明显低质量样本,同时避免过度清洗导致数据分布变窄。
  6. 按来源分四类(文件 / 仓库 / 演化 / 合成)
    将不同结构和用途的数据分桶,为后续采样和课程调度做准备。
  7. 三阶段数据调度,结构化数据后置
    先学基础代码能力,再学仓库上下文,最后引入演化和合成类复杂数据。
  8. 依赖图重建仓库顺序 + 结构感知 FIM
    按依赖关系组织仓库文件,并让 FIM 利用函数、文件和跨文件结构信息。
  9. n-gram 去污 + 语义去污
    同时检测表面文本重合和语义近似,降低 benchmark 泄漏风险。
  10. 时间切分内部留出集
    用未来时间段数据构建内部评测集,作为数据策略和 checkpoint 的最终裁决依据。
参数推荐取值依据
MinHash 参数5-gram、112 hash、14 band × 8 row;阈值按语言样本实测后定FineWeb 的性价比点;命中率在 0.75→0.85 之间从 77% 跳到 98.8%
去重粒度文件级;仓库结构在打包阶段重建OpenCoder:仓库级去重保留 3× token 但下游更差,且 68.4% 残留可再按文件级去重
超大簇处置N≥1000 的簇权而非保留FineWeb2 的簇大小理水化策略
质量过滤强度保守:只滤最差一档(10% 量级),不做“只留 1% 精品”Seed-Coder 滤 10%;代码最优 D/N 高于文本(2510.08702)
打分器强 LLM 标注 20 万级样本 → 蒸馏 1B 级打分器 → 全语料推理Seed-Coder(1.3B)、Stack-Edu(StarEncoder)
评分维度按数据源分别发现维度,而不是一套固定 rubricMIRA:半量 token 追平全量
FIM 格式 / 粒度 / 比例SPM;结构感知掩码(AST 子树或依赖图选函数);常规 0.5 → 持续预训练 0.1,别用 0.7+2207.14255、2506.00204、2607.12463
合成数据形态优先改写型;教科书型控制比例Meta(2510.01631):1/3 改写 + 2/3 真实提速 5–10×;教科书型 33% < 67%
合成数据比例≈30%(随模型规模与数据预算微调)Meta 的经验收敛值
代码在通用预训练中的占比25–40% 是反复出现的甜点;100% 伤世界知识Cohere(2408.10914);另有研究显示算术类峰值在 40–50%
mid-training 时机早引入 + 高权重;晚引入只能用低权重2510.14865:晚期加大配比无法补偿错过窗口
长上下文扩成本只需预训练预算的 0.1%–1%;重点是 RoPE θ 阶梯重标定Granite 4B token(0.1%);JetBrains 1B token(有效 72M)
去污8–13 gram 必做,补 embedding 语义检索,最好再建时间切分留出集n-gram 漏掉 78% 的 CodeForces 语义重复
去污 n-gram 长度8(s1 / open-r1)、10(Seed-Coder)、13(SmolLM / Llama 系)各家实践

参考文献与延伸阅读

以下按正文编号整理。论文结果均以所列版本为准;动态数据卡尤其应锁定revision。部分近作尚属预印本,引用表示可核读,不表示本文完成独立复现。

  1. Kocetkov et al. The Stack: 3 TB of permissively licensed source code. 2022,v1。§3、表3/5/6。论文
  2. BigCode. The Stack 数据卡。初始与后续版本、许可修订。数据卡
  3. Lozhkov et al. StarCoder 2 and The Stack v2: The Next Generation. 2024,核读v1,§2–4。正文
  4. BigCode. The Stack v2 数据卡。数据发布物与访问安排。数据卡
  5. Zhang et al. Seed-Coder: Let the Code Model Curate Data for Itself. 2025,v2,§2与附录A。正文
  6. HuggingFaceCode. The Stack v3. 2026。固定修订README · 同修订训练统计 · full说明
  7. Huang et al. OpenCoder: The Open Cookbook for Top-Tier Code Large Language Models. 2024/2025,v3;来源表亦核对v1原始HTML。正文
  8. Penedo et al. The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scale. 2024,v2,§3.4、附录E。正文 · 官方长文
  9. Penedo et al. FineWeb2: One Pipeline to Scale Them All. 2025,v1,§4.3–4.5。正文
  10. SmolLM2: When Smol Goes Big — Data-Centric Training of a Small Language Model. 2025,v1,表2、附录D。正文 · Stack-Edu
  11. MIRA: Mid-training Rubric Anchoring for Source-Aware Data Selection. 2026,v2,表1、附录A。预算/checkpoint文字存在不完全一致之处,正文只采用明确表格比较。正文
  12. Muennighoff et al. OctoPack: Instruction Tuning Code Large Language Models. 2023/2024。论文 · CommitPackFT官方卡
  13. Pull Requests as a Training Signal for Repo-Level Code Editing(Clean-PR). 2026,v2,表2–9、附录A。正文 · Microsoft Research发表页
  14. Gunasekar et al. Textbooks Are All You Need. 2023,v2,§2、§5。论文
  15. Training Software Engineering Agents and Verifiers with SWE-Gym. 2024/2025,v2,§3–4。正文
  16. SWE-rebench: An Automated Pipeline for Task Collection and Decontaminated Evaluation of Software Engineering Agents. 2025,v2。正文
  17. R2E-Gym: Procedural Environments and Hybrid Verifiers for Scaling Open-Weights SWE Agents. 2025,v1。正文
  18. SWE-Mirror: Scaling Issue-Resolving Datasets by Mirroring Issues Across Repositories. 2025,v1,§2–3、表6。PDF
  19. Rewriting Pre-Training Data Boosts LLM Performance in Math and Code(SwallowCode). 2025/2026,v4,§3、附录G/I。正文
  20. Demystifying Synthetic Data in LLM Pre-training: A Systematic Study of Scaling Laws, Benefits, and Pitfalls. arXiv记录为2025 v1,正文日期及比例网格有不一致;不据此采用精确最优比例。正文
  21. UnitCoder: Scalable Code Synthesis from Pre-training Corpora. EMNLP 2025,§3–4。正式论文
  22. KodCode: A Diverse, Challenging, and Verifiable Synthetic Dataset for Coding. 2025,v2,§2–3。正文
  23. Phi-4 Technical Report. 2024,表4–5、附录B。正文
  24. Shumailov et al. AI models collapse when trained on recursively generated data. Nature,2024。论文
  25. Is Model Collapse Inevitable? Breaking the Curse of Recursion by Accumulating Real and Synthetic Data. 2024,v2。正文
  26. Scaling Granite Code Models to 128K Context. 2024,v1,§2–3。正文
  27. On Pretraining for Project-Level Code Completion. 2025,v1,§3、表3–4。正文
  28. OctoLong: Mid-Training On Cross-Repository Code Contexts Enhances Long-Context Modeling. 2026,v1,§3–5、附录B/C。正文
  29. Bavarian et al. Efficient Training of Language Models to Fill in the Middle. 2022,v1,§3–5、§8。正文
  30. Hugging Face. DataTrove。仓库 · MinHash分阶段示例
  31. IBM / data-prep-kit. Repo Level Order Transform。本次核读dev分支,不作为稳定API承诺。说明
  32. GitHub Docs. Viewing and understanding files;Software Heritage软件标识说明。GitHub历史查看 · SWHID标准说明
  33. DeepSeek-Coder,2024,v2,§3.1.2;StarCoder,2023,v2,训练格式小节。DeepSeek-Coder · StarCoder
  34. Structure-Aware Fill-in-the-Middle Pretraining for Code. 2025,v1,§3、§5–7。正文
  35. Function-Aware Fill-in-the-Middle as Mid-Training for Coding Agent Foundation Models. 2026,v3,§2–3、§6。正文
  36. Scaling Laws for Code: Every Programming Language Matters. 2025,v1,§3–6、表3。部分迁移表和规模口径需谨慎解读。正文
  37. Scaling Laws for Code: A More Data-Hungry Regime. 2025/2026,v2,§3–4。正文
  38. To Code, or Not To Code? Exploring Impact of Code in Pre-training. 2024,v1,§3.3。正文
  39. Midtraining Bridges Pretraining and Posttraining Distributions. 2025/2026,v2,§5–6。正文
  40. Soft Contamination Means Benchmarks Test Shallow Generalization. 2026,v1,§3–4。正文
  41. Jimenez et al. SWE-bench: Can Language Models Resolve Real-World GitHub Issues? . 2023起始工作,附录A;SWE-smith: Scaling Data for Software Engineering Agents,2025,v2。SWE-bench · SWE-smith
  42. 社区实践,作为定性经验而非独立实验:crazycth《OpenCoder:顶尖代码大模型的开源实践全指南》、 《LLM Pretrain Data Project》;真中合欢《LLM实践–数据去重:Simhash&Minhash 原理分析&代码实现》;字节跳动Seed官方中文解读。OpenCoder分享 · 预训练实践 · 去重实现讨论 · Seed官方解读