测试LLM输出效果,离不开大量数据集。从零开始准备这些数据,费时、烧钱,还特别折腾。但现在情况不一样了:以前要花几周手工打造的数千条测试用例,现在几分钟就搞定。
合成数据生成的核心思路很简单:让LLM自己造数据,省掉收集、清洗、标注这些苦力活。有了GPT-4等这样的模型,合成出来的数据集比人工标注的更全面、更多样,速度还快得多。这些数据可以用来给LLM系统做基准测试,配合评测指标效果更好。
本文会教你用LLM生成合成数据集的全套方法(比如用来评测RAG管道)。内容包括:
什么是用LLM生成合成数据?
用LLM生成合成数据,就是让LLM创造人工数据。这些数据通常用来训练、微调,甚至评测LLM本身。生成合成数据集不仅比找公开数据快,比人工标注便宜,质量还更高、多样性更好,这对LLM红队测试也很重要。
整个流程从创建合成查询开始。这些查询用知识库里的上下文(通常是文档)作为参考生成。生成的查询会被多次“演化”,变得更复杂、更真实。把这些查询和原始上下文结合起来,就成了最终的合成数据集。虽然可选,但建议给每个查询-上下文对生成一个目标标签,作为LLM系统针对这个查询的预期输出。

生成评测用的合成数据集,主要有两种方法:从模型自己的输出做自我改进,或者从更强的模型做蒸馏。
- 自我改进:模型从自己的输出迭代生成数据,不依赖外部资源
- 蒸馏:用更强的模型给弱模型生成合成数据做评测
自我改进方法(像Self-Instruct或SPIN)受限于模型自身能力,可能放大偏见和错误。蒸馏技术只受限于能用到的最好模型,能保证最高质量的生成结果。
从知识库生成数据
合成数据生成的第一步,是从上下文列表创建合成查询,这些上下文直接来自知识库。说白了,上下文就是LLM应用的理想检索内容,就像预期输出是LLM实际输出的参考答案一样。
想立即上手的话,下面展示如何用DeepEval(开源LLM评测框架)生成高质量合成数据:
构建上下文
上下文生成时,知识库里的文档会用token分割器切成块(chunks)。然后随机选一个块,再根据相似度检索和分组其他块。

相似度可以用这几种方法计算:
- 用相似度或距离算法,比如余弦相似度
- 用知识图谱
- 直接用LLM本身(虽然不太现实,但最准确)
- 用聚类技术识别模式
- 用机器学习模型基于特征预测分组
不管哪种方法,目标都一样:有效聚合相似的信息块。
想让这些分组发挥作用,最好在上下文生成时复制应用的检索器逻辑。token分割方法、块大小、块重叠这些细节都要仔细考虑。
这样对齐能保证合成数据的表现符合应用预期,避免因检索器复杂度不同导致结果偏差。
从上下文生成合成输入
上下文准备好后,下一步就是生成合成输入。这个方法反转了标准检索操作——不是根据输入找上下文,而是基于预设上下文创建输入。这样能确保每个合成输入都直接对应一个上下文,相关性和准确性都更高。
另外,这些上下文还能选择性地用来生成预期输出,和合成输入对齐。

这种非对称方法能让所有组件——输入、输出、上下文——完美同步。
过滤合成数据
开始演化新生成的数据集前,必须做彻底的质量检查,别在本来就有问题的输入上浪费时间。这步很关键,既能避免资源浪费,又能确保最终数据集只包含高质量样本。
过滤发生在两个关键阶段:上下文生成时,以及从上下文生成合成输入时。
上下文过滤
上下文生成时,可能随机抽到质量差的数据块。知识库里常有复杂结构或多余空格,切分后会变得难以理解。用LLM做评判是识别和过滤这些低质量上下文的好办法。

可以自定义评测和过滤标准,这里给些基础准则参考:
- 清晰度:信息是否清楚易懂
- 深度:有没有详细分析和原创见解
- 结构:内容组织和逻辑是否清晰
- 相关性:跟主题的关联度
- 精确度:准确性和细节把控
- 新颖性:内容是否独特原创
- 简洁性:表达是否简洁高效
- 影响力:对读者的潜在影响
过滤完低质量块后,还要确保剩下的块足够相似。这需要二次过滤,剔除相似度不达标的块。
这种结构化过滤能确保只有高质量、相关、有用的上下文进入下一阶段。
输入过滤
第二个过滤阶段关注从上下文生成的合成输入。这步很重要,因为就算上下文质量好,也可能生成不合格的输入。

评判合成输入可以用这些标准:
- 自包含性:输入是否完整,能否独立运作
- 清晰度:输入是否清楚传达意图,避免误解
- 一致性:输入是否和上下文在主题和事实上一致
- 相关性:输入是否直接关联预期任务或查询
- 完整性:输入是否包含所有必要细节
用这些标准能确保合成输入不仅质量高,还完美适配预期应用。
风格化合成数据
最后,可能需要把查询定制成特定主题,自定义输入输出格式来适应具体用例。
比如,应用涉及文本转SQL,输出就该准确反映SQL语句。如果是评测型LLM场景,用带“score”和“reason”键的JSON格式可能更合适。
建议在初始生成、任何演化变更时,以及最终输出生成后都应用特定风格。初始生成后重新审视风格很重要,因为合成查询演化可能改变最初的风格设定。
首轮后的风格调整程度取决于你对最终产品的控制要求和预算考虑。
数据的适者生存
来说说什么是数据演化,以及为什么它对用LLM生成合成数据这么重要。数据演化最早由微软的Evol-Instruct提出,通过提示工程迭代增强现有查询集,生成更复杂更多样的查询。这步决定了数据集的质量、全面性、复杂性和多样性,也是合成数据优于公开或人工标注数据集的关键。
微软团队做了个实验:175条人工查询 → 25万条指令,这就是数据演化的威力。数据演化有三种类型:
- 深度演化:把简单指令扩展成更详细复杂的版本
- 广度演化:产生新的多样化指令,丰富数据集
- 淘汰演化:移除效果差或失败的指令

深度演化有多种玩法,比如让输入更复杂、增加推理需求、或者添加多个步骤完成任务。每种方法都能提升生成数据的复杂度。
深度演化能创建细致入微的高质量查询,广度演化能增强多样性和全面性。多次演化每个查询或指令,就能增加复杂性,产生丰富多面的数据集。
举个例子:原始查询 —— 1+1等于多少?
深度演化后:演化查询 —— 什么情况下1+1不等于2?
这显然比普通的1+1更复杂更真实。下一节会展示如何在生成合成数据集时实际运用这些演化方法。
分步指南:用LLM生成合成数据
开始前,先看看要构建的数据合成器架构:

可以看到有五个主要步骤:
- 文档分块
- 上下文生成
- 查询生成
- 数据演化
- 标签/预期输出生成(可选)
想立即上手的话,这个流程已经在DeepEval中开源了,只需2行代码就能准备好合成数据集生成,还支持过滤和风格化(稍后展示)。
想了解工作原理的话,继续往下看。
1. 文档分块
第一步是给文档分块。顾名思义,就是把文档切成更小、有意义的“块”。这样能把大文档拆解成可管理的子文档,同时保持上下文完整。分块还能让超过嵌入模型token限制的文档生成嵌入。
这步很关键,能帮你找出语义相似的块,基于共享上下文生成查询或任务。
分块策略有好几种,比如固定大小分块和上下文感知分块。还可以调整超参数,像字符大小和块重叠。下面例子用基于token的分块,字符大小1024,无重叠。分块方法:
2. 数据合成流程详解
DeepEval 的数据合成流程包含四个核心步骤:文档分块与嵌入、上下文生成、查询生成以及查询演化。
1. 文档分块与嵌入
首先,将原始文档(如PDF)分割成语义连贯的文本块,并为每个块生成向量嵌入,以捕获其语义信息。
# Step 1. Chunk Documents
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import TokenTextSplitter
text_splitter = TokenTextSplitter(chunk_size=1024, chunk_overlap=0)
loader = PyPDFLoader("chatbot_information.pdf")
raw_chunks = loader.load_and_split(text_splitter)
分块完成后,将每个块转换为嵌入向量,并与原始内容结合,形成 Chunk 对象列表。
from langchain_openai import OpenAIEmbeddings
embedding_model = OpenAIEmbeddings(api_key="...")
content = [rc.page_content for rc in raw_chunks]
embeddings = embedding_model.embed_documents(content)
2. 上下文生成
生成上下文时,首先随机选择一个数据块作为“锚点”,用于寻找语义上相关的其他块。
# Step 2: Generate context by selecting chunks
import random
reference_index = random.randint(0, len(embeddings) - 1)
reference_embedding = embeddings[reference_index]
contexts = [content[reference_index]]
随后,通过计算余弦相似度,将与锚点块相似度超过设定阈值的块纳入上下文,从而构建一个围绕同一主题的、信息丰富的上下文集合。
similarity_threshold = 0.8
similar_indices = []
for i, embedding in enumerate(embeddings):
product = np.dot(reference_embedding, embedding)
norm = np.linalg.norm(reference_embedding) * np.linalg.norm(embedding)
similarity = product / norm
if similarity >= similarity_threshold:
similar_indices.append(i)
for i in similar_indices:
contexts.append(content[i])
此步骤至关重要,它能通过整合多个来源的信息,增强查询的鲁棒性,并为后续的查询生成提供更细致、全面的背景信息。
3. 查询生成
利用大语言模型(LLM),基于上一步生成的上下文来创建初始查询或任务。通过结构化提示词,引导模型生成一个包含 input 键(即问题或陈述)的 JSON 对象列表。
# Step 3. Generate a series of queries for similar chunks
from langchain_openai import ChatOpenAI
prompt = f"""
I want you act as a copywriter. Based on the given context,
which is list of strings, please generate a list of JSON objects
with a `input` key. The `input` can either be a question or a
statement that can be addressed by the given context.
contexts:
{contexts}
"""
query = ChatOpenAI(openai_api_key="...").invoke(prompt)
这些初始查询构成了最终评测数据集的基础。
4. 查询演化
最后一步是对初始查询进行演化,以增加问题的多样性和复杂性。通过应用不同的“演化模板”,可以生成多种类型的查询。DeepEval 主要关注三类演化:
* 多上下文理解:要求模型综合多个上下文块的信息进行回答。
* 多步推理:设计需要多个逻辑步骤才能解决的问题。
* 假设场景:基于给定上下文,提出“如果…会怎样”类型的问题。
通过这一流程,DeepEval 能够自动化、低成本地合成高质量、多样化的评测数据,为 LLM 的评估提供了坚实的基础。

查询演化模板与步骤
每个演化模板都对输出有特定约束。根据您希望评测查询在最终数据集中的呈现方式,可以自由调整这些模板。通过多次随机选择模板来演化原始查询,可以生成多样化的数据。
# 演化提示词模板
multi_context_template = f"""I want you to rewrite the given `input` so that it requires readers to use information from all elements in `Context`.
1. `Input` should require information from all `Context` elements.
2. `Rewritten Input` must be concise and fully answerable from `Context`.
3. Do not use phrases like 'based on the provided context.'
4. `Rewritten Input` should not exceed 15 words.
Context: {context}
Input: {original_input}
Rewritten Input:"""
reasoning_template = f"""I want you to rewrite the given `input` so that it explicitly requests multi-step reasoning.
1. `Rewritten Input` should require multiple logical connections or inferences.
2. `Rewritten Input` should be concise and understandable.
3. Do not use phrases like 'based on the provided context.'
4. `Rewritten Input` must be fully answerable from `Context`.
5. `Rewritten Input` should not exceed 15 words.
Context: {context}
Input: {original_input}
Rewritten Input:"""
hypothetical_scenario_template = f"""I want you to rewrite the given `input` to incorporate a hypothetical or speculative scenario.
1. `Rewritten Input` should encourage applying knowledge from `Context` to deduce outcomes.
2. `Rewritten Input` should be concise and understandable.
3. Do not use phrases like 'based on the provided context.'
4. `Rewritten Input` must be fully answerable from `Context`.
5. `Rewritten Input` should not exceed 15 words.
Context: {context}
Input: {original_input}
Rewritten Input:"""
# 步骤 4:演化查询
example_generated_query = "How do chatbots use natural language understanding?"
context = contexts
original_input = example_generated_query
evolution_templates = [multi_context_template, reasoning_template, hypothetical_scenario_template]
# 设定演化步数
num_evolution_steps = 3
# 执行随机演化步骤的函数
def evolve_query(original_input, context, steps):
current_input = original_input
for _ in range(steps):
# 从列表中随机选择一个模板
chosen_template = random.choice(evolution_templates)
# 用当前上下文和输入替换占位符
evolved_prompt = chosen_template.replace("{context}", str(context)).replace("{original_input}", current_input)
# 使用“Rewritten Input”部分更新当前输入
current_input = ChatOpenAI(openai_api_key="...").invoke(evolved_prompt)
return current_input
# 通过随机选择演化类型来演化输入
evolved_query = evolve_query(original_input, context, num_evolution_steps)
通过上述过程即可获得最终演化的查询。重复此过程可以生成更多查询,从而进一步完善数据集。为了进行评测,需要将这些输入查询和上下文正确格式化为适合的测试框架。
5. 预期输出生成
此步骤为可选,但强烈建议为每个演化查询生成预期输出。相较于从头创建,人工评测员修改和标注预期输出可以节省大量时间和精力。
Step 5. Generate Expected Output
最后一步是生成预期输出。这需要将演化后的查询和上下文输入给LLM,并要求其生成一个与上下文事实相符的答案。
# Define prompt template
expected_output_template = f"""I want you to generate an answer for the given `input`. This answer has to be factually aligned to the provided context.
Context: {context}
Input: {evolved_query}
Answer:"""
# Fill in the values
prompt = expected_output_template.replace("{context}", str(context)).replace("{evolved_query}", evolved_query)
# Generate expected output
expected_output = ChatOpenAI(openai_api_key="...").invoke(prompt)
至此,我们已获得所有必要组件:演化查询、上下文和预期输出。接下来,将它们组合成合成数据集中的一条记录。
from pydantic import BaseModel
from typing import Optional, List
class SyntheticData(BaseModel):
query: str
expected_output: Optional[str]
context: List[str]
synthetic_data = SyntheticData(
query=evolved_query,
expected_output=expected_output,
context=context
)
# Simple implementation of synthetic dataset
synthetic_dataset = []
synthetic_dataset.append(synthetic_data)
现在,只需重复步骤1至5,即可生成规模合理的合成数据集。之后,这个数据集就可以直接用于评测您的LLM系统。
总结
利用LLM生成合成数据集,其核心优势在于能够快速、低成本地获取大量数据。然而,原始生成的数据往往存在模式单一、重复性高的问题,难以真实反映现实世界的数据分布,从而限制了其实际应用价值。
本文介绍的方法旨在解决这一痛点。其核心流程是:首先从文档中选取相关的上下文片段,然后基于这些上下文生成能够有效测试目标LLM系统的查询。此外,我们还探讨了通过“数据演化”技术,使生成的查询更加多样化和贴近真实场景。
如果您希望从头构建一个高质量的数据合成器,本文提供的思路和步骤将是一个实用的起点。
- Qwen3-Max-Preview实测:非思考模型新王者诞生
- LLM文本摘要评测实战指南
- 姚顺雨成名作“智能体评测集τ-bench”上手指南
- DeepSeek-V3.2-Exp非思考模式实测
- DeepSeek-V3.2-Exp思考模式实测:开源模型王者
- 深度拆解:为什么通用 Agent 的下一站是 Agentic Browser?
- 每月AI大模型更新速递(25年9月)
- 每周AI大模型更新速递10.1~10.12
- 大模型智能体评测综述【Benchmarks解读】
- 智谱GLM-4.6硬刚豆包、DeepSeek:速度快40%,为何还是输了?
- 腾讯混元turbos实测:Agent能力暴跌25.7%,2元成本却让全行业沉默了
- 做好AI Agent最重要的是什么?Uber等大厂600人现场揭秘:95%失败的真相!
关于大模型评测诊断NoneLinear
https://nonelinear.com
- 评测榜单——已囊括300+大模型、300+评测维度,每周更新大模型评测结果
- 模型选型降本——一键选出最合适模型,效果更优,成本降低50%以上
- 智能模型超市——统一API,一键调用全球所有大模型,GPT5 / Gemini2.5 / Claude4.5免费体验,高并发,自动故障切换,实时监控模型调用效果

关注“鲸栖”小程序,掌握最新AI资讯
本文来自网络搜集,不代表鲸林向海立场,如有侵权,联系删除。转载请注明出处:http://www.itsolotime.com/archives/14691
