微调

微调 是指获取一个现有模型并继续在你自己的例子上训练它,使其默认行为转向你想要的方向。本章阐述了这种改变的具体内容、它的用途,以及何时应该选择微调而不是提示词或检索。
训练实际上做了什么
要了解微调改变了什么,需要知道模型的来源。模型分两个大阶段构建。
第一个是**预训练:模型阅读大量文本,反复学习预测下一个词元,直到语法、事实和推理模式作为副作用沉淀到其中。产出是一个基础模型**,流畅但未经调整。它乐意继续你的文本,但还没有被教会成为回答问题的有用助手。
第二个阶段是后训练:基础模型在经过筛选的好回答例子上继续训练,再加上人类反馈,指出哪些答案更好。这就是把原始的文本预测器变成你真正对话的指令跟随助手的方式。你从 API 调用的模型已经经历了这两个阶段。
两个阶段都通过相同的机制工作:向模型展示例子,推动其内部数字(即参数或权重),使其预测更接近那些例子。训练是预测练习,让模型永久改变。
什么是微调
微调是那第二个阶段的一个小的、有针对性的版本,由你运行。你获取一个已经训练过的模型并继续在你自己的例子集上训练它,每个例子是一个输入配对你希望它产生的输出。足够多的例子后,模型的权重移动,使得这种响应成为它的默认值,不需要你在提示词中每次都要求。
与提示词和 RAG 的真正区别在于改变住在哪里。提示词和 RAG 让模型冻结,并通过你在调用时刻提供的上下文来引导它。微调改变模型本身,所以新行为被烤入并即使用短提示词也会显示。你不是在运行时给出更好的指令;你是在运送一个已经按你想要的方向倾斜的模型。
实际上你把一个示例对话文件交给提供商,它运行一个训练工作,然后给你返回一个新的**模型 id**。你调用这个 id 的方式正好就像任何其他模型,除了它的答案现在反映你训练的内容。微调把行为移进模型,提示词和 RAG 引导冻结的模型。
它擅长什么,不擅长什么
微调获得它的位置当你需要一个**一致的行为**,是提示词难以确定的:每次精确的输出格式、特定的语调或品牌风格,或像分类这样的狭窄任务在数千个调用中可靠地完成。它也可以使调用更便宜和更快,因为你会以其他方式在长提示词中拼写的行为被烤入模型,所以你的提示词变短了。
它失败的地方是知识。微调在教一个模型新事实上很差,在事实改变时更差。训练例子模糊成一般模式而不是被存储为精确的、可查找的条目,所以一个微调的模型仍然编造细节,在你的信息更新的一刻就过时。每次价格或策略改变时重新训练是慢的和昂贵的。当问题是"模型不知道 X"时,答案几乎总是 RAG,而不是微调。
经验法则:微调来改变形式,不是来添加事实。教模型如何回答,让检索处理用什么回答。
提示词、RAG 还是微调?
大多数时候你不是从这里开始的。三个技术形成一个**阶梯**,最便宜和最快改变先:
- 提示词。 总是先尝试这个。它是即时迭代的,成本没有额外的,清晰的提示词加上一两个例子解决了比人们期望的更多。如果你还没有让提示词工作,你还没准备好微调。
- RAG。 当差距是知识时选择这个:模型需要它没有的事实,或随时间改变的事实。RAG 在问题时刻提供它们而不接触模型。
- 微调。 当差距是行为而不是知识,且提示词不能使它足够一致时,或当你的提示词已经长到把指令烤入模型是规模上更便宜和更快时,选择这个。
它们不是互斥的,最强系统结合它们:微调一个模型为你的格式和语调,然后在运行时使用 RAG 来提供它当前事实。来自训练的行为,来自检索的知识。
所以在你微调前的快速测试。你能用更好的提示词到达那里吗?然后做那个。差距是缺少知识吗?然后它是 RAG。
爬阶梯;微调是最后的梯级,不是第一个。仅当提示词已经正确、事实已经可用、模型仍然不足够一致地表现,微调才成为适合的工具。
实际上
微调数据没有什么特别的。每个例子是一个短对话,形态正好就像你在运行时发送的,以你希望模型给出的答案结尾:
# 这里显示几个;真实数据集是数百到数千个例子,
# 覆盖你在运行时期望的输入的全部范围。
training_examples = [
{"messages": [
{"role": "system", "content": "Classify the ticket's urgency as low, medium, or high."},
{"role": "user", "content": "我这周被收费两次,今天必须修复。"},
{"role": "assistant", "content": "high"},
]},
{"messages": [
{"role": "system", "content": "Classify the ticket's urgency as low, medium, or high."},
{"role": "user", "content": "有没有深色模式设置?"},
{"role": "assistant", "content": "low"},
]},
# ...
]你把这些保存到一个文件,用提供商开始训练工作,然后等待它完成。回来的是一个新的模型 id,你然后调用它正好就像任何其他模型:
# 微调的模型是另一个 id;其他所有东西都不变。
response = client.chat.completions.create(
model="your-org/urgency-classifier-v1",
messages=[
{"role": "system", "content": "Classify the ticket's urgency as low, medium, or high."},
{"role": "user", "content": "导出按钮点击时什么都不做。"},
],
)
# response.choices[0].message.content -> "low" (仅标签,你训练的行为)赢利是行为现在住在模型。指令可以更短,格式在数千个调用上保持,你不需要成长提示词来到达那里。成本是周围的所有东西:你需要一个质量**数据集**,一个训练运行,每次你想改变它学了什么时的一个新鲜工作,这正好是为什么这座在阶梯底部。上传例子,获得一个模型 id,像调用任何其他一样调用它。
这是最后一个塑造模型知道什么和如何回答的方式,所有这些留它在你安排的桌子上预测文本。下一章给它行动能力:在 工具使用 模型调用你自己的函数,然后在循环中运行它们作为代理。

