数据构建深度解析:LLM 训练数据的艺术与科学

7815 字
39 分钟
数据构建深度解析:LLM 训练数据的艺术与科学

1. 引言:数据是 LLM 的灵魂#

1.1 数据决定模型上限#

在 LLM 领域,有一个被反复验证的铁律:

“Garbage in, garbage out.” — 数据的质量决定了模型能力的上限,训练只是无限逼近这个上限。

数据 vs 模型能力的相关性:
GPT-3 (300B tokens) → GPT-4 (?)
→ 能力跃升的核心原因之一是数据质量的提升
→ 不仅仅是参数规模的扩大
LLaMA 2 (2T tokens) vs LLaMA 3 (15T tokens)
→ LLaMA 3 用更多但更高质量的数据
→ 在更少参数下超越了 LLaMA 2
Phi-3 (3.8B 参数)
→ 仅用 3.3T tokens 训练
→ 超越大它 10 倍的模型
→ 秘诀:高质量"教科书级"数据

1.2 LLM 数据的三大类型#

LLM 训练涉及三类核心数据,它们的角色和构建方法截然不同:

┌─────────────────────────────────────────────────────────────────┐
│ LLM 训练数据的三种类型 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 类型 1: 预训练数据 (Pre-training Data) │
│ 用途: 学习语言模型的基础能力(语法、语义、世界知识) │
│ 规模: trillions of tokens(数万亿) │
│ 来源: 网页、书籍、代码、论文、百科等 │
│ 构建: 爬取 → 去重 → 质量过滤 → 格式转换 │
│ │
│ 类型 2: SFT 数据 (Supervised Fine-Tuning Data) │
│ 用途: 学习指令遵循、对话格式、特定任务能力 │
│ 规模: thousands to millions(数千到数百万) │
│ 来源: 人类标注、LLM 生成、公开数据集 │
│ 构建: 指令设计 → 回答生成 → 质量筛选 │
│ │
│ 类型 3: 偏好数据 (Preference Data) │
│ 用途: 学习人类偏好(RLHF/DPO/KTO 对齐) │
│ 规模: thousands to hundreds of thousands(数千到数十万) │
│ 来源: 人类标注、LLM 评判 │
│ 构建: 候选生成 → 偏好标注 → 质量过滤 │
│ │
└─────────────────────────────────────────────────────────────────┘

1.3 本系列文章关联#

文章关联
后训练深度解析数据在后训练流水线中的使用方式
偏好对齐深度解析偏好数据的具体应用
知识蒸馏深度解析蒸馏数据的特殊构建方法
DeepSeek-R1R1 的数据构建实践

2. 预训练数据构建#

2.1 数据来源#

预训练数据的来源决定了模型的知识面和能力边界:

class PretrainingDataSources:
"""
预训练数据来源及其特点
"""
SOURCES = {
# 网页数据:最大、最多样、但噪声最多
"web": {
"examples": ["CommonCrawl", "WebText", "CCNet", "C4"],
"size": "~trillions of tokens",
"pros": ["多样性高", "覆盖广", "成本相对低"],
"cons": ["噪声多", "隐私问题", "质量参差不齐"],
},
# 书籍:高质量、连贯、但覆盖有限
"books": {
"examples": ["BookCorpus", "Books3", "Gutenberg", "Libgen"],
"size": "~hundreds of billions",
"pros": ["质量高", "长程依赖", "结构化"],
"cons": ["版权问题", "覆盖有限", "可能过时"],
},
# 代码:GPT-4/Codex 能力的关键
"code": {
"examples": ["GitHub", "The Stack", "Python data"],
"size": "~hundreds of billions",
"pros": ["结构化", "逻辑性强", "可执行验证"],
"cons": ["语言有限", "注释质量差", "版权问题"],
},
# 学术论文:知识和推理能力
"papers": {
"examples": ["arXiv", "Semantic Scholar"],
"size": "~hundreds of billions",
"pros": ["知识密集", "推理严谨", "引用丰富"],
"cons": ["格式复杂", "数学公式多", "需要处理"],
},
# 百科:结构化知识
"encyclopedia": {
"examples": ["Wikipedia", "Wikidata"],
"size": "~billions",
"pros": ["知识准确", "结构化", "引用丰富"],
"cons": ["覆盖面有限", "可能有偏见"],
},
}

2.2 网页数据流水线:CCNet#

CommonCrawl 是预训练语料的最大来源,CCNet 是处理它的经典流水线:

class CCNetPipeline:
"""
CCNet: CommonCrawl Net
处理 CommonCrawl 网页数据的完整流水线
论文: Wenzek et al., 2020
"""
def __init__(self):
self.language = "en"
self.min_quality_score = 0.7
self.min_length = 100
def process_common_crawl(self, raw_warc_files):
"""
完整流水线:
1. 下载 CommonCrawl WARC 文件
2. 提取文本(Text Extraction)
3. 语言识别(Language Identification)
4. 质量过滤(Quality Filtering)
5. 去重(Deduplication)
"""
all_documents = []
for warc_file in tqdm(raw_warc_files):
# Step 1: 下载并解压 WARC 文件
warc_records = self.parse_warc(warc_file)
# Step 2: 文本提取
for record in warc_records:
text = self.extract_text(record)
# Step 3: 语言识别
if self.is_target_language(text, self.language):
all_documents.append(text)
# Step 4: 质量过滤
filtered = self.quality_filter(all_documents)
# Step 5: 去重
deduped = self.deduplicate(filtered)
return deduped
def extract_text(self, warc_record):
"""
从 HTML 中提取文本
使用 jusText 或类似的启发式提取器
移除导航栏、页脚、广告等噪音内容
"""
html = warc_record.content
# 方法 1: jusText
# 基于马尔可夫链的文本提取
# 区分"正文内容"和"模板内容"
# 方法 2: trafilatura
# 更准确的提取,保留表格和列表
# 方法 3: boilerplate removal
# 基于规则的噪音移除
text = trafilatura.extract(html)
return text
def is_target_language(self, text, target_lang):
"""
语言识别
使用 fastText 的 LID (Language Identification) 模型
在 Wikipedia 上预训练,支持 176 种语言
"""
# 加载预训练的 fastText 模型
lid_model = fasttext.load_model('lid.176.bin')
# 预测语言和置信度
predictions = lid_model.predict(text, k=1)
lang = predictions[0][0].replace('__label__', '')
confidence = predictions[1][0]
return lang == target_lang and confidence > 0.8
def quality_filter(self, documents):
"""
质量过滤
使用多个质量指标组合:
1. 语言模型困惑度(LM Perplexity)
2. 单词/字符比率
3. 特殊字符密度
4. 停用词比率
"""
scored_docs = []
for doc in documents:
score = 0.0
# 指标 1: 句子完整度
# 好的文档应该有完整的句子
sentences = sent_tokenize(doc)
complete_ratio = sum(1 for s in sentences if s.endswith(('.','!','?'))) / len(sentences)
score += 0.3 * complete_ratio
# 指标 2: 词/字符比率
# 合理范围:4-10 chars/word
words = doc.split()
if len(words) > 0:
avg_word_len = len(doc) / len(words)
if 3 < avg_word_len < 15:
score += 0.2
else:
score += 0.1 * (10 - abs(avg_word_len - 6)) / 10
# 指标 3: 停用词比率
stopwords = set(stopwords_list)
stopword_ratio = sum(1 for w in words if w.lower() in stopwords) / len(words)
if 0.3 < stopword_ratio < 0.7:
score += 0.2
# 指标 4: 重复度
# 高重复度可能是模板/垃圾内容
repeat_ratio = self.compute_repeat_ratio(doc)
if repeat_ratio < 0.2:
score += 0.3 * (1 - repeat_ratio)
if score >= self.min_quality_score:
scored_docs.append((score, doc))
# 按分数排序
scored_docs.sort(reverse=True)
return [doc for _, doc in scored_docs]
def compute_repeat_ratio(self, text, n=5):
"""
计算 n-gram 重复比率
重复比率 = 1 - (唯一 n-gram 数 / 总 n-gram 数)
"""
words = text.split()
if len(words) < n:
return 0.0
ngrams = [tuple(words[i:i+n]) for i in range(len(words)-n+1)]
unique_ngrams = len(set(ngrams))
total_ngrams = len(ngrams)
return 1 - unique_ngrams / total_ngrams

2.3 RefineWeb: 高质量网页数据#

RefineWeb(Faoorosh et al., 2023)提出了更精细的过滤策略:

class RefineWebPipeline:
"""
RefineWeb: Refined Web Dataset
相比 CCNet 的改进:
1. 更激进的模板过滤
2. 使用更强的质量分类器
3. 保留文档级去重
"""
def __init__(self):
self.quality_classifier = None # 用高质量数据训练的分类器
def build_quality_classifier(self, positive_samples, negative_samples):
"""
训练质量分类器
positive: Wikipedia, Books, 人工筛选的高质量网页
negative: 广告、导航栏、低质量网页
"""
from sklearn.linear_model import LogisticRegression
def extract_features(text):
"""提取质量相关特征"""
features = {}
# 词汇丰富度
words = text.split()
unique_words = set(words)
features['vocab_richness'] = len(unique_words) / (len(words) + 1)
# 平均句子长度
sentences = sent_tokenize(text)
features['avg_sent_len'] = np.mean([len(s.split()) for s in sentences])
# 标点符号密度
punct_count = sum(1 for c in text if c in '.,!?;:')
features['punct_density'] = punct_count / (len(text) + 1)
# 大写字母比率
upper_count = sum(1 for c in text if c.isupper())
features['upper_ratio'] = upper_count / (len(text) + 1)
# URL 密度(低质量内容 URL 多)
url_count = len(re.findall(r'http[s]?://', text))
features['url_density'] = url_count / (len(text) + 1)
return list(features.values())
# 训练
X_pos = [extract_features(s) for s in positive_samples]
X_neg = [extract_features(s) for s in negative_samples]
X = X_pos + X_neg
y = [1] * len(X_pos) + [0] * len(X_neg)
self.quality_classifier = LogisticRegression().fit(X, y)
def heuristic_filters(self, doc):
"""
启发式过滤器
RefineWeb 使用的 10 个启发式规则
"""
words = doc.split()
# 规则 1: 最小长度
if len(words) < 50:
return False
# 规则 2: 最大长度(避免文档过长)
if len(words) > 100000:
return False
# 规则 3: 最小平均词长
avg_word_len = len(doc) / len(words)
if avg_word_len < 2.5 or avg_word_len > 15:
return False
# 规则 4: 最大特殊字符密度
special_chars = sum(1 for c in doc if not c.isalnum() and not c.isspace())
if special_chars / len(doc) > 0.3:
return False
# 规则 5: 最小句子数
sentences = sent_tokenize(doc)
if len(sentences) < 3:
return False
# 规则 6: 检查"段落"结构
# 好的文档应该有多个段落
paragraphs = doc.split('\n\n')
if len(paragraphs) < 2:
return False
# 规则 7: 检查"锚文本"密度
# 锚文本(链接文字)过多可能是导航/列表页
anchor_ratio = doc.count('<a ') / (len(words) + 1)
if anchor_ratio > 0.3:
return False
# 规则 8: 检查"call to action"
cta_patterns = ['click here', 'sign up', 'subscribe', 'buy now', 'learn more']
if any(p in doc.lower() for p in cta_patterns):
return False
# 规则 9: 检查"contact us"
if 'contact' in doc.lower() and 'email' in doc.lower():
return False # 可能是联系页面
# 规则 10: 检查"terms of service"
if 'terms of service' in doc.lower() or 'privacy policy' in doc.lower():
return False # 法律页面
return True

2.4 去重策略#

去重是预训练数据处理中最关键的步骤之一:

class DeduplicationStrategies:
"""
多层次去重策略
"""
def exact_deduplication(self, documents):
"""
精确匹配去重(MinHash)
时间复杂度: O(n)
空间复杂度: O(n)
"""
from datasketch import MinHash, MinHashEncoder
minhashes = []
for doc in documents:
m = MinHash(num_perm=128)
for word in doc.split():
m.update(word.encode('utf8'))
minhashes.append(m)
# 编码并去重
encoder = MinHashEncoder(num_perm=128)
encoded = [encoder.encode(m) for m in minhashes]
unique_idx = []
seen = set()
for i, e in enumerate(encoded):
if e not in seen:
seen.add(e)
unique_idx.append(i)
return [documents[i] for i in unique_idx]
def near_deduplication(self, documents, threshold=0.8):
"""
近似去重(SimHash 或 MinHash Jaccard)
用于检测高度相似的文档
threshold: Jaccard 相似度阈值
"""
from datasketch import MinHash, MinHashLSH
# 构建 MinHash 索引
lsh = MinHashLSH(threshold=threshold, num_perm=128)
for i, doc in enumerate(documents):
m = MinHash(num_perm=128)
for word in doc.split():
m.update(word.encode('utf8'))
lsh.insert(f"doc_{i}", m)
# 查找并移除重复
unique_docs = []
duplicate_indices = set()
for i, doc in enumerate(documents):
if i in duplicate_indices:
continue
unique_docs.append(doc)
# 查找相似文档
m = MinHash(num_perm=128)
for word in doc.split():
m.update(word.encode('utf8'))
duplicates = lsh.query(m)
for dup_id in duplicates:
dup_idx = int(dup_id.split('_')[1])
if dup_idx != i:
duplicate_indices.add(dup_idx)
return unique_docs
def sentence_deduplication(self, text, min_occurrence=10):
"""
句子级去重
移除在整个语料中出现次数过多的句子
这些通常是模板文本或版权声明
"""
from collections import Counter
sentences = sent_tokenize(text)
# 统计句子出现次数
sentence_counts = Counter(sentences)
# 过滤出现过多的句子
filtered = [
s for s in sentences
if sentence_counts[s] <= min_occurrence
]
return ' '.join(filtered)
def document_level_deduplication(self, documents):
"""
文档级去重(基于内容哈希)
方法:
1. 提取文档的 k-mer
2. 计算 MinHash
3. 用 LSH 找相似文档
4. 保留最长/质量最高的版本
"""
from datasketch import MinHash, MinHashLSH
lsh = MinHashLSH(threshold=0.9, num_perm=256)
# 构建索引
indexed = []
for i, doc in enumerate(documents):
m = self._compute_minhash(doc)
key = f"doc_{i}"
lsh.insert(key, m)
indexed.append((i, doc, m))
# 聚类并保留代表
clusters = defaultdict(list)
for i, doc, m in indexed:
# 查找相似文档
candidates = lsh.query(m)
if candidates:
cluster_id = int(candidates[0].split('_')[1])
clusters[cluster_id].append((i, doc))
else:
clusters[i].append((i, doc))
# 从每个 cluster 选代表(最长/最高质量)
representatives = []
for cluster in clusters.values():
best = max(cluster, key=lambda x: len(x[1].split()))
representatives.append(best[1])
return representatives
def _compute_minhash(self, text, k=5):
"""
计算文本的 MinHash
"""
from datasketch import MinHash
words = text.split()
m = MinHash(num_perm=256)
for i in range(len(words) - k + 1):
kmer = ' '.join(words[i:i+k])
m.update(kmer.encode('utf8'))
return m

3. SFT 数据构建#

3.1 SFT 数据的核心要素#

SFT 数据与预训练数据有本质区别:它需要包含**指令(Input)和回答(Output)**的配对。

class SFTDataCore:
"""
SFT 数据的核心要素
"""
@dataclass
class SFTSample:
"""
SFT 样本的三个核心要素
"""
instruction: str # 指令/问题/任务描述
input: str # 可选的输入上下文
output: str # 期望的回答
def format(self, template="chatml"):
"""
格式化为训练格式
"""
if template == "chatml":
return f"<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n<|im_start|>user\n{self.instruction}\n{self.input}<|im_end|>\n<|im_start|>assistant\n{self.output}<|im_end|>"
elif template == "alpaca":
return f"Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.\n\n### Instruction:\n{self.instruction}\n\n### Input:\n{self.input}\n\n### Response:\n{self.output}"
elif template == "llama3":
return f"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nYou are a helpful assistant.<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\n{self.instruction}\n{self.input}<|eot_id|>\n<|start_header_id|>assistant<|end_header_id|>\n\n{self.output}<|eot_id|>"

3.2 指令模板设计#

指令模板的设计直接影响模型学到的能力:

class InstructionTemplates:
"""
指令模板设计
"""
TEMPLATES = {
# 开放式问答
"qa_open": [
"{instruction}",
"请回答以下问题:{instruction}",
"Question: {instruction}\nAnswer:",
],
# 带上下文的问答
"qa_context": [
"根据以下信息回答问题:\n{input}\n\n问题:{instruction}",
"Context: {input}\n\nQuestion: {instruction}\n\nAnswer:",
],
# 总结任务
"summarize": [
"请总结以下文本:\n{input}",
"Summarize this: {input}",
],
# 翻译任务
"translate": [
"请将以下文本翻译成{target_lang}\n{input}",
"Translate to {target_lang}: {input}",
],
# 代码任务
"code": [
"请用{language}编写代码:\n{instruction}",
"Write a {language} function that {instruction}",
],
# 数学任务
"math": [
"求解:{instruction}",
"Calculate: {instruction}",
"Given that {input}, {instruction}",
],
# 分析任务
"analysis": [
"分析以下内容:\n{input}",
"请分析{instruction},参考:\n{input}",
],
}
def generate_instruction_variants(self, base_instruction, num_variants=5):
"""
生成指令变体
使用 LLM 重写指令,增加多样性
"""
prompt = f"""
请将以下指令改写为 {num_variants} 种不同的表述方式。
保持原意,但改变措辞和句式。
原始指令:{base_instruction}
改写要求:
1. 使用不同的开头词
2. 使用不同的句式结构
3. 保持相同的任务要求
4. 不要改变任务的核心目标
"""
response = llm.generate(prompt)
variants = extract_variants(response)
return variants

3.3 LLM 生成 SFT 数据#

class LLMDataGenerator:
"""
使用 LLM 生成 SFT 数据
"""
def __init__(self, generator_model, judge_model=None):
self.generator = generator_model
self.judge = judge_model
def generate_from_prompts(self, prompts, task_type="general"):
"""
从提示生成 SFT 数据
"""
data = []
for prompt in tqdm(prompts):
response = self.generator.generate(prompt)
# 质量检查
if self.judge:
quality = self.judge.score(prompt, response)
if quality < 0.7:
continue
data.append({
"instruction": self.extract_instruction(prompt),
"input": self.extract_input(prompt),
"output": response,
"source": "llm_generated",
})
return data
def self_generate(self, model, instructions, num_samples_per_inst=1):
"""
Self-Generation: 用模型自己生成回答
典型流程:
1. 准备多样化的指令集
2. 用模型生成多个回答(不同 temperature)
3. 过滤低质量回答
4. 得到 (instruction, response) 对
"""
data = []
for instruction in tqdm(instructions):
for _ in range(num_samples_per_inst):
# 随机 temperature
temp = random.choice([0.5, 0.7, 0.9, 1.1])
response = model.generate(
instruction,
temperature=temp,
max_tokens=2048,
do_sample=True,
)
# 质量检查
if self._passes_quality_check(response):
data.append({
"instruction": instruction,
"input": "",
"output": response,
"temperature": temp,
})
return data
def _passes_quality_check(self, response):
"""
简单的质量检查
"""
# 长度检查
if len(response.split()) < 20:
return False
# 完整性检查
if not response.strip().endswith(('.', '!', '?', '"', "'")):
# 不完整可能表示截断
if len(response) < 200:
return False
# 重复检查
if self._has_excessive_repetition(response):
return False
return True
def _has_excessive_repetition(self, text, n=3):
"""
检查过度重复
"""
words = text.lower().split()
if len(words) < 10:
return False
# 检查连续 n 个词是否重复
for i in range(len(words) - n * 2):
window = ' '.join(words[i:i+n])
next_window = ' '.join(words[i+n:i+2*n])
if window == next_window:
return True
return False

3.4 人类标注流程#

class HumanAnnotationWorkflow:
"""
人类标注工作流
"""
def __init__(self, annotation_platform):
self.platform = annotation_platform
def setup_task(self, task_config):
"""
配置标注任务
"""
task = {
"name": task_config["name"],
"description": task_config["description"],
# 输入字段
"input_fields": [
{"name": "instruction", "type": "text", "required": True},
{"name": "context", "type": "text", "required": False},
],
# 输出字段
"output_fields": [
{"name": "response", "type": "textarea", "required": True},
{"name": "quality_score", "type": "rating", "min": 1, "max": 5},
{"name": "issues", "type": "multiselect",
"options": ["incomplete", "incorrect", "harmful", "off-topic"]},
],
# 质量控制
"qualification_requirements": [
{"type": "approval_rate", "threshold": 0.85},
{"type": "completed_tasks", "threshold": 100},
],
# 奖励设置
"reward": task_config.get("reward_per_task", 0.10),
}
return self.platform.create_task(task)
def annotate_instructions(self, instructions, num_workers=10):
"""
标注指令-回答对
典型流程:
1. 分发任务给标注者
2. 每个任务多人标注
3. 收集并合并结果
"""
# 分配任务
tasks = self._distribute_tasks(instructions, num_workers)
# 收集结果
all_results = []
for worker_id, worker_tasks in tasks.items():
results = self.platform.get_worker_results(worker_id)
all_results.extend(results)
# 合并重复任务(多人标注同一任务)
merged = self._merge_annotations(all_results)
# 过滤低质量标注
filtered = self._filter_by_agreement(merged)
return filtered
def _distribute_tasks(self, instructions, num_workers):
"""
分发任务,确保每个任务被多人标注
"""
import random
tasks_per_worker = len(instructions) // num_workers
tasks = {}
for i in range(num_workers):
start = i * tasks_per_worker
end = start + tasks_per_worker if i < num_workers - 1 else len(instructions)
tasks[f"worker_{i}"] = instructions[start:end]
return tasks
def _merge_annotations(self, annotations):
"""
合并同一任务的多个标注
策略:
- 如果多数一致,选择多数结果
- 如果一致,选择质量最高的
"""
from collections import defaultdict
by_instruction = defaultdict(list)
for ann in annotations:
key = ann["instruction"]
by_instruction[key].append(ann)
merged = []
for instruction, anns in by_instruction.items():
if len(anns) == 1:
merged.append(anns[0])
continue
# 检查一致性
responses = [a["response"] for a in anns]
response_counts = Counter(responses)
if response_counts.most_common(1)[0][1] >= len(anns) * 0.5:
# 多数一致,选择多数结果
best_response = response_counts.most_common(1)[0][0]
else:
# 不一致,选择质量最高的
best_ann = max(anns, key=lambda a: a["quality_score"])
best_response = best_ann["response"]
merged.append({
"instruction": instruction,
"output": best_response,
"agreement": response_counts.most_common(1)[0][1] / len(anns),
"num_annotations": len(anns),
})
return merged
def _filter_by_agreement(self, annotations, min_agreement=0.5):
"""
按一致性过滤
"""
return [a for a in annotations if a.get("agreement", 1.0) >= min_agreement]

4. 偏好数据构建#

4.1 偏好数据的格式#

偏好数据是对齐训练的核心,其基本格式为:

class PreferenceDataFormat:
"""
偏好数据的三种格式
"""
@dataclass
class PreferencePair:
"""
标准偏好对
"""
prompt: str
chosen: str # 被选中的回答
rejected: str # 被拒绝的回答
@dataclass
class PreferenceTriple:
"""
偏好三元组(包含多个候选)
"""
prompt: str
responses: List[str] # 候选回答列表
ranking: List[int] # 排序(0 = 最好)
@dataclass
class BinaryPreference:
"""
二元偏好(正/负样本)
"""
prompt: str
response: str
label: bool # True = desirable, False = undesirable

4.2 偏好标注流水线#

class PreferenceAnnotationPipeline:
"""
偏好标注流水线
"""
def __init__(self, annotation_platform, judge_model=None):
self.platform = annotation_platform
self.judge = judge_model
def generate_candidates(self, prompts, generator, num_candidates=4):
"""
为每个 prompt 生成多个候选回答
"""
candidates_data = []
for prompt in tqdm(prompts):
candidates = []
for temp in [0.3, 0.5, 0.7, 0.9]:
response = generator.generate(
prompt,
temperature=temp,
max_tokens=1024,
)
candidates.append(response)
candidates_data.append({
"prompt": prompt,
"candidates": candidates,
})
return candidates_data
def annotation_task(self, candidates_data, num_annotators=3):
"""
偏好标注任务
标注者需要:
1. 阅读 prompt 和多个候选回答
2. 选择最好的一个(或排序)
3. 标记理由(可选)
"""
task_config = {
"name": "Preference Annotation",
"instruction": """
请阅读以下问题及其多个回答,选择最好的一个。
评分标准:
- 准确性:回答是否正确
- 完整性:回答是否全面
- 清晰度:回答是否易于理解
- 有用性:回答是否有帮助
请为每个回答打分(1-5)并选出最佳。
""",
"input_fields": [
{"name": "prompt", "type": "display"}, # 只读
{"name": "candidate_1", "type": "display"},
{"name": "candidate_2", "type": "display"},
{"name": "candidate_3", "type": "display"},
{"name": "candidate_4", "type": "display"},
],
"output_fields": [
{"name": "scores", "type": "rating_group", "count": 4, "min": 1, "max": 5},
{"name": "best", "type": "select", "options": ["1", "2", "3", "4"]},
{"name": "reason", "type": "textarea"},
],
}
return task_config
def build_preference_pairs(self, annotations):
"""
从标注结果构建偏好对
策略:两两比较构建 pair
如果 A 得分 > B 得分,则 (prompt, A, B) 是一个正例
"""
pairs = []
for item in annotations:
prompt = item["prompt"]
candidates = item["candidates"]
scores = item["scores"] # [score_1, score_2, ...]
# 构建所有两两比较
for i in range(len(candidates)):
for j in range(i+1, len(candidates)):
if scores[i] > scores[j]:
pairs.append({
"prompt": prompt,
"chosen": candidates[i],
"rejected": candidates[j],
})
elif scores[j] > scores[i]:
pairs.append({
"prompt": prompt,
"chosen": candidates[j],
"rejected": candidates[i],
})
return pairs

4.3 LLM-as-Judge#

使用 LLM 作为评判者可以大幅降低标注成本:

class LLMAsJudge:
"""
LLM-as-Judge: 用 LLM 进行偏好判断
"""
def __init__(self, judge_model):
self.judge = judge_model
def judge_preference(self, prompt, response_a, response_b):
"""
判断哪个回答更好
"""
judge_prompt = f"""
You are an expert evaluator. Given a question and two responses,
determine which response is better.
Question: {prompt}
Response A:
{response_a}
Response B:
{response_b}
Consider:
- Accuracy and correctness
- Completeness and thoroughness
- Clarity and readability
- Helpfulness and relevance
Output your decision in JSON format:
{{"winner": "A" or "B", "reason": "brief explanation"}}
"""
result = self.judge.generate(judge_prompt)
parsed = json.loads(result)
return parsed
def score_and_rank(self, prompt, responses):
"""
给多个回答打分并排序
"""
judge_prompt = f"""
Evaluate and rank the following responses to the question.
Question: {prompt}
{''.join([f'Response {i+1}: {r}\n\n' for i, r in enumerate(responses)])}
Score each response (1-10) and provide rankings.
Output in JSON format:
{{
"rankings": [3, 1, 2, 4], # Response indices in rank order
"scores": [7.5, 9.0, 8.5, 6.0],
"justifications": ["..."]
}}
"""
result = self.judge.generate(judge_prompt)
parsed = json.loads(result)
return parsed
def batch_judge_preferences(self, data, batch_size=8):
"""
批量判断偏好(提高效率)
"""
results = []
for i in range(0, len(data), batch_size):
batch = data[i:i+batch_size]
# 构建批量评判 prompt
batch_prompt = self._build_batch_prompt(batch)
batch_result = self.judge.generate(batch_prompt)
# 解析结果
parsed = self._parse_batch_result(batch_result, len(batch))
results.extend(parsed)
return results
def _build_batch_prompt(self, batch):
"""
构建批量评判 prompt
"""
prompt = "Evaluate the following preference pairs:\n\n"
for i, item in enumerate(batch):
prompt += f"--- Pair {i+1} ---\n"
prompt += f"Question: {item['prompt']}\n"
prompt += f"Response A: {item['response_a']}\n"
prompt += f"Response B: {item['response_b']}\n\n"
prompt += "\nOutput JSON array of results:\n"
prompt += '[{"pair_id": 1, "winner": "A", "reason": "..."}, ...]'
return prompt

4.4 偏好数据质量控制#

class PreferenceDataQualityControl:
"""
偏好数据质量控制
"""
def __init__(self):
self.agreement_threshold = 0.6
self.min_annotators = 3
def compute_inter_annotator_agreement(self, annotations):
"""
计算标注者一致性
方法:Fleiss' Kappa 或 Krippendorff's Alpha
"""
import numpy as np
from scipy import stats
# 将评分转换为矩阵
# 行:样本
# 列:标注者
n_samples = len(set(a["sample_id"] for a in annotations))
n_annotators = self.min_annotators
ratings = np.zeros((n_samples, n_annotators))
for ann in annotations:
sid = ann["sample_id"]
aid = ann["annotator_id"]
score = ann["score"]
ratings[sid, aid] = score
# 计算 Fleiss' Kappa
kappa = self._fleiss_kappa(ratings)
return kappa
def _fleiss_kappa(self, ratings):
"""
Fleiss' Kappa 计算
"""
n_subjects, n_raters = ratings.shape
# 观测一致性
observed = self._compute_observed_agreement(ratings)
# 期望一致性(随机)
expected = self._compute_expected_agreement(ratings)
kappa = (observed - expected) / (1 - expected)
return kappa
def filter_by_consistency(self, preference_pairs):
"""
过滤不一致的偏好
检测方法:
1. A > B, B > C, 但 A < C(循环偏好)
2. 同一 prompt 多次标注结果差异大
"""
from collections import defaultdict
# 按 prompt 分组
by_prompt = defaultdict(list)
for pair in preference_pairs:
by_prompt[pair["prompt"]].append(pair)
filtered = []
for prompt, pairs in by_prompt.items():
# 检查是否有循环偏好
if self._has_cycle_preference(pairs):
continue # 跳过不一致的数据
# 检查标注一致性
consistency = self._compute_pairwise_consistency(pairs)
if consistency >= self.agreement_threshold:
filtered.extend(pairs)
return filtered
def _has_cycle_preference(self, pairs):
"""
检测循环偏好
"""
# 如果有 A > B > C > A 的循环,返回 True
# 简化为:检查是否有传递性冲突
responses = {}
for pair in pairs:
chosen = pair["chosen"]
rejected = pair["rejected"]
if chosen not in responses:
responses[chosen] = set()
if rejected not in responses:
responses[rejected] = set()
# chosen 优于 rejected
responses[chosen].add(rejected)
# 检查传递性
for a in responses:
for b in responses[a]:
for c in responses[b]:
if a in responses[c]:
# a > b > c > a,存在循环
return True
return False
def filter_by_length_ratio(self, pairs, max_ratio=5.0):
"""
过滤长度差异过大的偏好
理由:长度偏差可能影响人类判断
"""
filtered = []
for pair in pairs:
len_chosen = len(pair["chosen"].split())
len_rejected = len(pair["rejected"].split())
ratio = max(len_chosen, len_rejected) / (min(len_chosen, len_rejected) + 1)
if ratio <= max_ratio:
filtered.append(pair)
return filtered

5. 测试集设计#

5.1 测试集的核心原则#

class TestSetDesign:
"""
测试集设计的核心原则
"""
PRINCIPLES = {
# 1. 不泄漏训练数据
"no_leakage": """
测试集不应该出现在训练数据中。
检查方法:
1. 用 MinHash 检测与训练数据的重叠
2. 过滤重叠度 > 5% 的样本
3. 定期审计测试集
""",
# 2. 代表性
"representativeness": """
测试集应该代表模型将面对的真实分布。
检查方法:
1. 与训练数据分布对比
2. 覆盖所有能力维度
3. 考虑真实使用场景
""",
# 3. 难度分布
"difficulty_distribution": """
测试集应该有合理的难度分布。
建议分布:
- Easy: 30%
- Medium: 50%
- Hard: 20%
理由:
- 太难:无法区分模型能力
- 太简单:无法区分模型能力
""",
# 4. 抗污染
"contamination_resistance": """
测试集应该能抵抗数据污染。
方法:
1. 使用闭卷测试(模型未见过的场景)
2. 使用需要推理的问题
3. 定期更新测试集
""",
}

5.2 能力维度覆盖#

class CapabilityCoverage:
"""
能力维度的测试覆盖
"""
CAPABILITIES = {
# 知识与问答
"knowledge": {
"description": "知识问答和事实准确性",
"tests": [
"Factual QA (TriviaQA, NaturalQuestions)",
"World Knowledge (MMLU subjects)",
"Reading Comprehension (SQuAD, HotpotQA)",
],
"difficulty_levels": ["factual", "reasoning", "multi-hop"],
},
# 推理能力
"reasoning": {
"description": "逻辑和数学推理",
"tests": [
"Math (GSM8K, MATH, MATH-500)",
"Logic (LogiQA, ReClor)",
"Commonsense (HellaSwag, PIQA)",
"Code (HumanEval, MBPP, LiveCodeBench)",
],
"difficulty_levels": ["single-step", "multi-step", "adversarial"],
},
# 代码能力
"coding": {
"description": "代码生成和理解",
"tests": [
"Code Generation (HumanEval, MBPP)",
"Code Completion (Fill-in-the-middle)",
"Code Explanation (Code Understanding)",
"Code Debugging (Bug Detection)",
],
"difficulty_levels": ["simple", "medium", "complex"],
},
# 对齐质量
"alignment": {
"description": "指令遵循和偏好对齐",
"tests": [
"Instruction Following (IFEval)",
"Helpfulness (MT-Bench, AlpacaEval)",
"Safety (ToxiGen, HarmBench)",
"Honesty (TruthfulQA)",
],
"difficulty_levels": ["basic", "complex", "adversarial"],
},
# 多语言能力
"multilingual": {
"description": "多语言理解和生成",
"tests": [
"Translation (WMT, Flores)",
"Multilingual QA (XQuAD, MLQA)",
"Language Understanding (XGLUE)",
],
"difficulty_levels": ["high-resource", "low-resource"],
},
}

5.3 测试集去污染#

class ContaminationChecker:
"""
测试集污染检测
"""
def __init__(self, training_data):
self.training_minhash = self._build_minhash_index(training_data)
def _build_minhash_index(self, documents):
"""
为训练数据构建 MinHash 索引
"""
from datasketch import MinHash, MinHashLSH
lsh = MinHashLSH(threshold=0.5, num_perm=128)
for i, doc in enumerate(documents):
m = MinHash(num_perm=128)
for word in doc.split()[:1000]: # 只用前1000词
m.update(word.encode('utf8'))
lsh.insert(f"doc_{i}", m)
return lsh
def check_contamination(self, test_sample):
"""
检查测试样本是否与训练数据重叠
"""
m = MinHash(num_perm=128)
for word in test_sample.split()[:1000]:
m.update(word.encode('utf8'))
candidates = self.training_minhash.query(m)
return len(candidates) > 0, len(candidates)
def compute_overlap_score(self, test_sample):
"""
计算与训练数据的重叠分数
"""
test_words = set(test_sample.lower().split())
# 采样检查(完整检查太慢)
overlap_count = 0
sample_size = min(len(test_words), 1000)
sampled_words = random.sample(list(test_words), sample_size)
for word in sampled_words:
if self._word_in_training(word):
overlap_count += 1
return overlap_count / sample_size
def filter_contaminated(self, test_set, overlap_threshold=0.1):
"""
过滤被污染的测试样本
"""
clean_set = []
contaminated_count = 0
for sample in tqdm(test_set):
overlap = self.compute_overlap_score(sample["text"])
if overlap < overlap_threshold:
clean_set.append(sample)
else:
contaminated_count += 1
print(f"Filtered {contaminated_count}/{len(test_set)} contaminated samples")
return clean_set

6. Scaling Law 与数据配比#

6.1 数据 Scaling Law#

class DataScalingLaw:
"""
数据 Scaling Law
核心发现(Hoffmann et al., 2022):
计算最优:C ≈ 20 * N
其中 C 是 tokens 数量,N 是参数量
Chinchilla 结论:
模型大小和数据量应该同比 scaling
"""
def compute_optimal_tokens(self, model_params, total_compute):
"""
Chinchilla 最优:20 tokens per parameter
LLaMA 2 (70B) 应该用 1.4T tokens
实际用了 2T,已经超过 Chinchilla 最优
"""
optimal_tokens = 20 * model_params
return optimal_tokens
def compute_optimal_model_size(self, total_tokens, total_compute):
"""
给定 tokens 和 compute,估算最优模型大小
"""
# total_compute ∝ N * T
# 最优点:N ≈ C / 20
optimal_params = total_compute / 20
return optimal_params
def predict_performance(self, model_params, num_tokens, quality_factor=1.0):
"""
预测模型性能(基于 scaling law)
损失 ~ (C / (N * T))^(alpha)
其中:
- C 是计算量
- N 是参数量
- T 是 tokens
- alpha ≈ 0.5
"""
alpha = 0.5
quality_factor = quality_factor # 数据质量因子
compute = model_params * num_tokens
# 简化的损失预测
loss = (1.0 / compute) ** alpha * quality_factor
# 转换为困惑度
perplexity = np.exp(loss)
return perplexity

6.2 数据配比策略#

class DataMixingStrategy:
"""
数据配比策略
"""
def compute_optimal_mix(
self,
domain_importance,
domain_difficulty,
current_performance,
target_capabilities,
):
"""
计算最优数据配比
考虑因素:
1. 领域重要性(任务占比)
2. 领域难度(需要多少数据才能掌握)
3. 当前性能(短板优先)
4. 目标能力(重点发展的方向)
"""
mix = {}
for domain, importance in domain_importance.items():
difficulty = domain_difficulty.get(domain, 1.0)
current = current_performance.get(domain, 0.0)
target = target_capabilities.get(domain, 1.0)
# 基础权重 = 重要性
weight = importance
# 难度调整:越难需要越多数据
weight *= (1 + 0.5 * difficulty)
# 性能调整:短板优先
gap = target - current
weight *= (1 + gap)
mix[domain] = weight
# 归一化
total = sum(mix.values())
mix = {k: v / total for k, v in mix.items()}
return mix
def expert_mixture(self, num_experts=8, expert_domain_size=100e9):
"""
专家混合数据配比
DeepSeek-V2 的做法:
每个"专家"专注一个领域
"""
mix = {}
domains = [
"code", # 代码
"math", # 数学
"reasoning", # 逻辑推理
"science", # 自然科学
" humanities", # 人文
"social", # 社会科学
"news", # 新闻
"web", # 网页
]
# 基于能力目标分配
base_mix = {
"code": 0.20, # 代码是关键
"math": 0.15, # 数学推理
"reasoning": 0.15, # 逻辑推理
"science": 0.15, # 自然科学
"humanities": 0.10,
"social": 0.10,
"news": 0.05,
"web": 0.10,
}
return base_mix
def progressive_mix(self, training_steps, total_steps):
"""
渐进式数据混合
训练过程中动态调整数据配比
"""
progress = training_steps / total_steps
if progress < 0.3:
# 早期:更多通用数据
return {
"general": 0.8,
"domain": 0.2,
}
elif progress < 0.7:
# 中期:增加领域数据
return {
"general": 0.5,
"domain": 0.5,
}
else:
# 后期:领域数据为主
return {
"general": 0.2,
"domain": 0.8,
}

6.3 数据质量 vs 数量#

class QualityVsQuantity:
"""
数据质量 vs 数量的权衡
"""
def analyze_tradeoff(self):
"""
分析质量与数量的权衡
关键发现:
1. Phi-3: 3.3T 高质量 tokens ≈ 15T 混合质量 tokens
2. 数据质量提升 2x ≈ 数据量提升 10x
3. "Textbook quality" 数据最有效
"""
return {
"phi_insight": {
"description": "Phi-3 的数据策略",
"high_quality_tokens": 3.3e12,
"equivalent_mixed_tokens": 15e12,
"quality_premium": "5x",
"key": "Textbook-level quality",
},
"scaling_curve": {
"x": "Data quality (normalized)",
"y": "Model performance (normalized)",
"shape": "log-linear",
"slope": 0.5, # 质量翻倍 → 性能提升 2^0.5 ≈ 1.4x
},
"practical_recommendation": {
"high_budget": "Maximize quality, moderate quantity",
"medium_budget": "Balance quality and quantity",
"low_budget": "Prioritize quality in key domains",
},
}

7. 数据清洗工具链#

7.1 完整清洗流水线#

class DataCleaningPipeline:
"""
完整数据清洗流水线
"""
def __init__(self):
self.stages = [
"deduplication",
"language_filter",
"quality_filter",
"safety_filter",
"format_filter",
]
def clean(self, documents, config=None):
"""
完整清洗流水线
"""
if config is None:
config = self.default_config()
current = documents
stats = {"input": len(documents)}
for stage in self.stages:
current = getattr(self, f"stage_{stage}")(current, config[stage])
stats[stage] = len(current)
stats["output"] = len(current)
stats["retention_rate"] = len(current) / stats["input"]
return current, stats
def default_config(self):
"""
默认配置
"""
return {
"deduplication": {
"threshold": 0.85, # MinHash Jaccard 阈值
"method": "minhash",
},
"language_filter": {
"target_languages": ["en", "zh", "es", "fr", "de", "ja", "ko"],
"min_confidence": 0.8,
},
"quality_filter": {
"min_length": 100,
"max_length": 100000,
"min_sentence_count": 3,
"quality_threshold": 0.5,
},
"safety_filter": {
"toxicity_threshold": 0.5,
"pii_removal": True,
},
"format_filter": {
"remove_html": True,
"remove_urls": False,
"normalize_whitespace": True,
},
}
def stage_deduplication(self, documents, config):
"""
去重阶段
"""
return self.near_deduplication(documents, threshold=config["threshold"])
def stage_language_filter(self, documents, config):
"""
语言过滤阶段
"""
from fasttext import load_model
lid_model = load_model('lid.176.bin')
filtered = []
for doc in documents:
predictions = lid_model.predict(doc, k=1)
lang = predictions[0][0].replace('__label__', '')
confidence = predictions[1][0]
if lang in config["target_languages"] and confidence >= config["min_confidence"]:
filtered.append(doc)
return filtered
def stage_quality_filter(self, documents, config):
"""
质量过滤阶段
"""
filtered = []
for doc in documents:
words = doc.split()
# 长度检查
if len(words) < config["min_length"]:
continue
if len(words) > config["max_length"]:
continue
# 句子数检查
sentences = sent_tokenize(doc)
if len(sentences) < config["min_sentence_count"]:
continue
# 质量评分
quality = self.compute_quality_score(doc)
if quality < config["quality_threshold"]:
continue
filtered.append(doc)
return filtered
def stage_safety_filter(self, documents, config):
"""
安全过滤阶段
"""
# 简化实现
toxic_patterns = [
"hate speech patterns",
"violent content patterns",
]
filtered = []
for doc in documents:
# 检查毒性
toxicity_score = self.estimate_toxicity(doc)
if toxicity_score > config["toxicity_threshold"]:
continue
# PII 移除
if config.get("pii_removal", False):
doc = self.remove_pii(doc)
filtered.append(doc)
return filtered
def stage_format_filter(self, documents, config):
"""
格式过滤阶段
"""
cleaned = []
for doc in documents:
if config.get("remove_html", True):
doc = self.remove_html_tags(doc)
if config.get("remove_urls", True):
doc = re.sub(r'http[s]?://\S+', '', doc)
if config.get("normalize_whitespace", True):
doc = re.sub(r'\s+', ' ', doc)
cleaned.append(doc.strip())
return cleaned

8. 主流数据集汇总#

8.1 预训练数据集#

数据集规模来源特点
CommonCrawl~数十 TB网页最大、噪声多
The Pile825 GB22 个来源混合多样、学术导向
RedPajama1.2TC4 + Reddit + Wikipedia + etc.开源完整
RefineWeb500B网页高质量
Dolma3T多种来源最新、高质量
FineWeb15T网页高质量过滤
Cosmopedia25BSynthetic高质量教科书级

8.2 SFT 数据集#

数据集规模来源特点
FLAN1.8M62 任务多任务指令微调
Alpaca52KLLM 生成简单、便宜
Vicuna70KLLM 对话多轮对话
WizardLM180KLLM 进化复杂指令
ShareGPT~150K用户共享真实对话
OpenOrca~1MLLM 生成CoT 推理

8.3 偏好数据集#

数据集规模来源特点
HH-RLHF160K人类标注Helpfulness/Harmlessness
SHP385KReddit 投票人类偏好
PKU-Alignment340K人类标注安全对齐
Anthropic HH42K人类标注对话偏好
UltraFeedback64KLLM 评判高质量

9. 核心公式汇总#

9.1 MinHash 去重#

hmin(S)=minsSh(s)h_{\min}(S) = \min_{s \in S} h(s)

其中 h(s)h(s) 是元素 ss 的哈希函数,MinHash 是多个哈希函数的集合。

9.2 Jaccard 相似度#

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

9.3 质量评分(简化)#

Q(d)=αC(d)+βL(d)+γR(d)Q(d) = \alpha \cdot C(d) + \beta \cdot L(d) + \gamma \cdot R(d)

其中 CC 是完整性、LL 是词汇丰富度、RR 是重复度。

9.4 Chinchilla Scaling Law#

L(N)(NcN)αN+(DcD)αDL(N) \approx \left(\frac{N_c}{N}\right)^{\alpha_N} + \left(\frac{D_c}{D}\right)^{\alpha_D}

其中 NN 是参数量,DD 是数据量,LL 是损失。


10. 总结#

10.1 数据构建的核心原则#

┌─────────────────────────────────────────────────────────────┐
│ 数据构建的五大核心原则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 质量第一 │
│ → 高质量 3.3T tokens > 低质量 15T tokens │
│ → Textbooks are all you need │
│ → 投资在质量过滤上有最高的 ROI │
│ │
│ 2. 去重不可忽视 │
│ → 去重可移除 20-40% 的重复数据 │
│ → MinHash 是工业级去重的标准方法 │
│ → 文档级 + 句子级去重组合使用 │
│ │
│ 3. 多样性很重要 │
│ → 单一来源的数据会导致能力偏差 │
│ → 平衡不同领域、风格、难度的数据 │
│ → 渐进式调整数据配比 │
│ │
│ 4. 测试集要独立 │
│ → 严格防止训练数据泄漏测试集 │
│ → 定期审计和更新测试集 │
│ → 使用闭卷测试验证真实能力 │
│ │
│ 5. 迭代改进 │
│ → 训练实验 → 分析失败案例 → 针对性补充数据 │
│ → 数据构建是一个持续的过程 │
│ → 不要期望一次就做到完美 │
│ │
└─────────────────────────────────────────────────────────────┘

10.2 方法选择指南#

数据构建方法选择:
预训练数据:
→ 质量优先:RefineWeb 流水线 > CCNet
→ 开源首选:RedPajama-Data > 从零爬取
→ 大规模:FineWeb / Dolma
SFT 数据:
→ 资源充足:人类标注
→ 资源有限:LLM 生成 + 质量过滤
→ 最佳平衡:混合(50% 人工 + 50% LLM)
偏好数据:
→ LLM-as-Judge 是降低成本的关键
→ 多标注者一致性 > 标注数量
→ 偏好对质量比数量更重要
推荐阅读
  1. CCNet(Wenzek et al., 2020)—— 网页数据处理流水线
  2. RefineWeb(Faoorosh et al., 2023)—— 高质量网页数据构建
  3. The Pile(Gao et al., 2020)—— 多样化预训练语料
  4. Phi-3 数据(Microsoft, 2024)—— Textbooks are all you need
  5. HH-RLHF(Anthropic, 2022)—— 偏好数据标注
  6. LLM-as-Judge(Zheng et al., 2023)—— LLM 评判方法

参考资料#

  1. Wenzek, G., et al. (2020). “CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Data.” LREC.
  2. Faoorosh, G., et al. (2023). “RefineWeb: A Recipe for Efficient Data Cleaning.” arXiv.
  3. Gao, L., et al. (2020). “The Pile: An 800GB Dataset of Diverse Text for Language Modeling.” arXiv.
  4. Penedo, G., et al. (2023). “The RefinedWeb Dataset for Falcon LLM.” arXiv.
  5. Soldaini, L., et al. (2024). “Dolma: An Open Corpus of 3 Trillion Tokens for Language Model Pretraining.” arXiv.
  6. Labrak, Y., et al. (2024). “FineWeb: 15T tokens of high-quality web data.” arXiv.
  7. Azeret, A., et al. (2024). “Cosmopedia: Synthetic Data for Education.” arXiv.
  8. Taori, R., et al. (2023). “Alpaca: A Strong, Replicable Instruction-Following Model.” Stanford CRFM.
  9. Peng, B., et al. (2023). “Vicuna: An Open-S chatbot Impressing GPT-4 with 90%* ChatGPT Quality.” LMSYS.
  10. Xu, C., et al. (2023). “WizardLM: Empowering Large Language Models to Follow Complex Instructions.” ICLR.
  11. Bai, Y., et al. (2022). “Training a Helpful and Harmless Assistant with Reinforcement Learning from Human Feedback.” arXiv.
  12. Zheng, L., et al. (2023). “Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena.” NeurIPS.
  13. Hoffmann, J., et al. (2022). “Training Compute-Optimal Large Language Models.” NeurIPS.
  14. Touvron, H., et al. (2023). “LLaMA: Open and Efficient Foundation Language Models.” Meta AI.
  15. Team, G., et al. (2024). “Phi-3 Technical Report.” Microsoft.

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

数据构建深度解析:LLM 训练数据的艺术与科学
https://aiattnstudio.link/posts/data-construction/
作者
Federico
发布于
2026-07-16
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author

Federico

AI Research Lab

Hello, I'm Federico.

关于实验室 / About
公告

欢迎来到Federico的个人博客

分类
标签
站点统计
57文章
7分类
404标签