简介:这份文档围绕ChatGPT技术的训练数据收集与标注方法展开,面向自然语言处理入门者、AI产品从业者及对大模型训练流程感兴趣的学习者,帮助读者理解高质量对话数据从何而来、如何标注与迭代优化。资源包共1个docx文件,约37KB,内容以文字讲解为主,结构清晰,便于快速通读与查阅。文档系统梳理了数据收集、数据标注与迭代调优三大环节:数据收集部分介绍Web爬虫获取对话文本及数据过滤思路;数据标注部分涵盖人工标注、标注指导与标注质量控制,涉及分类、实体识别、意图识别等具体任务;迭代调优部分说明如何通过持续对话评估提升模型鲁棒性与性能。文末附有知识点归纳,方便读者把握重点。目前已有81人学习,适合作为了解ChatGPT训练数据工程全流程的入门参考。
1. 从一份文档拆起:ChatGPT 训练数据到底怎么收、怎么标
很多人第一次接触大模型训练,注意力全在模型结构和算力上,觉得数据就是「爬一堆文本喂进去」。真到动手做对话数据集才发现,最耗时间的恰恰是数据收集与标注这一环。这份《ChatGPT 技术的训练数据收集与标注方法》文档,讲的就是 OpenAI 在构建对话训练集时的完整链路:Web 爬虫采集对话文本、启发式规则加人工审核做数据过滤、聘请标注员做分类与实体识别、用标注规范和示例统一口径、再用重复标注和争议仲裁控制质量,最后通过持续对话评估做迭代调优。它适合两类人:一类是想自己搭对话数据集、做指令微调或 RLHF 数据准备的工程师;另一类是数据标注团队的管理者,需要一套能落地的标注规范和质量控制流程。文档本身是方法层面的梳理,不含代码,所以下面我会把它拆成可复现的工程步骤,该补的参数、该避的坑一并说清。
2. 数据收集与过滤:从爬取到可训练语料的工程链路
2.1 为什么 Web 爬虫仍是对话语料的主力来源
对话模型的语料需求有两个硬指标:覆盖广、场景杂。单一来源的语料,比如只从客服工单里抽,主题会高度集中,模型遇到闲聊、追问、纠错这类场景就露怯。Web 爬虫的价值在于它能一次性覆盖论坛问答、博客评论、百科讨论页等多种对话形态,天然带来主题和语气的多样性。文档里提到 OpenAI 团队把 Web 爬虫作为有效数据来源,逻辑就在这里。
但「有效」不等于「直接可用」。原始爬取结果里混着导航栏文本、广告、重复模板、乱码,直接拿去训练,模型学到的就是噪声。所以采集链路必须分成两段:抓取和清洗。抓取阶段关注覆盖率和去重,清洗阶段关注质量和格式统一。
常见做法是先用广度优先策略抓取种子页面,再按域名和路径做去重。抓取频率要控制,单域名并发别超过 2,否则容易被限流甚至封 IP,这是血泪经验。抓下来的原始 HTML 先落盘存档,不要边抓边清洗,否则一旦清洗规则写错,原始数据就没了后悔药。
import hashlib import re from urllib.parse import urlparse # 抓取阶段的去重与初步过滤 seen_hashes = set() def normalize_url(url): """去掉 URL 中的追踪参数,避免同一页面被重复抓取""" parsed = urlparse(url) # 只保留 scheme + netloc + path,丢弃 query 和 fragment return f"{parsed.scheme}://{parsed.netloc}{parsed.path}" def is_duplicate(text): """基于内容哈希做精确去重,防止模板页反复入库""" h = hashlib.md5(text.encode("utf-8")).hexdigest() if h in seen_hashes: return True seen_hashes.add(h) return False def rough_clean(html): """粗清洗:去标签、压空白,保留段落结构""" text = re.sub(r"<script.*?</script>", "", html, flags=re.S) text = re.sub(r"<style.*?</style>", "", text, flags=re.S) text = re.sub(r"<[^>]+>", " ", text) text = re.sub(r"[ \t]+", " ", text) text = re.sub(r"\n{3,}", "\n\n", text) return text.strip()这段代码解决三个问题:URL 归一化避免同一页面因参数不同被重复抓取;内容哈希做精确去重,模板页和转载页会被拦下;粗清洗把 HTML 转成带段落结构的纯文本。参数上,seen_hashes用集合存内存,百万级以内没问题,再大就要换成布隆过滤器或落库。rough_clean里的正则顺序不能反,先删 script 和 style 再删标签,否则脚本内容会被当成正文留下来。
2.2 启发式规则过滤:把低质量语料挡在训练集外
粗清洗之后,语料还是「能读但未必能用」。文档里强调 OpenAI 用启发式规则加人工审核做过滤,启发式规则的作用是低成本筛掉明显不合格的样本,把人工审核的精力留给边界样本。
我一般会设这几类规则:长度阈值、语言置信度、符号噪声比、重复 n-gram 比例。长度太短的对话没有上下文价值,太长且无换行的多半是拼接垃圾。语言置信度用轻量分类器或字符集统计都行,中文语料里混进大段乱码要直接丢。符号噪声比指非字母数字字符占比,超过阈值说明是代码块或表格残留。重复 n-gram 比例高,说明是模板或刷屏内容。
import re from collections import Counter def ngram_repeat_ratio(text, n=5): """计算重复 n-gram 占比,识别模板化或刷屏文本""" tokens = text.split() if len(tokens) < n: return 1.0 ngrams = [tuple(tokens[i:i+n]) for i in range(len(tokens)-n+1)] counter = Counter(ngrams) repeated = sum(c for c in counter.values() if c > 1) return repeated / len(ngrams) def symbol_noise_ratio(text): """非字母数字字符占比,过高说明是代码或表格残留""" if not text: return 1.0 noise = len(re.findall(r"[^\w\s\u4e00-\u9fff]", text)) return noise / len(text) def heuristic_filter(text, min_len=20, max_len=8000, max_noise=0.35, max_repeat=0.3): """组合过滤:任一条件不满足即丢弃""" if len(text) < min_len or len(text) > max_len: return False if symbol_noise_ratio(text) > max_noise: return False if ngram_repeat_ratio(text) > max_repeat: return False return True参数说明:min_len=20是经验值,低于这个长度的对话基本没有训练价值;max_len=8000防止超长拼接文本拖慢后续处理;max_noise=0.35对中文语料偏宽松,因为中文标点也算非字母数字,如果语料以英文为主可以降到 0.2;max_repeat=0.3是重复 n-gram 的上限,模板页通常远超这个值。这几个阈值没有绝对标准,建议先在小批量样本上跑一遍,看丢弃率和留存样本的观感再调。
提示:启发式规则只做「粗筛」,不要指望它替代人工审核。规则太严会误杀正常口语化表达,太松又起不到过滤作用,边界样本必须留给人工判断。
2.3 人工审核环节怎么组织才不失控
启发式规则跑完,剩下的样本进入人工审核。文档里提到 OpenAI 用人工审核过滤不符合要求的数据,这一步的组织方式直接决定成本和一致性。常见做法是抽样审核加全量抽检:对规则边界附近的样本全量看,对明显合格的样本按比例抽检。
审核界面要给审核员三个明确选项:通过、丢弃、存疑。存疑样本单独进队列,由第二个人复核,避免单人判断偏差。审核标准要写成可操作的条目,比如「包含明显广告或引流信息的丢弃」「包含个人隐私信息的丢弃」「对话轮次少于 2 的丢弃」,而不是「质量差的丢弃」这种没法执行的描述。
审核吞吐量要监控。如果某个审核员每小时处理量远高于平均,多半是没认真看;远低于平均,可能是标准理解有偏差。这两个方向都要及时介入。
3. 数据标注:从标注规范到质量控制的可执行流程
3.1 标注任务怎么拆:分类、实体识别与意图识别
文档里把标注工作拆成分类、实体识别、意图识别几类,这个拆法对应的是对话模型需要理解的不同层面。分类解决「这句话属于什么类型」,比如是提问、回答、追问还是纠错;实体识别解决「这句话里提到了什么」,比如人名、时间、地点、产品名;意图识别解决「用户想干什么」,比如查询、下单、投诉、闲聊。
拆任务的原则是:一个标注任务只让标注员做一个判断维度。让同一个人同时标分类和意图,出错率会明显上升,因为两个判断会互相干扰。正确做法是把任务串行化,先标分类,再在分类结果上标意图,每步都有独立的质检。
标注格式建议用 JSONL,每行一条样本,字段固定。这样后续转训练格式时不用再解析嵌套结构。
{"id": "s001", "text": "帮我查一下明天的天气", "category": "提问", "intent": "查询", "entities": [{"type": "时间", "value": "明天"}]} {"id": "s002", "text": "这个功能上周还能用,现在报错了", "category": "反馈", "intent": "投诉", "entities": [{"type": "时间", "value": "上周"}]}字段说明:id用于追溯和去重;text是原始对话文本;category是粗分类;intent是细粒度意图;entities是实体列表,每个实体带类型和值。这个结构的好处是分类和意图可以独立统计分布,发现某类样本过少时能针对性补数据。
3.2 标注规范与培训:让一百个人标出一致的结果
文档里特别强调标注指导和培训,这是被很多团队低估的环节。标注一致性差,后面做质量控制就是无源之水。规范文档要包含三部分:任务定义、判断标准、边界示例。
任务定义说清「标什么」,判断标准说清「怎么判」,边界示例说清「拿不准时看哪个」。边界示例是最有价值的部分,要覆盖容易混淆的场景。比如「帮我查天气」和「天气怎么样」,前者是明确的查询指令,后者更像闲聊式提问,如果意图体系里两者都算查询,就要在示例里说明;如果算不同意图,更要说清区别。
培训不能只发文档。常见做法是先让标注员做一批测试题,测试题里埋入已知答案的边界样本,通过率低于阈值的不进入正式标注。正式标注开始后,前 200 条全量复核,稳定后再转为抽检。这个流程能挡住大部分理解偏差。
3.3 标注质量控制:重复标注与争议仲裁
文档里提到 OpenAI 选择一小部分数据重复标注,与标准答案比对来评估准确性,争议情况讨论达成一致。这套机制的核心是「用可测量的方式发现偏差」。
重复标注的比例一般设在 5% 到 10%。太低发现不了问题,太高成本吃不消。重复标注的样本要随机抽取,不能只抽简单样本,否则一致性指标会虚高。一致性用 Cohen's Kappa 或简单一致率都行,分类任务看一致率,实体识别看边界和类型是否都匹配。
from sklearn.metrics import cohen_kappa_score def check_agreement(labels_a, labels_b): """计算两名标注员的一致性,labels 为同顺序的标签列表""" kappa = cohen_kappa_score(labels_a, labels_b) # Kappa 低于 0.6 说明一致性不足,需要重新培训或修订规范 if kappa < 0.6: return {"kappa": kappa, "status": "需介入"} return {"kappa": kappa, "status": "可接受"}参数说明:cohen_kappa_score适用于两名标注员、类别互斥的场景。Kappa 低于 0.6 是常见的介入阈值,低于 0.4 说明规范本身有问题,不是标注员的问题。争议样本不要直接丢,要进仲裁队列,由资深标注员或任务负责人裁决,裁决结果反哺规范文档,形成闭环。
注意:质量控制指标要按任务分别统计。分类任务一致性高,不代表实体识别一致性也高。混在一起看会掩盖问题。
4. 迭代调优:用对话评估反推数据缺口
4.1 评估集怎么建才有诊断价值
文档里提到通过不断与模型对话、评估回复来发现问题,这个环节的前提是有一个能诊断问题的评估集。评估集不能只放「标准问答对」,那样只能测出模型会不会答,测不出哪里不会。
我一般会按场景分层建评估集:事实问答、多轮追问、指令遵循、拒答边界、格式要求。每层放几十到上百条,覆盖典型和边界。评估时记录模型回复的问题类型,比如事实错误、答非所问、格式不符、过度拒答。这些错误类型直接对应数据缺口:事实错误多,说明知识类语料不足;格式不符多,说明指令微调数据里格式样本少。
评估集要冻结,不能边评边改。改了就失去纵向可比性。新增场景另建新评估集,老评估集保留用于回归测试。
4.2 从评估结果反推标注需求
评估发现的问题要能映射回数据生产。比如模型在多轮追问里频繁丢失上下文,说明训练数据里多轮对话样本少,或者标注时没有标出上下文依赖关系。这时候就要补多轮样本,并在标注规范里增加「上下文指代」标注项。
再比如模型对某些意图识别不准,回去看标注数据分布,多半是那类意图样本量太少,或者标注边界模糊导致标签噪声大。前者补数据,后者修规范重标。这个反推过程要形成固定流程:评估发现问题、定位错误类型、映射数据缺口、补数据或修规范、重新训练、回归评估。
4.3 迭代节奏与版本管理
迭代调优不是无限循环,要有节奏。常见做法是每轮迭代锁定一个主要问题,比如这轮专攻多轮上下文,下轮专攻格式遵循。一轮里改太多变量,出了问题说不清是哪个改动导致的。
数据版本要管理。每轮训练用的数据集打版本号,记录这版数据相比上版增删了什么、标注规范改了什么。模型版本和数据版本对应,出问题时能回溯。没有版本管理,迭代几轮后就是一笔糊涂账,这是很多团队踩过的坑。
5. 避坑与排查:数据链路里最容易翻车的五个点
5.1 爬取数据没存档,清洗规则写错后无法回滚
现象:清洗脚本上线后发现误删了大量正常样本,想重跑但原始 HTML 已经被覆盖或丢弃。 原因:抓取和清洗耦合在一起,边抓边清,原始数据没有独立存档。 解决:抓取阶段只做落盘和 URL 去重,原始 HTML 按域名分目录存压缩包。清洗脚本读存档、写新目录,永远不修改原始数据。清洗规则改多少版都能重跑。
5.2 启发式过滤阈值拍脑袋定,丢弃率失控
现象:过滤后语料只剩原始量的百分之几,或者几乎没丢但训练效果差。 原因:阈值没有基于实际样本分布校准,直接抄了别处的参数。 解决:先抽一万条样本,统计长度、噪声比、重复率的分布,按分位数定阈值。比如长度取 5% 分位和 95% 分位作为上下限,噪声比取 90% 分位。定完在小批量上验证丢弃率和留存质量,再全量跑。
5.3 标注规范太抽象,标注员各标各的
现象:重复标注一致性低,仲裁争议多,返工率高。 原因:规范里写的是「质量差的丢弃」「意图不明确的标其他」这类没法执行的描述。 解决:每条标准都要有可判断的条件和反例。把争议样本整理成边界示例集,新标注员先做示例集测试,通过再上岗。规范文档随仲裁结果持续更新,标注员能看到版本变化。
5.4 质量控制只统计整体一致性,掩盖单任务问题
现象:整体一致率看着不错,但某类意图的标注噪声很大,训练后该类意图识别效果差。 原因:一致性指标没有按任务和类别拆分统计。 解决:分类、实体、意图分别算一致性,每个大类下再按子类看分布。某子类样本少或一致性低,单独处理,不要混在整体指标里。
5.5 评估集和训练集重叠,指标虚高
现象:评估指标很好,上线后实际对话效果差。 原因:评估样本混进了训练数据,或者评估集和训练集来自同一批未去重的语料。 解决:评估集独立采集、独立标注、冻结存档。训练前用哈希比对评估集和训练集,重叠样本必须剔除。评估集不参与任何训练和调参。
6. 进阶技巧:把标注成本压下来又不牺牲质量
数据标注是重人力环节,成本控制是绕不开的。我试过几种做法,效果比较稳的是「主动学习加预标注」。先用一小批人工标注数据训一个轻量分类器,让它对未标注样本预测,按置信度排序,优先把低置信度样本送人工标注。高置信度样本先不标,等模型迭代后再看是否需要补。这样能把人工标注量压到全量的三到五成,且优先覆盖模型最不确定的样本。
预标注是另一个手段。用已有模型对样本做初步标注,人工只做修正。修正比从头标快,但要注意预标注的偏差会传导,所以预标注结果必须经过抽检,确认偏差在可接受范围再用。抽检发现某类样本预标注错误率高,该类就退回纯人工。
验证标注质量不能只看一致性。一致性高但都错的情况也存在,比如规范本身有系统性偏差。所以还要做「黄金样本」校验:在标注流里随机插入已知正确答案的样本,看标注员通过率。黄金样本比例控制在 2% 到 5%,太高会被标注员识别出来,太低起不到监控作用。
最后说一个我自己的习惯。每轮数据生产结束后,我会抽 50 条最终训练样本,从头到尾走一遍:看它怎么被爬取、怎么过滤、怎么标注、怎么进训练集。这条链路走通,心里才有底。有一次就是靠这个习惯发现某批样本在过滤阶段被误标为合格,实际是模板页残留,及时拦下避免了一轮无效训练。从那以后我每次数据版本发布前都强制走一遍抽样回溯,希望这个习惯也能帮到你。
本文还有配套的精品资源,点击获取