想象你是一家新餐厅的主厨。餐厅要推出菜单,但你不打算花大价钱雇几十个厨师没日没夜地试菜。你手里只有几张家传的经典菜谱,于是你把它们交给二厨,叮嘱一句“照这个风格,再变出几百道菜”。二厨依葫芦画瓢,一下子端出一大批新菜;你请来试吃官,把炒糊的、发霉的、重复的菜全部扔掉;最后再让几位星级大厨把其中几道菜“升级”成工序更复杂的创意料理。这就是今天要讲的两条合成数据路线——Self-Instruct 和 Evol-Instruct 在做的事。它们都在想办法让大模型自己“变出”高质量的训练数据,帮模型变得更强、更聪明。
对 AI 从业者来说,掌握合成数据生成两大路线,意味着能用更低成本造出高质量训练集、精准提升模型能力,是数据工程与模型微调岗位的核心技能。
目录
可视化演示
动态演示大模型合成数据生成两大路线对的核心机制,通过基础/核心/应用/扩展四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
大模型合成数据生成两大路线对:合成数据 合成数据生成动机与Self-I 种子指令自举生成的核心流程 核心机制可视化 大模型合成数据生成两大路线对整体架构与关键组件
种子指令自举:一道菜变一桌菜
餐厅要推出新菜单,最省力的办法是什么?不是让厨师凭空发明,而是翻出仓库里那几张家传菜谱。大厨对二厨说:“照这个菜谱的格式,把红烧肉换成红烧鱼,把清蒸换成干锅,再变出几十个版本。”二厨脑子转得飞快,一会儿就端出几十道新菜。这就是 Self-Instruct 的核心直觉——用模型自己“照着样子写新指令”,只需要少量人工种子。
Self-Instruct(Wang et al., 2022)正是这样工作的:先人工撰写约 175 条种子指令,覆盖问答、写作、编程等常见任务;然后把种子指令喂给大模型,让它生成更多同类指令。接着让模型为每条新指令补上输入和输出,构成完整的训练样本;新样本混入指令池,下一轮继续生成。这个“用模型自己的输出去训练它自己”的过程,就叫自举。
回到厨房的比喻:家传菜谱就是种子指令,二厨就是语言模型,一轮轮“照格式出新菜”就是自举。只要种子本身风格够典型,模型就能源源不断地变出风格统一但内容各异的新菜。这也是为什么几百条种子就能撑起几万条训练数据的原因。
- 更新后的数据集\(\mathcal{D}_{t+1}\) 代表新一轮完成后,指令池里已经累积的全部数据。
- 上一轮的数据集\(\mathcal{D}_t\) 是当前已经拥有的旧数据,它们是继续扩展的基础。
- 当前种子指令集合\(\mathcal{S}_t\) 中装着第 \(t\) 轮被当作“样例”的种子指令。
- 模型生成新样本\(f_{\theta}(s)\) 表示大模型根据单条种子指令 \(s\) 生成的候选数据,\(\theta\) 是模型参数。
- 并集扩张\(\cup\) 把所有新生成的样本并入旧数据,形成更大的数据集,供下一轮使用。
质量过滤:试吃官的严格品控
批量生产菜品时,二厨手一抖可能把盐放成糖,火一大可能把菜炒糊。如果这些菜直接端给顾客,餐厅口碑就砸了。所以餐厅里必须有试吃官——他们用手摸、用鼻闻、用嘴尝,把不合格的批次拦在厨房里。Self-Instruct 的数据同样需要这样的“试吃官”来把关。
在自举生成之后,研究者会对每一条新样本做三重检查。第一重是规则过滤:长度太短的、包含乱码或敏感词的、缺少必要格式的,直接剔除。第二重是模型过滤:用另一个经过训练的语言模型给指令打分,判断它“像不像一条人类会问的问题”。第三重是配对完整性检查:指令、输入、输出三者必须齐全且能对得上,任何一环为空都不行。
试吃官不会放走任何一道坏菜,过滤也不会让任何一条残缺样本混进数据集。经过这层品控,模型吃到的“训练餐”才干净卫生,不至于被垃圾数据带偏。记住:过滤不是越狠越好,而是要把确实有问题的样本挑出去。
- 保留信号\(\mathbb{1}_{\text{keep}}(x)\) 是指示函数,值为 1 表示保留,为 0 表示丢弃。
- 规则评分阈值\(r(x) \ge \tau_r\) 表示规则过滤器的打分必须超过预设阈值 \(\tau_r\)。
- 模型评分阈值\(m(x) \ge \tau_m\) 表示另一个模型对指令质量打的分也要达标。
- 输入输出非空\(x_{\text{in}}, x_{\text{out}} \neq \varnothing\) 确保指令的输入和输出都不是空值。
- 且关系乘积三个指示函数相乘,只有全部等于 1 时整体才等于 1,表达“缺一不可”。
多样性去重:菜单不重样的秘密
你有没有遇到过这种菜单?翻开前五页,全是“番茄炒蛋”“西红柿炒鸡蛋”“番茄炒鸡蛋(微辣版)”——虽然名字略有不同,菜的本质几乎一模一样。顾客翻两页就没了胃口。模型也一样:如果训练数据里全是近义词重复的指令,它学到的东西会非常单一,遇到真正多样的提问就傻眼。因此,菜单需要一位“策划”来去掉同质化的菜品。
Self-Instruct 使用相似度计算来做去重。最常用的指标是 ROUGE-L,它衡量两条指令在“最长公共子序列”意义上的重叠程度。流程是:新指令先和已保留的指令逐一比较,如果和任何一条的相似度都低于阈值,就收下它;否则,说明它只是一道换了个名字的旧菜,果断放弃。为了在大规模数据集上跑得更快,实际还会先做聚类,再在每个簇内挑代表。
菜单策划把“番茄炒蛋”和“西红柿炒鸡蛋”合并成一道菜,去重算法则把相似度超标的重复指令拦在门外。这样留下的数据集既有代表性又不冗余,模型才能在尽可能广的指令空间里得到充分训练。
- 相似度指标\(\text{ROUGE-L}(x_i, x_j)\) 计算两条指令的相似程度,值越高代表越接近。
- 取最大值\(\max_{j < i}\) 遍历所有排在 \(x_i\) 之前的旧指令,取其中最高的相似度。
- 阈值判定\(< \tau_d\) 要求最高相似度也低于去重阈值 \(\tau_d\),也就是说没有任何旧指令和它“撞菜”。
- 保留指示\(\mathbb{1}\{……\}\) 把“超过阈值就丢弃、低于阈值就保留”的决策包装成一条判定函数。
进化指令思想:家常菜升级创意菜
基础菜单备齐后,餐厅想要更上一层楼。普通家常菜人人都能做,很难形成竞争壁垒;真正让食客惊艳的,是那些工序复杂、摆盘精美、味道有层次感的创意菜。但让人类厨师天天研发新创意菜,成本高、速度慢。Evol-Instruct 的思路是:既然二厨已经学会了做家常菜,为什么不让他自己把家常菜“升级”成创意菜呢?
WizardLM 团队发现,如果只是用普通指令训练模型,模型能力提升有限。于是他们提出进化指令(Evol-Instruct):让大模型扮演“进化器”,对一条简单指令进行重写,比如添加更多约束条件、要求分步骤推理、增加边界情况讨论等,把指令变得越来越复杂。同时,进化必须遵守规则:不能丢失原指令的核心信息,复杂度必须真正提升,而且不能为了难而难到语义扭曲。每一条进化后的指令,再让模型生成对应的回答,成为高难度的训练样本。
这就好比二厨把一道普通的“宫保鸡丁”升级成“搭配三种干辣椒、带荔枝木熏香、要求精准控制油温的分子料理版宫保鸡丁”。菜还是那道菜,但工序复杂度天差地别。模型在训练时“啃”下这些高难度菜谱,自然能学会更复杂的推理和指令遵循能力。
- 进化器\(g_{\theta}\) 是具备改写能力的大模型,参数为 \(\theta\),它负责“二次创作”。
- 进化指令\(p_{\text{evol}}\) 是一段提示词,告诉模型“请把下面的指令变得更难、更详细、更复杂”。
- 新指令\(I'\) 是进化器输出的升级版指令,通常包含更多约束、更长的推理链。
- 复杂度约束\(\text{复杂度}(I') > \text{复杂度}(I)\) 说明进化不是随便换个说法,难度必须实打实地上升。
双向进化:做得更深与铺得更广
创意菜的升级方向不止一条。有的厨师选择“往深处走”:同一道菜增加更多工序,要求更精准的火候、更稀缺的食材、更苛刻的摆盘,把一道菜做到极致;也有的厨师选择“往宽处走”:把同一种基础配方改编成川菜、粤菜、法餐、日料等不同菜系,让菜单覆盖面更广。Evol-Instruct 也设计了这两条互补的进化策略,它们分别是深度进化和宽度进化。
深度进化(Evol Depth)是一条串行链路:从初始指令出发,反复调用进化器,每轮都添加新约束。比如先让模型“解释梯度下降”,再要求“用数学公式对比随机梯度下降和全量梯度下降”,再进一步要求“补充两个收敛性条件并分析它们的区别”。每经过一轮,指令都变得更难。宽度进化(Evol Width)则是一条并行分支:把同一条指令改写成涉及不同领域、不同风格、不同场景的多个版本。比如“写一封道歉信”可以扩展到“写一封给客户的正式道歉信”“用幽默风格写一封道歉邮件”“用繁体中文写一封给长辈的道歉信”等。
回到厨房:深度进化像主厨反复磨炼同一道招牌菜,宽度进化像把基础配方推广到八大菜系。真实训练中不能只做深度——那样数据会越来越偏、越来越窄;也不能只做宽度——那样难度上不去,模型学不到深推理。两条腿一起走,进化指令才能真正提升模型能力。
- 深度迭代\(I_{d+1} = g_{\text{deep}}(I_d)\) 表示第 \(d+1\) 轮深度进化把第 \(d\) 轮指令作为输入,再拔高一个难度等级。
- 宽度并行\(g_{\text{width}}(I)\) 一次性生成一组指令 \(\{I_w^{(1)}, \dots, I_w^{(K)}\}\),覆盖 \(K\) 个不同方向。
- 两个进化器\(g_{\text{deep}}\) 和 \(g_{\text{width}}\) 是同一模型在不同提示词驱动下的两种角色。
- 串行与并行深度进化是单线迭代,宽度进化是扇状展开,两者相互补充。
路线对比与选型:小餐馆和米其林的抉择
理解了 Self-Instruct 和 Evol-Instruct 的机制后,最现实的问题是:我到底该用哪条路线?答案取决于你的“餐厅定位”。开一家平价小餐馆,菜单要快速铺开、成本要低,Self-Instruct 这种“种子复制”思路最合适;要冲米其林星级,顾客期待的是有难度、有深度的硬菜,那就得靠 Evol-Instruct 持续打磨高复杂度指令。
从成本上看,Self-Instruct 对模型的调用次数少、生成速度快,一条种子指令能催生几十条新数据,适合冷启动阶段快速构建基础指令集。Evol-Instruct 每次进化都要多次调用模型,而且进化后的长指令生成回答更耗时,成本显著更高;但它能在复杂推理、多步规划、专业问答上带来明显的能力增益。实践中更常见的做法是混合:先用 Self-Instruct 铺量,再用 Evol-Instruct 挑一部分数据做难度升级,按比例配成最终数据集,最后通过评估集对比不同配比的效果。
开业选小餐馆还是米其林,没有绝对好坏,只有合不合适。合成数据也是一样:预算有限时优先 Self-Instruct,模型能力遇到瓶颈时引入 Evol-Instruct,有条件时按评估结果动态调整两者比例。理解了这两条路线的本质和差异,你就掌握了合成数据生成的完整方法论。
- 混合数据集\(\mathcal{D}_{\text{final}}\) 是把两类数据合并后的最终训练集,供模型微调使用。
- 两路来源\(\mathcal{D}_{\text{SI}}\) 来自 Self-Instruct 自举+过滤+去重的输出,\(\mathcal{D}_{\text{Evol}}\) 来自 Evol-Instruct 进化的高难度指令。
- 配比系数\(\alpha\) 是 Self-Instruct 数据量占总数据量的比例,用来刻画两条路线的“权重”。
- 评估驱动选型实际工程中通过 AlpacaEval 等评估集对比不同 \(\alpha\) 的模型表现,选择最优配比。
AI 应用场景
金融客服指令集快速冷启动
阶段:数据准备 / 指令微调
解决的问题:企业要微调客服机器人,但人工整理问答对既慢又贵。传统标注一批 2 万条数据需要数周,且难以覆盖用户各种问法。
具体案例:某金融科技公司先用 300 条人工编写的理财客服种子指令,让大模型通过 Self-Instruct 自举出 2 万条候选问答;再用规则过滤掉涉及收益承诺的敏感表述,用 ROUGE 相似度去重;最后用这批数据做 LoRA 微调。上线后客服意图识别准确率提升了 12%,数据构建成本仅为人工标注的五分之一。
复杂推理能力冲刺
阶段:模型训练数据增强
解决的问题:普通指令数据对模型复杂推理能力帮助有限。人工编写高难度数学、逻辑题成本极高,且难以规模化。
具体案例:一个开源模型团队想要提升模型的数学推理水平。他们用 Evol-Instruct 给简单题目逐步增加约束:把“解一元二次方程”进化成“结合韦达定理讨论参数范围、并给出至少两种解法、还要指出常见计算误区”。最终构建了 5000 条高难度进化题,微调后模型在 GSM8K 数学基准上的准确率提升了约 5 个百分点。
通用智能体混合数据配比
阶段:数据配比与评估
解决的问题:单一合成数据路线容易让模型能力失衡——只用 Self-Instruct 会导致模型解答不了难题,只用 Evol-Instruct 又会导致覆盖面不足、基础能力不稳。
具体案例:某智能体研发团队先用 Self-Instruct 生成 7 万条覆盖日常任务的指令,再用 Evol-Instruct 将其中 3 万条升级为需要多步工具调用的复杂指令,按 7:3 混合后微调。在智能体任务测试集上,相比只使用 Self-Instruct 数据的版本,任务完成率提升了 18%。
Python 演示
# -*- coding: utf-8 -*-"""Self-Instruct 与 Evol-Instruct 核心流程模拟"""import re SEED_INSTRUCTIONS = [ "请解释什么是机器学习", "写一个 Python 函数判断回文", "用一句话总结注意力机制", "列举三种排序算法并比较",] def llm_generate(prompt): """模拟大模型按照提示词生成新指令(真实场景中替换为 LLM 调用)""" templates = [ "请详细解释{kw},并给出一个生活中的例子", "针对{kw}写一段教学讲解,要求初学者能听懂", "结合{kw}设计三个练习题,难度从低到高", "把{kw}改写成对话形式,并指出常见误区", ] words = re.findall(r"[\u4e00-\u9fff]+", prompt) kw = words[-1] if words else "机器学习" t = templates[len(words) % len(templates)] return t.format(kw=kw) def quality_filter(text): """质量过滤规则:长度足够且不含非法描述""" if len(text) < 6: return False if any(w in text for w in ["报错", "无法", "空"]): return False return True def jaccard_similarity(a, b): """基于字符集合的简化去重指标,模拟 ROUGE 的用途""" sa, sb = set(a), set(b) return len(sa & sb) / max(len(sa | sb), 1) def llm_evolve(text, depth=1): """模拟 Evol-Instruct 的深度进化:给指令追加约束""" constraints = [ "同时给出时间复杂度和空间复杂度分析", "并补充至少 2 个边界案例", "再用对比表格总结优缺点", ] out = text for i in range(depth): out += "," + constraints[i % len(constraints)] return out def build_dataset(rounds=3, max_dedup=0.6): """完整流程:自举 -> 过滤 -> 去重 -> 进化""" dataset = list(SEED_INSTRUCTIONS) for r in range(rounds): new_items = [llm_generate(s) for s in dataset[:]] new_items = [x for x in new_items if quality_filter(x)] clean = [] for x in new_items: if all(jaccard_similarity(x, y) < max_dedup for y in clean): clean.append(x) dataset += clean evolved = [llm_evolve(x, depth=(r + 1)) for x in clean[:3]] dataset += evolved return dataset if __name__ == "__main__": final = build_dataset() print("最终数据集大小:", len(final)) for item in final[:10]: print("-", item)
SEED_INSTRUCTIONS = [...]定义种子菜谱,是整个数据生成流水线的起跑线。def llm_generate(prompt)模拟大模型把一条指令扩展成多条新指令,对应自举环节。quality_filter(text)用规则当“试吃官”,把长度不足或含异常词汇的样本挡在门外。jaccard_similarity(a, b)简化版去重指标,负责判断两条指令是否“撞菜”。llm_evolve(text, depth=1)模拟 Evol-Instruct 的深度进化,每轮追加一条约束。new_items = [llm_generate(s) for s in dataset[:]]对数据集里的每条旧指令做自举扩展。new_items = [x for x in new_items if quality_filter(x)]自举结果先过过滤关,只保留合格样本。if all(jaccard_similarity(x, y) < max_dedup for y in clean)只有和已保留样本都不相似的指令才能进最终列表。evolved = [llm_evolve(x, depth=(r + 1)) for x in clean[:3]]每轮挑几条干净指令做进化,模拟难度升级。
常见误区
误区以为 Self-Instruct 完全不需要人工参与,随便写几百条种子指令丢给模型,它自己就会产出高质量数据集,种子质量好坏无所谓。
正解种子指令决定了整个数据分布的质量上限。就像餐厅的家传菜谱如果本身是黑暗料理,二厨再努力也只能复制出更多黑暗料理。种子必须精心设计,覆盖目标任务的典型场景、风格和难度,否则自举出来的数据会带偏模型。
为何常见:因为“自举”听起来像全自动,人们容易忽略它只是生成机制,而质量源头仍然掌握在人工种子手里。
误区认为质量过滤是多多益善,把阈值设得很高,凡是模型评分低一点、长度短一点的样本统统删掉,这样数据一定更干净。
正解过度过滤会让数据分布严重失真。好比试吃官只留下满分的米其林菜,结果菜单上全是同一种风格,模型对其他合理表达完全没见过。过滤的目标是去掉“不合格”,而不是去掉“普通”。应该保留覆盖面,只剔除真实的噪声样本。
为何常见:人们直观上觉得“少而精”总比“多而杂”好,却忽略了训练数据需要一定的多样性才能学到泛化能力。
误区以为进化指令就是在原句后面多写几句废话,或者多加几个形容词,让文本看起来更长、更复杂就算完成。
正解Evol-Instruct 的核心是增加“认知难度”:多步推理、边界条件、跨知识约束,而不是单纯加字数。指令可以很短但难度极高,比如“用最多 50 字解释量子纠缠并证明 Bell 不等式”——短而难。长度和复杂度不是一回事。
为何常见:因为复杂指令在直觉上往往更长,人们容易把“变长”当作“变难”的等价信号。
误区认为 Self-Instruct 和 Evol-Instruct 是互相替代的方案,选了一条就不能用另一条,或者认为 Evol 一定全面优于 Self。
正解两条路线各有侧重:Self-Instruct 负责快速铺量、扩大覆盖面,Evol-Instruct 负责提升难度、突破能力上限。实际工程中经常先自举铺量再进化升级,按比例混合后通过评估选配比,取得“既能答日常问题又能解复杂难题”的均衡效果。
为何常见:因为资料通常把两者分开介绍,读者容易形成“路线=单选题”的印象,忽略了它们本质上是上下游互补的工具。
面试题
Q1. Self-Instruct 训练数据自举的第一步是?
- A.用种子指令让模型生成新指令← 正确答案
- B.用人工标注大规模全新数据集
- C.直接下载网上公开的问答数据
- D.随机删除部分旧训练集数据
答案:A。Self-Instruct 的第一步是把少量种子指令交给模型,让模型照葫芦画瓢生成新指令。这就像把家传菜谱交给二厨,先让他复制出更多变体。B 是人工方案,C 是采集合集,D 是删数据,都不是“自举扩展”。
Q2. Self-Instruct 中“自举”指的是什么?
- A.用模型自己生成数据再训练自己← 正确答案
- B.用外部数据集训练预训练模型
- C.让人类反馈强化学习模型行为
- D.把模型参数从零开始随机初始化
答案:A。自举的核心是“以模型输出训练模型自己”,像二厨做的新菜又成了下一批菜的样例。B 是预训练,C 是 RLHF,D 是随机初始化,都与自举的循环机制无关。
Q3. 下列哪项不属于 Self-Instruct 的质量过滤手段?
- A.按长度规则自动剔除过短指令
- B.用规则过滤包含敏感词的指令
- C.用另一个模型打分筛掉低分数据
- D.随机打乱语料并重新划分训练集← 正确答案
答案:D。质量过滤的三板斧是规则过滤、模型打分、输入输出配对检查。随机打乱语料只是改变顺序,不会提升数据质量,就像把臭豆腐在冰箱里换层放并不能让它变香。D 完全不属于过滤手段。
Q4. Evol-Instruct 的深度进化核心目标是?
- A.增加指令的复杂度和推理难度← 正确答案
- B.增加指令的主题数量与覆盖领域
- C.减少生成指令的文本长度
- D.让模型输出格式更加统一规范
答案:A。深度进化是往“难”里做:加约束、加推理步骤、加边界情况,对应把家常菜升级成工序复杂的创意菜。B 是宽度进化的目标,C 与进化方向相反,D 是格式控制而非难度提升。
Q5. Self-Instruct 多样性去重主要依赖什么指标?
- A.用 ROUGE-L 衡量指令相似度← 正确答案
- B.用 BLEU 和困惑度衡量质量
- C.用交叉熵损失衡量生成概率
- D.用 Top-p 参数控制采样随机性
答案:A。Self-Instruct 用 ROUGE-L 计算两条指令的公共子序列重叠度,判断是否“撞菜”。BLEU 和困惑度可用于评估文本质量,交叉熵是训练损失,Top-p 是采样参数,它们都不是去重时的主要相似度指标。
Q6. 一条指令被改写成“在加入参数范围约束、增加反例讨论、要求给出证明步骤”的版本,这属于哪种进化?
- A.采用了深度进化策略← 正确答案
- B.采用了宽度进化策略
- C.进行了数据去重处理
- D.进行了质量过滤处理
答案:A。加约束、加证明步骤、讨论反例,都是在让同一条指令“更难”,属于深度进化。这就像给宫保鸡丁增加分子料理工序,是纵向变深而非横向变广。
Q7. Self-Instruct 生成的候选数据要经过哪些处理环节?
- A.规则和模型双重质量过滤← 正确答案
- B.基于相似度聚类的去重筛选← 正确答案
- C.指令与回答配对去噪清洗← 正确答案
- D.全部交给人类重新撰写一遍
答案:ABC。候选数据要过“试吃官”(规则和模型过滤)、“菜单策划”(相似度去重)以及配对完整性检查三道关。D 放弃模型生成改由人工重写,既不现实也违背自举的初衷。
Q8. 关于 Self-Instruct 与 Evol-Instruct,说法正确的有?
- A.Self-Instruct 侧重从种子扩展规模← 正确答案
- B.Evol-Instruct 侧重提升指令难度← 正确答案
- C.两者都必须结合大量人工数据
- D.两者可以搭配形成混合训练路线← 正确答案
答案:ABD。Self-Instruct 把种子越滚越多,Evol-Instruct 把指令越磨越难,两者是互补关系,实践中常混合使用。C 错误,因为它们的优势恰恰是减少人工数据依赖,而不是必须大量人工介入。
Q9. 下列哪些是 Evol-Instruct 进化时必须遵守的规则?
- A.不能丢失原指令的核心语义← 正确答案
- B.新指令的复杂度要明显提升← 正确答案
- C.可以让新指令含义完全反转
- D.每轮进化都必须生成一百条
答案:AB。进化要在保留原意的基础上提升难度,像升级菜谱不能把宫保鸡丁变成芒果糯米饭。C 语义反转违背“不丢失信息”原则,D 中的数量是人为设定,不是必须遵守的规则。