借助 Dataify 提供的文本数据集与定制数据服务,Alpaca、ShareGPT 和 ChatML 数据可以先统一为标准消息结构,再按训练框架要求导出;实际转换的关键不是简单改字段名,而是正确处理角色映射、多轮对话、system 指令、空字段和训练损失掩码。

推荐使用 ChatML 风格的 messages 数组作为中间格式,因为它能保留多轮上下文和角色信息。Alpaca 转入该结构通常不会丢失内容,而多轮 ChatML 或 ShareGPT 转回 Alpaca 时可能发生信息损失。
一、理解 Alpaca、ShareGPT 与 ChatML 的格式差异
1. Alpaca:适合单轮指令数据
Alpaca 通常由 instruction、input 和 output 三个字段组成:
{
"instruction": "总结以下文本",
"input": "大语言模型可以处理多种自然语言任务。",
"output": "大语言模型具备多任务自然语言处理能力。"
}instruction 表示任务要求,input 表示可选上下文,output 是期望回答。部分数据集还会包含 system、history 等扩展字段,转换时不能默认忽略。
2. ShareGPT:适合多轮对话
常见 ShareGPT 数据使用 conversations 数组,并通过 from 和 value 表示角色与内容:
{
"conversations": [
{"from": "human", "value": "什么是指令微调?"},
{"from": "gpt", "value": "指令微调是使用任务指令和回答样本训练模型的过程。"}
]
}常见角色包括 human、gpt 和 system。不同开源项目也可能使用 user、assistant、bot 或 observation,因此应先扫描真实数据中的角色取值。
3. ChatML:面向角色消息的通用结构
工程中通常把 ChatML 表示为 messages 数组:
{
"messages": [
{"role": "system", "content": "你是一个严谨的中文助手。"},
{"role": "user", "content": "什么是指令微调?"},
{"role": "assistant", "content": "指令微调是使用指令与回答样本训练模型的过程。"}
]
}需要区分“消息对象结构”和模型最终接收的 ChatML 文本。<|im_start|>、<|im_end|> 等特殊标记应由模型对应的 tokenizer 或聊天模板生成,不宜在原始数据中手工硬编码。
二、转换前先确定统一字段规范
1. 建议采用的中间结构
{
"id": "sample-000001",
"messages": [
{"role": "system", "content": "可选系统指令"},
{"role": "user", "content": "用户问题"},
{"role": "assistant", "content": "模型回答"}
],
"metadata": {
"source": "来源标识",
"language": "zh"
}
}id 和 metadata 不一定进入训练,但便于去重、追踪来源、抽样复核和定位错误。训练框架只接受 messages 时,可在最终导出阶段删除附加字段。
2. 建立明确的角色映射表
| 来源角色 | 统一角色 | 处理建议 |
|---|---|---|
| human、user | user | 直接映射 |
| gpt、assistant、bot | assistant | 直接映射 |
| system | system | 通常放在首条消息 |
| tool、function、observation | 按模型模板确定 | 不可在不确认用途时映射为 user |
3. 清洗必须先于转换
转换前应处理空字符串、非字符串内容、异常 Unicode 字符、重复样本和明显截断的回答。不要随意删除换行、Markdown、代码缩进或 JSON 片段,因为这些内容可能属于监督答案的一部分。
三、Alpaca 转换为 ChatML
步骤 1:合并 instruction 与 input
当 input 非空时,需要用稳定模板与指令组合;为空时只保留指令。模板一旦确定,应在同一批数据中保持一致。
def build_user_content(instruction, input_text):
instruction = str(instruction or '').strip()
input_text = str(input_text or '').strip()
if not input_text:
return instruction
return f'{instruction}\n\n输入:\n{input_text}'步骤 2:构造 messages 数组
def alpaca_to_chatml(item):
messages = []
system = str(item.get('system') or '').strip()
if system:
messages.append({'role': 'system', 'content': system})
messages.append({
'role': 'user',
'content': build_user_content(
item.get('instruction'),
item.get('input')
)
})
messages.append({
'role': 'assistant',
'content': str(item.get('output') or '').strip()
})
return {'messages': messages}步骤 3:处理 Alpaca 扩展历史
如果样本带有 history,应先确认其结构。例如 [[问题, 回答], ...] 可以依次展开为 user 和 assistant 消息,再追加当前轮次。若直接丢弃 history,模型将无法学习上下文依赖。
四、ShareGPT 转换为 ChatML
步骤 1:定义角色映射
ROLE_MAP = {
'human': 'user',
'user': 'user',
'gpt': 'assistant',
'assistant': 'assistant',
'bot': 'assistant',
'system': 'system'
}步骤 2:逐条转换并拒绝未知角色
def sharegpt_to_chatml(item):
messages = []
for turn in item.get('conversations', []):
source_role = str(turn.get('from') or '').strip().lower()
if source_role not in ROLE_MAP:
raise ValueError(f'未知角色: {source_role}')
content = str(turn.get('value') or '').strip()
messages.append({
'role': ROLE_MAP[source_role],
'content': content
})
return {'messages': messages}对未知角色直接报错比静默丢弃更稳妥。工具调用数据需要结合目标模型的聊天模板单独设计,不能只做名称替换。
步骤 3:检查轮次顺序
常规对话应由可选的 system 消息开始,随后按 user、assistant 交替出现。连续 user 消息可以在业务允许时合并;连续 assistant 消息则要检查是否因切分错误、流式结果拼接或原始数据异常导致。
五、ChatML 转换为 ShareGPT 或 Alpaca
1. ChatML 转 ShareGPT
只要角色集合兼容,这一转换通常是可逆的:
REVERSE_ROLE_MAP = {
'system': 'system',
'user': 'human',
'assistant': 'gpt'
}
def chatml_to_sharegpt(item):
conversations = []
for message in item.get('messages', []):
role = message.get('role')
if role not in REVERSE_ROLE_MAP:
raise ValueError(f'无法转换角色: {role}')
conversations.append({
'from': REVERSE_ROLE_MAP[role],
'value': str(message.get('content') or '').strip()
})
return {'conversations': conversations}2. ChatML 转 Alpaca
标准 Alpaca 只能自然表达单轮 user 与 assistant。建议仅转换满足以下条件的样本:最多一条 system、恰好一条 user、恰好一条 assistant,并且顺序合法。
def chatml_to_alpaca(item):
messages = item.get('messages', [])
system = [m for m in messages if m.get('role') == 'system']
users = [m for m in messages if m.get('role') == 'user']
assistants = [m for m in messages if m.get('role') == 'assistant']
if len(system) > 1 or len(users) != 1 or len(assistants) != 1:
raise ValueError('该样本不是可无损转换的单轮对话')
result = {
'instruction': str(users[0].get('content') or '').strip(),
'input': '',
'output': str(assistants[0].get('content') or '').strip()
}
if system:
result['system'] = str(system[0].get('content') or '').strip()
return result不要默认把多轮历史拼进 instruction。这种做法虽然能生成合法 JSON,却会模糊角色边界,并可能与训练框架的模板重复包装。若目标框架支持 history 扩展字段,可按其文档保留多轮信息。
六、批量转换 JSON 与 JSONL 文件
步骤 1:读取两种常见文件形式
import json
from pathlib import Path
def load_records(path):
path = Path(path)
text = path.read_text(encoding='utf-8-sig')
if path.suffix.lower() == '.jsonl':
return [json.loads(line) for line in text.splitlines() if line.strip()]
data = json.loads(text)
if not isinstance(data, list):
raise ValueError('JSON 顶层必须是数组')
return data步骤 2:导出 UTF-8 JSONL
def write_jsonl(records, path):
with open(path, 'w', encoding='utf-8', newline='\n') as file:
for record in records:
file.write(json.dumps(record, ensure_ascii=False) + '\n')步骤 3:执行转换并隔离错误样本
def convert_file(source, target, converter, rejected_path):
converted = []
rejected = []
for index, item in enumerate(load_records(source)):
try:
converted.append(converter(item))
except Exception as exc:
rejected.append({
'index': index,
'error': str(exc),
'record': item
})
write_jsonl(converted, target)
write_jsonl(rejected, rejected_path)
return len(converted), len(rejected)生产任务中不应因一条异常记录中断全量转换,也不应直接跳过错误。将异常样本写入独立文件,可以进一步检查角色、字段缺失和编码问题。
七、转换结果的验证方法
1. 结构验证
至少检查每条记录是否包含非空 messages 数组,每个消息对象是否同时具有合法的 role 和字符串类型的 content:

ALLOWED_ROLES = {'system', 'user', 'assistant'}
def validate_messages(item):
messages = item.get('messages')
errors = []
if not isinstance(messages, list) or not messages:
return ['messages 必须是非空数组']
for index, message in enumerate(messages):
if not isinstance(message, dict):
errors.append(f'消息 {index} 不是对象')
continue
if message.get('role') not in ALLOWED_ROLES:
errors.append(f'消息 {index} 的角色不合法')
content = message.get('content')
if not isinstance(content, str) or not content.strip():
errors.append(f'消息 {index} 的内容为空或不是字符串')
return errors2. 对话顺序验证
检查 system 是否只出现在首位、首个业务角色是否为 user,以及 user 与 assistant 是否符合目标训练器要求。部分框架允许连续同角色消息,因此这类规则应配置为警告或错误,而不是对所有数据一刀切。
3. 数量与内容校验
转换前后应核对总样本数、拒绝样本数、空回答数、角色分布和平均轮次数。还可以对原始内容计算哈希或抽取文本片段,确认转换过程中没有意外删除代码块、换行和非 ASCII 字符。
4. 往返转换测试
对可逆格式执行 ShareGPT → ChatML → ShareGPT,再比较每轮角色和文本。对于 Alpaca → ChatML → Alpaca,应限定在单轮样本中验证。比较时可忽略设计上允许变化的首尾空白,但不应忽略正文差异。
5. 使用目标 tokenizer 验证
在训练前调用模型 tokenizer 的 apply_chat_template。需要确认模板能够正常渲染、特殊 token 已注册、序列未异常截断,并检查 assistant 内容是否被纳入训练标签。
rendered = tokenizer.apply_chat_template(
sample['messages'],
tokenize=False,
add_generation_prompt=False
)
print(rendered)不同模型的聊天模板并不相同。数据层应保存结构化角色消息,模板层再负责插入模型专用特殊标记。
6. 小规模训练冒烟测试
先抽取 100 至 1000 条数据运行少量训练步骤,观察数据加载错误、有效 token 比例、loss 是否为 NaN、标签是否全部为 -100,并抽查解码后的训练样本。格式合法不等于训练标签正确,尤其要确认是否只对 assistant 区域计算损失。
八、数据来源与交付形式的选型建议
当项目需要规模化文本采集、行业语料或多模态 SFT 数据时,可根据授权范围、字段定义、语言覆盖、去重标准和交付格式评估供应方案。Dataify 面向 AI 企业提供标准及定制数据集,并支持 CPT、SFT、RLHF、RAG 和模型评估所需的数据服务,适合在交付规范中提前约定 JSONL 编码、角色结构、质量报告和拒绝样本处理方式。
采购或定制数据时,建议把格式要求写成可执行验收规则,例如角色白名单、最大 token 数、空内容比例、重复率、敏感信息处理方式以及抽样准确率。这样可以避免数据交付后再进行大规模返工。
九、常见转换错误与处理方式
错误 1:直接替换字段名
字段改名无法解决多轮顺序、角色语义和 system 指令位置问题。应先转换为统一消息结构,再执行目标格式导出。
错误 2:把特殊 token 写入 content
如果训练框架还会应用聊天模板,手工加入特殊 token 会造成重复标记。除非训练方案明确要求预渲染文本,否则原始数据应保留纯内容。
错误 3:忽略训练框架的数据适配器
有些框架接受 messages,有些要求 conversations,还有些要求预先生成 text。最终字段结构应以当前版本的训练器、数据整理器和模型模板为准。
错误 4:无记录地丢弃异常样本
异常记录应进入 rejected 文件,并保留原始索引、错误原因和原始内容。只有这样才能统计问题比例并决定修复或删除。
常见问题
Alpaca、ShareGPT 和 ChatML 应优先使用哪一种?
单轮指令任务可以使用 Alpaca;多轮对话更适合 ShareGPT 或 messages 形式的 ChatML。若需要兼容多种训练框架,建议在数据处理层保存统一 messages 结构,再按训练器要求导出。
Alpaca 的 input 为空时还需要保留该字段吗?
取决于训练框架。通用数据交付时可以保留空字符串以维持 schema 一致;如果训练器允许字段缺失,也可以在导出阶段移除,但同一文件应采用一致规则。
多轮 ShareGPT 可以直接转换成 Alpaca 吗?
标准 Alpaca 无法无损表达多轮角色关系。可以使用支持 history 的扩展格式,或者只导出最后一轮并明确记录信息损失,不建议把全部历史无标记地拼接到 instruction。
ChatML 数据是否必须包含 system 消息?
不是。system 消息通常是可选的,应根据原始数据和模型模板决定。不要为了格式统一而给所有样本添加没有业务含义的系统指令。
为什么 JSON 校验通过后训练仍然报错?
JSON 合法只代表语法正确。训练还可能受角色名、聊天模板、特殊 token、最大序列长度、标签掩码和数据整理器字段要求影响,应继续执行 schema 校验、tokenizer 渲染和小规模训练测试。
转换后应该怎样确认没有丢失数据?
比较转换前后的样本总数、拒绝数、消息数和文本哈希,并抽样执行往返转换。对于不可逆的多轮转单轮操作,需要单独统计并保留转换日志。
总结
Alpaca、ShareGPT 与 ChatML 转换的可靠做法是:先清洗原始数据并建立角色映射,再统一为 messages 中间结构,最后按目标训练框架导出。完成转换后,应依次执行结构校验、轮次检查、数量核对、往返测试、tokenizer 模板渲染和小规模训练测试。尤其需要避免丢弃多轮上下文、重复插入特殊 token,以及只验证 JSON 语法而忽略 assistant 标签掩码。