3、常见微调数据格式
前面看到的文件名以 .jsonl 结尾,内容又被称为 ShareGPT,后面还会出现 Chat Template。它们处理的不是同一件事:
| 要解决的问题 | 对应名称 | 本课程中的例子 |
|---|---|---|
| 多条记录怎样放进文件 | JSONL | 一行保存一条完整的 JSON 记录 |
| 每条记录怎样保存指令、输入和答案 | Alpaca、ShareGPT | 三个独立字段,或一组按角色排列的消息 |
| 消息怎样组织成模型熟悉的输入 | Chat Template(对话模板) | 加入用户、助手的边界标记,第 6 节展开 |
因此,一个文件可以同时是“JSONL 文件”和“ShareGPT 数据”,两者并不冲突。先看一条记录的两种常见写法。
| 格式 | 一条数据怎样保存 | 更适合的情况 |
|---|---|---|
| Alpaca | instruction、input、output | 单轮的“指令 + 输入 + 答案”任务 |
| ShareGPT | 一组按角色排列的消息 | 用统一的消息结构保存单轮或多轮对话 |
3.1 Alpaca 数据格式
Alpaca 格式会把任务说明、具体输入和标准答案拆开保存。仍用第 1 节的图书馆教学示例:
{
"instruction": "请提取关键词,只输出关键词,并使用英文分号分隔。",
"input": "市图书馆周末开设儿童阅读课,读者可通过公众号预约。",
"output": "市图书馆;儿童阅读课;公众号预约"
}instruction 是任务要求,input 是这次要处理的文章,output 是参考答案。这种拆法直观,适合单轮任务。
3.2 ShareGPT 数据格式
同一条教学样本也可以按本课程采用的 ShareGPT 风格保存:
{
"conversations": [
{
"role": "user",
"content": "市图书馆周末开设儿童阅读课,读者可通过公众号预约。\n请提取关键词,只输出关键词,并使用英文分号分隔。"
},
{
"role": "assistant",
"content": "市图书馆;儿童阅读课;公众号预约"
}
]
}任务和答案都没有改变,只是把指令与文章放进 user.content,把答案放进 assistant.content。最外层的 conversations 是消息列表:
conversations
├── 第 1 条:role = user → 待抽取的文本和任务指令
└── 第 2 条:role = assistant → 标准关键词答案上面为了讲解而展开换行;保存为 JSONL 时,整个对象要放在一条物理行中,消息内部的换行用 \n 表示。不要把展开后的十几行当作十几条训练样本。
如果以后有多轮任务,也可以在同一条样本里继续追加消息:
user1 → assistant1 → user2 → assistant2本课程的关键词数据是一问一答。后面使用的清洗脚本也按这种单轮结构检查;换成多轮数据时,需要相应调整检查逻辑,不能直接套用。
字段名不一定永远叫 conversations、role 和 content。有的数据把用户写成 human,有的数据把消息列表写成 messages。这不是数据一定有问题,而是训练工具需要一份“字段对照表”才能正确读取它。第 31 章第 6.2 节会在 dataset_info.json 中填写这份对照表。
Alpaca 和 ShareGPT 用来整理样本;训练工具读取这些样本后,还要通过与模型匹配的对话模板和分词器准备模型输入。第 6 节会展示转换前后的区别。
<span id="tool-calling-data"></span>
3.3 从单轮问答到工具调用(选读)
关键词任务只需要“读文章 → 输出关键词”。如果希望助手查询儿童阅读课还有没有名额,它还需要判断信息是否齐全、请求查询,并根据查询结果回答。训练样本也要包含这些可观察的步骤。
<details> <summary>进阶阅读:从澄清到工具返回的一条完整样本</summary>下面是虚构的教学示意,用于理解一条多轮样本,不是已执行的工具记录,也不是可直接上传训练的文件。本例提供 query_reading_class 工具,只查询市图书馆儿童阅读课的余位,接收两个参数:date 使用 YYYY-MM-DD,time_slot 使用 morning(上午)或 afternoon(下午)。
| 顺序 | 谁提供内容 | 消息或动作示意 |
|---|---|---|
| 1 | 用户 | 儿童阅读课还有名额吗? |
| 2 | 助手 | 你想查询哪一天、上午还是下午的场次? |
| 3 | 用户 | 2026 年 9 月 12 日上午。 |
| 4 | 助手 | 请求 query_reading_class,参数为 date="2026-09-12"、time_slot="morning" |
| 5 | 工具 | 程序执行查询后返回 remaining=6,表示还有 6 个名额 |
| 6 | 助手 | 查询结果显示,2026 年 9 月 12 日上午的儿童阅读课还有 6 个名额。 |
这里最关键的是第 4、5 步的区别:模型提出调用请求,程序负责实际执行,再把结果交还给模型。 助手不能自己写出一个 remaining=6,就当作查到了真实余位。保存整条消息链及工具说明,才有条件让模型学习“何时澄清、怎样调用、如何使用结果”。
准备这类数据时,还需要覆盖不同情况:
| 情况 | 应有的示范 |
|---|---|
| 用户一开始就给齐日期与场次 | 直接填写已有信息,避免重复询问 |
| 用户已经贴出通知,只要求提取关键词 | 根据已给文本回答,不为使用工具而调用工具 |
| 查询返回“场次不存在”或暂时失败 | 按实际结果说明情况;若允许重试,遵守次数和退出条件 |
| 用户信息不足 | 先澄清,不猜测日期或场次 |
落到训练文件时,还要按所用工具核对消息字段、工具参数说明(schema)、调用与返回的对应关系,以及哪些助手消息参与监督。可参考 SFT 工具调用数据说明。本章的单轮关键词清洗脚本不能直接校验这种多轮数据,字段映射和聊天模板也需要相应验证。
如果用另一个模型起草轨迹,调用结果应由真实执行或明确标注的模拟环境核验,不能把生成的成功描述当作执行证据。后续评估还应分别检查工具是否选对、参数是否正确、结果是否被正确使用,见第 32 章。只训练关键词抽取,并不能证明模型已经学会这些行为。
</details>继续本课主线时,仍使用单轮关键词数据;下面的文档问答也是独立扩展,不把三种任务混到同一次练习中。
<span id="_33-实操:把自己的文档做成问答训练数据"></span> <span id="easy-dataset-qa"></span>