当 AI 的表达风格反复不符合要求时,人们很容易想到“训练一个自己的模型”。但如果任务规则没有定义清楚,参考答案前后矛盾,或根本没有独立测试题,上传更多材料也不能说明模型会变好。理解微调,应该先从任务、示范数据和验证方式开始,而不是先支付训练费用。
本文介绍监督微调的基本思路,用四条原创通知改写样本,完成一次本地 JSONL 数据练习:写输入输出、分开训练与验证、检查格式和重复,再判断是否值得进入真正的训练流程。示例数量仅用于学习文件结构,不足以发起本文参考服务的训练任务;没有上传文件、调用模型或创建收费任务。
一、微调主要在改变什么
监督微调通常使用一组输入与理想输出,让模型通过训练调整参数,更符合特定任务中的表现要求。它适合讨论的是稳定的表达、格式或行为模式,而不是把任意资料塞进去,期待以后准确背出所有细节。
普通提示词是在当前请求里交代要求;Few-shot 把少量示范放在请求上下文中;RAG 先检索外部资料,再把相关内容交给模型回答;微调则涉及单独的训练过程。它们可以组合使用,不需要把某一种技术当成所有问题的答案。
例如,活动时间每周变化,首先应考虑提供最新资料或检索机制。若是已经给足事实,但模型总把简短通知扩写成营销文案,可以先改进提示词、补示例并评测;只有仍有稳定问题,且有足够高质量示范时,才进一步评估微调。
事实更新与行为学习是两个问题。 微调后的模型也可能答错,需要提供必要背景与持续验收。它不会因为文件曾经上传过,就自动拥有可信、随时更新的业务知识库。
二、先定义一个能人工判断对错的任务
练习任务是“把口语化通知改成中性、简洁的书面表达”。必须保留原有事实,不增加优惠、赔偿、办理承诺或完成状态。输出一段通知,不加开场解释,不改人物、日期、金额和否定条件。
这是一套本文人为制定的改写约定。比如输入“明天仓库不开门,周五恢复”,输出可以是“仓库明日暂停开放,周五恢复开放。”不能改成“我们会在周五优先处理所有订单”,因为原文没有提供这个承诺。
准备样本时先让人写出参考答案,再检查每条输出为什么合格。不要把某次模型的草稿不加审校地当成训练标签。如果要求是“简洁”,就具体说明保留哪些信息、删除哪些口头语,而不是只给一个无法复查的主观评价。
三、把四条示范分成两个本地文件
JSONL 是逐行保存 JSON 的文本格式,每个物理行是一条完整记录。本例采用由 user 输入与 assistant 参考输出组成的简化消息结构,便于检查;实际服务还可能支持其他字段和对话方式,应以对应接口文档为准。
新建空文件夹,创建 train-demo.jsonl,以 UTF-8 保存下面两行。注意每条记录必须独占一行,不要把示例套进最外层的数组。
{"messages":[{"role":"user","content":"明天仓库不开门,周五恢复。"},{"role":"assistant","content":"仓库明日暂停开放,周五恢复开放。"}]}
{"messages":[{"role":"user","content":"报名截止到周三18点,过了就不收了。"},{"role":"assistant","content":"报名截止时间为周三18点,逾期不再受理。"}]}再创建 valid-demo.jsonl,保存另外两行,后续用于检查未参与训练的输入,不要混进训练文件。
{"messages":[{"role":"user","content":"这次借用只限一天,得当天还回来。"},{"role":"assistant","content":"本次借用期限为一天,须当日归还。"}]}
{"messages":[{"role":"user","content":"周六换到二楼开会,时间还是下午三点。"},{"role":"assistant","content":"周六会议地点调整为二楼,时间仍为下午三点。"}]}四条参考都只做表达整理。第三条没有补充逾期收费,第四条没有把下午三点改成上午。真实数据准备应记录样本来源与使用权限,去除不必要的个人信息;本例没有真实客户记录。
OpenAI 当前监督微调文档要求训练文件至少有十条样本。本例两条训练记录显然不够,不能直接上传开训。 也不应把它们复制五遍来凑门槛:重复行没有增加新的任务情形,只会掩盖覆盖不足。满足数量限制与数据质量合格同样不是一回事。
四、运行一个只读检查脚本
这一步只需本地 Python,不需要 API 密钥或额外依赖。先用 python --version 检查环境,将下面代码保存为 check_data.py,放在两个文件旁边,执行 python check_data.py。
import json
from pathlib import Path
def read_inputs(filename):
inputs = set()
count = 0
with Path(filename).open(encoding="utf-8-sig") as f:
for number, line in enumerate(f, 1):
try:
obj = json.loads(line)
if not isinstance(obj, dict):
raise ValueError("记录必须是对象")
messages = obj.get("messages")
if not isinstance(messages, list) or len(messages) != 2:
raise ValueError("本例每条须有两条消息")
for message, role in zip(messages, ["user", "assistant"]):
if not isinstance(message, dict) or message.get("role") != role:
raise ValueError("本例角色顺序须为user、assistant")
value = message.get("content")
if not isinstance(value, str) or not value.strip():
raise ValueError("内容须为非空文本")
text = messages[0]["content"].strip()
if text in inputs:
raise ValueError("同一文件存在重复输入")
inputs.add(text)
count += 1
except (ValueError, TypeError) as error:
raise ValueError(f"{filename}第{number}行:{error}") from error
if count == 0:
raise ValueError(f"{filename}没有样本")
return count, inputs
train_count, train_inputs = read_inputs("train-demo.jsonl")
valid_count, valid_inputs = read_inputs("valid-demo.jsonl")
if train_inputs & valid_inputs:
raise ValueError("训练与验证文件存在相同输入,请重新划分")
print(f"本例结构检查通过:训练{train_count}条,验证{valid_count}条")
print("这不代表达到服务训练门槛或内容质量已通过")它会检查逐行 JSON、消息结构、角色顺序、空答案、文件内重复和跨文件重复。不会修改文件,也不会联网。本例的双消息约束只是教学约定,不能把脚本拒绝的其他对话形式一概视作接口不支持。
五、结构检查之后,还要逐条检查内容
脚本通过后,应得到训练两条、验证两条的数量报告。再用人工核对每条原文与输出:日期、地点、否定条件是否一致;有没有删掉关键限制;有没有增加“已处理”“保证完成”等承诺;风格是否前后一致。
可以故意把一条 assistant 内容改为空白,确认脚本能定位;再把训练输入复制进验证文件,确认交叉重复会被拒绝。练习结束后恢复原示范,不要让故意写坏的材料进入正式数据集。
同义改写泄漏需要另查。把“周三18点截止”改成“星期三下午六点截止”,程序不会自动发现两者可能来自同一个原始任务。真实拆分应按客户会话、原始文档或其他相关来源分组,避免同一材料稍改措辞后同时出现在训练和验证中。
六、什么时候才考虑真正训练
先保存一组普通提示词或 Few-shot 的结果作为基线,使用同一批独立题核验事实保留与表达要求。需要真实调用时记录所用模型、提示词和参数;本文没有运行这一步,因此没有可报告的效果提升数字。
如果基线已经满足需求,未必需要微调。如果问题主要是资料缺失,先补资料;如果参考答案自己也有矛盾,先修数据。只有目标稳定、示范足够、评测可用,并愿意承担训练与后续维护成本时,再检查平台当前支持的模型、权限、费用与上传条件。
实际训练前还要明确谁能访问数据、如何保留原始样本、模型不达标时怎样回退。本地文件格式通过,不等于已经同意向任何服务传输资料,更不等于收费任务已获批准。不要把密钥写进数据文件或公开仓库。
七、常见误区
如果准备继续积累材料,可以单独建立样本台账:每条给一个内部编号,记录原始来源、允许用途、整理人员、复核状态与修改原因。编号用于追踪,不一定要发送给模型;台账也不要混进训练文件,避免把管理字段误当成模型应学习的答案。
遇到两条相近输入却有不同参考输出,先判断是否存在缺失条件。例如同一句“明天暂停开放”,在两个部门可能有不同恢复时间。原始输入没有部门或日期背景时,不应要求模型凭空区分,更不能用互相冲突的答案训练。先补齐任务必要背景,或把信息不足的处理方式明确写入规则。
每轮调整保留旧文件和检查结果,用新文件名保存修订版。检查失败时先根据文件名、行号定位,再重新运行完整检查;不要只删除报错行就认为问题已经解决。删除样本后还要重新统计数量与场景覆盖,确认没有把少数重要异常情形一起丢掉。
“验证正确率很高”可能是测试题泄漏,也可能任务过于单一。增加来自不同原始材料的保留题,查看哪些场景仍然容易改错,而不只盯着平均值。
“训练成功”只说明任务完成了某个技术流程,不能代替业务验收。“数据越多越好”也不成立:事实错误、风格冲突与重复示范可能扩大问题。每次改动都应有记录,能够说明为什么增加这些样本,以及希望改善哪类错误。
参考资料
微调流程、训练数据格式与最低样本要求,参考 OpenAI:监督微调指南。提示词、评测与微调的组合关系,参考 OpenAI:模型优化概述。本文四条通知、脚本与本地检查为原创教学练习,不构成训练效果实测。

还没有公开评论,欢迎分享你的想法。