想象你是培训机构的教研组长。学生等着做题,但一道题一道题亲自出太慢了——于是你请来一位聪明的助教。你先手写 20 道例题,让助教照着风格批量出题;出完的题还要有质检员检查错题,有查重小组防套壳抄袭,最后按难度和题型配比装订成册。这套“出题工坊”的玩法,正是大模型时代造指令数据的整套方法论。 本文要讲两条核心技术路线:Self-Instruct 让模型照着种子指令“自举”出新指令,越滚越多;Evol-Instruct 让简单题一步步“进化”成复杂应用题。同时我们讨论指令的多样性与难度均衡——就像考卷不能只考计算题,也不能全是奥数题。最后是质量过滤、语义去重与工程化流水线,确保造出来的数据干净、不重复、能落地。
对 AI 从业者而言,掌握指令数据合成意味着不再依赖天价人工标注,而是用一条自动化流水线低成本为 LLM 微调造出高质量训练集——这是算法工程师从“调参”走向“造数据”的关键一跃。
可视化演示
展示Self-Instruct自举生成流程、Evol-Instruct进化复杂度增强、质量过滤去重管线,切换模式掌握大模型指令数据自动化生产核心原理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Self-Instruct自举生成方法 种子指令池 bootstrap 启动,LLM根据已有指令生成新指令-响应对,逐步扩展指令池实现数据自增殖 生成后经质量过滤(语法/重复/相似度)和去重处理,合格指令回填种子池形成正向循环 seed(175) → LLM generate → filter → pool(N×) Self-Instruct通过自举循环实现指令数据的自动化规模化生产
自举生成
教研组长翻遍资料柜,好不容易凑出 20 道不同风格的好例题——有概念题、有应用题、有代码题。组长把例题往助教桌上一放:“照这个手感,给我出满一千道。”助教秒懂每道题的套路,刷刷刷写出几百道风格相近的题目。组长挑出其中最好的几十道收进例题册,下一轮再让助教照着更厚的册子出题。这个过程,就是自举。
Self-Instruct 来自 2022 年底斯坦福的工作,核心是让大语言模型用少量“种子指令”生成大量新指令。把这段迭代精简成一句话:先准备种子,让模型生成,过滤后回填,再重复。每多跑一轮,指令池就厚一圈,指令风格也越发贴近我们想要的方向。
实际操作时,种子指令只有几十到几百条。每一步从池中随机抽 8 条作为“上下文示范”喂给模型,要求“仿照以上指令的风格,写出一条全新的指令”。新指令再经过输入生成与回答生成两个阶段,通过质量检查后才允许加入指令池。这样循环几十轮,通常能得到上万条覆盖广泛任务的指令。
老教师只负责最初的 20 道例题,剩下几千道全是助教自学的成果——这正是自举最迷人的地方:用一小撮人工种子,撬动一大片合成数据。
- 条件概率符号竖线右边是已知条件,左边是预测目标,整体读作“在给定种子指令的条件下,模型生成新指令的概率”。
- 序列展开w_t 是第 t 个词,w_{<t} 是它前面已经生成的所有词,表示每个词都是基于上下文和已有词逐一预测的。
- 连乘累加从第 1 个词到第 T 个词的预测概率连乘,得到整条新指令的生成概率,训练目标就是最大化这个概率。
进化复杂度
光会出基础题还不够,考试要有区分度。老教师拿出最简单的一道“1+1“,先加上情境:”小明有 3 个苹果又买了 2 个,一共几个?“再要求”列出算式并说明为什么用加法“,最后要求”改写为一道需要分步计算的购物找零问题”。每改一遍,题目就复杂一截。这条从易到难的改造链,就是进化。
Evol-Instruct 由 WizardLM 团队提出,它不要求模型凭空创造新指令,而是对已有指令做“复杂度改造”。改造分两个方向:深度进化让原有逻辑链变长、增加约束;广度进化则让指令换成全新任务类型。
具体提示词像一张“改造任务单”:给它一条指令 I_t,要求它“重写为更复杂的版本,例如增加 5 个约束、要求分步思考、补充背景条件,或改写成代码生成任务”;同时约束“新指令必须可回答,且复杂度高于原指令”。模型输出的 I_{t+1} 继续喂给下一轮,形成阶梯。
老教师靠着“每次加一点难度”的策略,把一道口算题喂成了压轴大题——模型的知识边界也被这样一点点撑开。
- 进化算子I_t 是第 t 轮的指令,Evolve 是“进化”这个动作——把指令交给 LLM 并要求它改写。
- 约束记号s.t. 表示“subject to(满足)”,后面跟着的是进化的硬性要求,防止模型随便乱改。
- 复杂度严格递增要求新指令的复杂度大于旧指令,确保每一轮都在往难里走,防止模型把题改简单。
多样性控制
一套好卷子要是清一色计算题,学生练完只会套公式。教研组长在开工前会先定“出题大纲”:概念题 30%、应用题 30%、代码题 20%、开放论述 20%。大纲定完,助教们分头执行,谁也不好意思只出自己擅长的类型。
指令数据的多样性同理。如果生成出的指令集中在少数几个模板上,模型微调后就学成“偏科生”:训练集里的任务做得飞起,换个问法就懵。信息熵是衡量分布均匀程度的数学工具。
多样性可以从事前与事后两个层面控制。事前:在生成提示词中注入随机任务类型、随机领域主题、随机角色设定,人为打散数据分布。事后:统计生成结果属于哪几类,用熵值评估分布是否失衡,若某些类别过少就定向补充生成。
出题大纲就是多样性控制的标杆,熵则像是工坊里的“均衡仪表盘”——指针偏了,就提醒组长赶紧调整生成任务。
- 事件概率p(x_i) 指第 i 种指令类型在所有指令中的占比,x 是类型的具体取值。
- 对数项占比越小,负对数越大,说明这类指令越稀缺,对多样性的贡献越大。
- 加权求和把所有类型的“稀缺度贡献”加起来得到熵,熵越大分布越均匀。
难度管理
卷子难度要有梯度。全基础题,优等生觉得无聊;全奥数题,普通学生直接放弃。有经验的组长会定“基础 60%、中档 30%、压轴 10%”的配比,让每个层次的学生都有收获。
指令难度同样需要配比。难度过低,模型得不到有效训练;难度过高,模型学不会,损失长期不降甚至损害基础能力。怎么量化难度?最朴素的办法是让模型自己试答,用“通过率”反推。
把生成的每条指令丢给一个基础模型试做,统计正确率。通过率越高说明指令越简单。有了难度标签后,可以按预算分层采样:60% 低难度、30% 中难度、10% 高难度,或用课程学习策略先易后难地喂给模型。
组长的难度账本上,每条指令都标着难度系数;最终按 6:3:1 配比装订,训练出的模型既扎实又不偏科。
- 通过率统计分子是模型答对的样本数,分母是参与测试的样本总数,比值就是通过率。
- 难度映射用 1 减去通过率,把“会不会做”转成 0 到 1 的难度值,通过率高的题难度低。
质量过滤
助教再聪明,批量出题也难免带病:有的题条件自相矛盾,有的题答案算错,有的题题干缺主语。工坊为此设了“质检组”——先让机器检查基本格式,再请更资深的老师通读打分,最后组长抽几份复核。三道关卡下来,才敢把题印进卷子。
LLM 合成数据的质量噪声远比人工数据大。质量过滤通常也是三层结构:规则过滤 + 模型评分 + 人工抽检。
规则层是便宜又快速的一刀切:空指令、超短指令、含占位符或敏感词的,直接丢。模型层用更强的大模型当“裁判”,对(指令,回答)给出 1-5 分,低于阈值的淘汰;还可以让裁判判断“这条指令是否清晰、是否有唯一可接受的答案”。人工抽检按 1%-5% 的比例抽查,估算整批合格率,防止机器判断出现系统性偏差。
质检组把关后,入库的每一道题都经得起检验;有了这套关卡,助教才能放心大胆地批量出题。
- 规则分数S_rule 表示第一道关卡——规则检查给出的评分,比如长度、格式、敏感词是否通过。
- 模型分数S_llm 是第二道关卡——强模型给这条数据打的软性质量分。
- 加权合成α 与 β 是两个关卡的权重,和为 1,最终得分是两道关卡的加权平均。
语义去重
偶尔有偷懒的助教,把“小明有 3 个苹果”改成“小李有 3 个梨”,就当成新题交差。字面上确实是两道题,但模型一看本质上还是同一种运算。工坊请来了“查重小组”——不看表面文字,而是比“题意指纹”,指纹相近的判为重复。
查重的关键在于理解语义。字符串完全相同的重复容易去,但大模型生成的变体往往是“换了个实体名、改了个数字”的套壳题,必须用文本向量来捕捉语义。
先把每条指令经 embedding 模型编码成一个稠密向量,这个向量就是“题意指纹”。再用余弦相似度计算两两距离:相似度超过阈值(常见 0.85)就丢弃其中一条。几十万条的大规模场景下,两两比对太慢,可先用聚类把相近指令粗分到桶里,桶内再精细去重。
查重小组的“指纹库”保证了指令池的独立性——每条题都有自己的位置,不被套壳同胞挤占。
- 点积把两个向量对应位相乘再求和,衡量它们在嵌入空间中的方向一致性。
- 模长归一除以两个向量的长度,把结果映射到 [-1, 1],消除向量长度不同带来的干扰。
- 相似度判定余弦值接近 1 说明语义高度相似,超过预设阈值(如 0.85)就判为重复。
工程化落地
当工坊从“周末突击出题”变成“每天稳定出千道题”,就不能再靠人肉协调了。组长要搭一条流水线:出题任务自动派发、质检自动通过、查重自动完成、合格题自动归档,每一步都有记录,随时能查“某道题是谁出的、哪一轮出的、难度多少”。
实际生产环境里,指令数据合成同样是一条 pipeline:任务配置 → 批量生成 → 规则过滤 → 模型评分 → 语义去重 → 分层采样 → 入库。每个环节都要考虑吞吐量、成本与可追溯性。
生成环节通常异步并发调用模型接口,用多 key 分组控制速率;超时或失败的请求自动重试,成功的结果写缓存,避免同一批数据重复花钱;每条数据打上生成链路标签(用哪个模型、第几轮、难度标签)。最终用“良率”评估整条管线:生成 10 万条,入库 3 万条,良率就是 30%,这个数字直接决定数据成本。
流水线把“出题—质检—查重—归档”固化为一套自动工序,老教师终于从重复劳动中解放出来,专心做最难的事——定方向。
- 通过数量分子指通过过滤、去重等所有关卡后真正入库的指令条数。
- 总生成量分母指模型原始生成的所有指令条数,包括被淘汰的部分。
- 转化百分数把比值换算成百分比,便于设置监控指标,比如“良率低于 20% 要告警”。
AI 应用场景
客服意图识别数据合成
阶段:数据准备(合成数据生成)
解决的问题:人工标注客服意图样本成本高,一条数据 3-5 元,且覆盖场景有限。传统做法靠运营同学手工整理“用户问法→意图”的语料,整理 5000 条就要数周时间。
具体案例:某电商平台用 Self-Instruct 从 50 条种子意图指令出发,生成 3 万条“用户问法 → 意图分类”的指令对。先做规则过滤和语义去重,再按难度分层采样,最终微调意图识别模型,准确率提升 8 个百分点,成本只有人工方案的十分之一。
数学推理能力增强
阶段:数据增强与模型微调
解决的问题:开源数学问答数据量少、难度偏低,直接用现有数据微调,模型只会套公式不会多步推理。人工编高质量数学题又需要学科专家参与。
具体案例:用 Evol-Instruct 把基础运算题逐步改造成多步推理题、应用题,配合难度控制按 6:3:1 生成训练集。微调后模型在数学评测集上通过率提升显著,尤其在中高难度题上表现亮眼。
数据飞轮与持续更新
阶段:数据回流与再合成
解决的问题:真实线上数据分布会漂移,静态训练集容易过期。每次人工整理新数据都是一轮重活。
具体案例:上线后将模型失败的线上 case 收集起来,作为种子指令触发新一轮 Self-Instruct 生成,自动经历过滤、去重后增量入库,实现“周级”数据迭代。每条新增数据都带着生成链路标签,方便回溯是哪一轮、哪个模型产物。
Python 演示
"""Self-Instruct 简化演示:种子指令 -> 模板自举 -> 规则过滤 -> 语义去重"""import random SEEDS = [ "解释一下{concept}的基本原理", "请给出{concept}的一个实际例子", "为什么{concept}在工程中很重要", "写出实现{concept}的伪代码",] CONCEPTS = ["哈希表", "快速排序", "动态规划", "二叉树", "图搜索"] BAD_WORDS = ["TODO", "忽略", "随便", "我不知道"] def llm_generate(prompt_pool, rounds=50): """模拟 LLM 自举:每轮从池中抽种子,变形出新指令并回填池子""" for _ in range(rounds): seed = random.choice(prompt_pool) concept = random.choice(CONCEPTS) new_inst = seed.replace("{concept}", concept) prompt_pool.append(new_inst) return prompt_pool def rule_filter(instructions): """规则过滤:长度限制在 5-30,剔除坏词""" good = [] for inst in instructions: if len(inst) < 5 or len(inst) > 30: continue if any(w in inst for w in BAD_WORDS): continue good.append(inst) return good def jaccard_sim(a, b): """用字符集合的 Jaccard 相似度近似语义相似度""" sa, sb = set(a), set(b) if not sa or not sb: return 0.0 return len(sa & sb) / len(sa | sb) def dedup(instructions, threshold=0.75): """与已保留指令相似度超过阈值则丢弃""" unique = [] for inst in instructions: dup = False for kept in unique: if jaccard_sim(inst, kept) > threshold: dup = True break if not dup: unique.append(inst) return unique def main(): random.seed(42) pool = [s.format(concept=CONCEPTS[0]) for s in SEEDS] generated = llm_generate(pool, rounds=50) filtered = rule_filter(generated) final = dedup(filtered) print(f"生成 {len(generated)} 条 -> 过滤后 {len(filtered)} 条 -> 去重后 {len(final)} 条") for inst in final[:8]: print("-", inst) if __name__ == "__main__": main()
pool = [s.format(concept=CONCEPTS[0]) for s in SEEDS]用“哈希表”填充 4 个种子模板,得到初始指令池,对应自举的第一步generated = llm_generate(pool, rounds=50)自举 50 轮:每轮从池中随机抽一条种子,替换概念后生成新指令并回填,模拟“越滚越多”filtered = rule_filter(generated)规则过滤:剔除过短、过长和含坏词的指令,对应质量过滤的第一道关卡final = dedup(filtered)用 Jaccard 相似度做语义去重,把内容高度雷同的指令留在池外,保证多样性random.seed(42)固定随机种子,让每次运行结果可复现,工程化中对齐实验数据很重要
常见误区
误区多写点提示词让模型多生成几万条指令,直接灌进去训练,模型肯定越来越强,数量就是王道。
正解数量不代表质量。低质量、重复度过高的数据会让模型学到错误模式,甚至出现“复读机”现象。就像工坊里堆了十万道互相套壳的题,学生练得再多也只会一种解法。质量过滤和去重的优先级高于数量。
为何常见:训练数据规模越大越好的传统直觉仍然有效,人们忽略了合成数据的噪声比人工数据高出一个量级。
误区我让 GPT 生成指令,再让 GPT 打分,这样应该就够了吧?反正都是“专家”。
正解同一模型存在“自我偏好”,会给自己生成的内容打高分,过滤环节形同虚设。就像助教自己出的题自己批改,很难发现设计缺陷。最好用更强的模型做裁判,或至少换一个不同家族的模型来打分。
为何常见:方便、省钱,看似闭环,实际上生成和评估的偏差同源,等于“既是运动员又是裁判”。
误区去重随便做做就行,把完全一模一样的字符串去掉就够了,剩下的看着都挺不一样。
正解LLM 生成的指令重形不成文,表面不同但语义相同的指令会大量挤占训练容量,导致模型在真实场景泛化不足。就像学生刷了一百道“换人名换数字”的同一题型,遇到真正的新题型依然不会做。语义去重是保障训练样本独立性的关键步骤。
为何常见:人们习惯用字符串级别的判断,没意识到模型学到的是语义分布而非字面内容。
误区Evol-Instruct 进化得越难越好,模型见过足够多的难题,就什么都会了。
正解过高的难度超出模型当前能力范围,训练时损失降不下去,反而可能损害基础能力。就像给小学生直接上微积分,课上完什么都留不下。“跳一跳够得着”的难度分布(基础:中等:困难 ≈ 6:3:1)最稳妥。
为何常见:把“数据挑战性”与“数据价值”画等号,忽略了学习理论里的最近发展区——最有效的学习发生在略高于当前水平的地方。
面试题
Q1. Self-Instruct 中“自举”的核心动作是?
- A.用模型生成的数据扩充训练集← 正确答案
- B.用人工标注的数据扩充集
- C.用外部公开的数据扩充集
- D.用数据增强的方式扩充集
答案:A。Self-Instruct 的自举类似老教师先写 20 道例题,再让助教照着出题并把好题收回例题册——核心是用模型自己产出的数据反哺训练集。B、C、D 都依赖外部来源,失去了“自产自销”的含义。
Q2. 指令多样性控制的主要目的是?
- A.防止模型过拟合单一任务类型← 正确答案
- B.加快模型训练收敛的速度
- C.减少训练数据的整体体积
- D.降低模型推理时的资源开销
答案:A。多样性控制像出题要覆盖不同知识点,防止学生只会做计算题。模型若只见过生成类型 A 的指令,真实场景遇到类型 B 就抓瞎。B、C、D 都与多样性无关。
Q3. Evol-Instruct 深度进化最常见的操作是?
- A.给指令增加前提和约束条件← 正确答案
- B.把指令翻译成其他语言
- C.删除指令中的冗余描述词
- D.把长指令缩减成短指令
答案:A。深度进化就像老教师把“1+1“改写成”3 个苹果再加 2 个苹果,一共有几个”,通过增加前提、约束让推理链变长。B、C、D 是改写或压缩,不增加复杂度。
Q4. 一条指令的通过率为 0.25,其难度是多少?
- A.难度是 0.75← 正确答案
- B.难度是 0.25
- C.难度是 1.25
- D.无法从通过率推算
答案:A。难度定义为 1 减去通过率:通过率 0.25 意味着 4 次尝试里只有 1 次答对,难度就是 1-0.25=0.75。B 把通过率当难度,C 超出取值范围,D 忽略了有公式可算。
Q5. 语义去重中余弦相似度接近 1 意味着?
- A.两条指令语义高度相似← 正确答案
- B.两条指令长度完全一致
- C.两条指令词汇完全不同
- D.两条指令词序完全相同
答案:A。余弦相似度衡量两个向量方向的一致性,接近 1 说明方向几乎相同,映射到语义层面就是高度相似。B 和 D 是词面层判断,C 是语义相反。
Q6. Self-Instruct 迭代流程的正确顺序是?
- A.种子指令到生成再到过滤回填← 正确答案
- B.过滤种子到生成再到丢弃
- C.生成新指令到过滤再丢弃
- D.人工标注到生成再到入库
答案:A。标准流程是种子指令让 LLM 生成新指令,过滤掉不合格的,把好指令加回指令池继续迭代,就像例题册越攒越厚。B、C、D 的顺序或关键动作有误。
Q7. 质量过滤的综合评分公式 Score 用到了?
- A.规则分和模型分加权求和← 正确答案
- B.仅用规则分直接判死
- C.仅用模型分直接判死
- D.人工分和模型分加权求和
答案:A。综合评分 = α × 规则分 + β × 模型分。规则分做硬性门槛,模型分做软性评价,加权合起来决定去留。B、C 孤注一掷,D 把人工放进公式——人工通常用在抽检而非在线打分。
Q8. 指令数据合成的质量关卡包括哪些?
- A.用规则过滤空短文本← 正确答案
- B.用强模型评分筛选← 正确答案
- C.人工抽检把好关← 正确答案
- D.随机丢弃一半数据
答案:ABC。质量关卡由规则过滤、强模型评分、人工抽检三层组成,缺一不可。D 是随机砍样本,不算质量把关,反而会误伤合格数据。
Q9. 关于 Evol-Instruct 的描述正确的是?
- A.深度进化让指令逻辑链变长← 正确答案
- B.广度进化引入新任务类型← 正确答案
- C.进化需控制跳跃幅度← 正确答案
- D.进化目标是最短指令
答案:ABC。Evol-Instruct 有两条路径:深度进化加深逻辑链、广度进化引入新任务类型,同时要控制跳跃幅度避免过难。D 说目标是最短指令,与进化方向完全相反。
Q10. 指令数据工程化落地的关键环节有哪些?
- A.异步并发调用接口生成← 正确答案
- B.失败重试与结果缓存← 正确答案
- C.每条数据记录生成链路← 正确答案
- D.完全无需人工抽检干预
答案:ABC。工程化需要异步并发调用提升吞吐、失败重试与缓存控制成本、链路标签保证可追溯。D 说不要人工抽检,但工程实践里抽检仍是质量保障的最后一道防线。