从网络构建微调数据集:从URLs到JSONL

一个好的微调90%依赖于数据集。这是从原始URLs到清洁JSONL的流程——大规模获取、去重、许可过滤,以及训练者实际期望的聊天格式。

微调的质量取决于你提供的数据,而微调中最难的部分几乎从来不是训练过程,而是构建一个干净的数据集。网络是这种数据最丰富的来源,但原始页面是混乱的、重复的、未标记的且法律上不均衡。本指南是从URLs到训练就绪JSONL的流程:你实际需要多少数据,如何大规模获取,如何清理和去重,如何处理许可,以及如何将其格式化为训练者期望的聊天结构。假设你正在从公共网络内容构建一个指令或聊天微调。

你实际上需要多少数据?

从现实的目标开始,这样你就不会过度或不足构建。一个产生合理结果的微调的实际最低限度是大约100行;对于稳固的性能,你通常需要超过1,000行。更多通常有帮助,但前提是它是干净的——一千个标记良好的例子胜过一万个嘈杂的例子。作为规模参考,经典的Alpaca数据集是52,000个指令/输出对,通过提示一个更强的模型生成。如果你使用一个大型模型生成合成例子,至少用十个手写例子来初始化它,以便它在生成更多之前学习你想要的确切结构和语气。

获取:从爬取到清洁markdown

在获取阶段的目标是清洁文本,而不是原始HTML。一个微调行需要页面的实质内容——文章、文档、问答——而不是导航栏、cookie横幅和广告标记,这些会污染一个天真的爬取。因此,爬取你的目标页面并在摄取时将其转换为markdown,这样可以在保留结构如标题和列表的同时去除样板。在任何实际的体量下,你都会遇到速率限制和IP封锁,因此通过一个旋转池路由爬取。一个Scraper API可以直接返回markdown,一次调用即可完成清洁输出和抵抗封锁的双重任务,这就是为什么我们在我们的为LLMs提供新鲜网络数据指南中涵盖它。

# Sketch: crawl target URLs to clean markdown, ready for shaping into rows.
import requests

API = "https://api.quantumproxies.io/scrape"   # returns markdown, handles rotation

def fetch_markdown(url):
    r = requests.get(API, params={"url": url, "format": "markdown"},
                     headers={"Authorization": "Bearer YOUR_KEY"}, timeout=60)
    return r.json()["markdown"]

docs = [fetch_markdown(u) for u in seed_urls]   # clean text, no boilerplate
从URLs到微调数据集的流程图:从源到清洁markdown,清理和去重,格式化为JSONL消息,然后数据集卡片和训练/评估拆分
模型只会看到你的数据集,因此每一个去除垃圾的阶段都直接改善微调。

训练者期望的JSONL格式

大多数现代微调工具默认使用对话式JSONL格式:每行一个JSON对象,每个对象都有一个messages数组,包含角色/内容对,其中角色是systemuserassistant,用户/助手轮流交替。这是Hugging Face和OpenAI风格的训练者摄取的聊天格式。较旧的指令数据集使用三字段形状(instructioninputoutput)——适合单轮监督微调——也存在多轮对话格式,但它们可以干净地转换为消息形状。选择一个目标格式并将所有内容标准化为该格式。

// One training example per line (.jsonl). Chat / messages format:
{"messages":[
  {"role":"system","content":"You classify support tickets by urgency."},
  {"role":"user","content":"My payment failed three times and the event is tomorrow."},
  {"role":"assistant","content":"high"}
]}
{"messages":[
  {"role":"system","content":"You classify support tickets by urgency."},
  {"role":"user","content":"How do I change my avatar?"},
  {"role":"assistant","content":"low"}
]}

将格式与训练目标匹配:原始文本用于持续预训练,指令加输出或多轮聊天用于监督微调,偏好方法的排序响应。如果你正在构建一个推理微调,保留问题和答案,但重写答案以包含你希望模型学习的思维链步骤。

清理:质量的决定因素

这是决定你结果的阶段,主要是乏味的过滤。永远不要假设网络来源或模型生成的行是正确的——检查它们。反复出现的失败模式是具体的,值得按名称检查:

一个好的习惯是保留清理前和清理后的JSONL,以便你可以衡量你去除了什么。并在类别之间平衡集合——一个过度代表的类别会教模型过度预测它。

去重和许可

网络数据充满了重复——联合文章、镜像文档、样板段落——重复悄悄地通过过度加权重复的内容损害微调。做两次遍历:通过对规范化文本进行哈希来进行精确匹配去重,以捕捉相同的行,然后进行近重复检测(如MinHash的相似性或分片技术)以捕捉精确哈希错过的改写副本。在许可方面,要有意识:并非所有公开的内容都可以自由使用。跟踪每个文档的来源和许可,过滤掉那些条款禁止训练使用的内容,并优先选择具有明确重用权限的来源。记录来源在爬取时比在混合后重构便宜得多。

为LLMs获取清洁的网络数据

合并、卡片和拆分

当你从多个来源提取时,将它们全部标准化为一种格式,并在训练前合并为一个统一的数据集——在组合集上进行一次干净的微调胜过在每个来源上顺序微调,这往往会侵蚀模型早期学到的东西。然后写一个数据集卡片:一个简短的记录,说明数据来自哪里,如何清理,其大小和标签分布,其许可,以及任何已知的限制。这使得数据集在几个月后可重现和可审计。最后,保留一个从未训练过的评估拆分,以便你可以诚实地衡量微调,而不是在模型记住的数据上评分。如果你正在为检索系统而不是微调提供数据,我们的RAG管道指南涵盖了同一问题的刷新方面。

显示微调数据集大小的统计面板:最低100行,最佳1000行以上,合成生成的10个种子例子,52000个Alpaca行
大约100行以下,微调几乎学不到东西;超过1,000个干净行,质量胜过数量。

常见问题解答

我需要多少行来微调一个LLM?

大约100行是合理结果的实际最低限度,超过1,000是稳固性能的好目标。更多通常有帮助,但前提是数据保持干净——一个较小、标记良好的集合胜过一个大的嘈杂集合。对于合成生成,至少用十个手写例子来初始化生成器,以便它首先学习你的确切格式。

微调数据应该是什么格式?

JSONL——每行一个JSON对象。大多数现代训练器默认使用带有messages数组的对话格式,包含系统/用户/助手角色-内容对。较旧的指令数据集使用指令/输入/输出字段。根据你的训练目标选择一个目标格式,并在训练前将每个来源标准化为该格式。

如何清理用于微调的爬取数据集?

将页面转换为markdown以去除样板,然后手动过滤常见的失败:标签不一致、偏离目标的答案、错误标记的行,以及剩余的导航或cookie文本。用精确哈希和近重复遍历去重,平衡类别,并保留原始和清理后的版本,以便你可以衡量你去除了什么。

我可以用任何网络内容来训练模型吗?

不是自动的——公开并不意味着可以自由使用。有些内容带有禁止训练使用的条款,个人数据有其自身的规则。在收集时跟踪每个文档的来源和许可,过滤掉任何条款不允许训练的内容,并优先选择明确许可的来源。这是一般信息,而非法律建议;对于商业数据集,请咨询法律顾问。

从网络构建微调数据集是一个过滤管道:获取清洁的markdown,将其塑造成训练者期望的消息格式,严格去重和标签检查,过滤许可,并记录结果。获取大约一千个干净行并保留一个诚实的评估拆分,这样你就可以将你的训练预算花在信号而不是噪音上。

使用QuantumProxies的网络数据构建你的数据集