Hello 大家好。好久不见。最近在工作中碰到一点挑战。目前我们的技术是基于RAG来处理问题。但是效果不是太好。原因是RAG对领域知识的召回率不够。导致LLM对用户问题的理解出现偏差。于是就想着能否微调一个小模型来处理特定领域的问题。以下是关于这次调研的一些记录。什么是微调微调(Fine-tuning)就是在一个已经训练好的基础/指令模型上,再用你自己的小规模、高质量数据继续训练,让模型更贴合你的业务任务、语气或领域知识。摘要:Hello 大家好。好久不见。最近在工作中碰到一点挑战。目前我们的技术是基于
目标:
固化稳定、不常变化的专有知识
让输出格式/语气统一(如结构化 JSON、报告模版、客服话术)提升特定任务表现(分类、抽取、窄域问答)
减少在特定领域里的胡编/幻觉
适用场景:
领域知识长期有效(规章、流程、产品线)
需要高一致性的输出格式或风格
高频相同任务调用,希望压缩上下文 token成本小模型在窄域“越级”替代大模型
不适用场景:
知识更新快(价格、库存、新闻)
样本太少( prompt/few-shot只是少量一次性实验
需要答案可追溯来源(优先 RAG)Fine-tuning vs RAG(机制 / 适用 / 成本)机制:
Fine-tuning:修改模型参数,把知识“刻”进去RAG(检索增强):不改模型,通过向量检索把外部文本塞进上下文临时使用适用场景:
Fine-tuning:稳定领域知识、固定格式、角色/语气、特定结构化任务RAG:动态更新知识、长文档问答、需要引用/可追溯、广覆盖信息聚合 组合: RAG提供最新事实 + 微调模型保证表达/格式稳定成本对比:
训练成本:微调有一次性训练费用; RAG几乎无训练费(只是建索引) 推理成本:微调后上下文可更短(便宜); RAG每次需检索+长上下文(token更多) 迭代速度: RAG更新文档即可;微调需再训练+部署 风险:微调数据错误会固化; RAG可随时删改简单决策:
下面我们通过一个具体的例子来演示微调的过程。在开始微调前,我们先对Phi4进行一轮测试。关于特定领域的问题,它是无法回答的。比如我问我们家的情况:老大的名字是什么?显然它不知道,只能回答一个比较通用的回答。
这种时候,我们可以对它进行微调,把我们家的情况告诉它。我们的期待是在微调后,我可以直接问一些关于我们家情况的问题。
在AI Foundry内创建一个新的project。类型选择:。因为只有Hub类型才能选择其他开源模型进行微调。比如等等。等待创建完成。
上传训练数据
训练数据为JSONL格式。每一行都定义了一个问题跟答案。比如以下训练数据里就描述了我家的情况。当然,这是让AI编的,假的。{"messages":[{"role":"system","content":"你需要记住以下家庭信息:\n1. 我家住在中国北京,有爸爸、妈妈、哥哥JIM、弟弟Mike,还有一只猫kitty。\n2. 哥哥JIM是老大,10岁,喜欢吃肉,爱踢足球,数学很好,最喜欢的颜色是蓝色,经常照顾弟弟。\n3. 弟弟Mike是老二,8岁,喜欢吃苹果,爱画画,也喜欢看动画片,最喜欢的颜色是绿色,经常和哥哥一起玩。\n4. 小猫kitty是白色的,喜欢睡在沙发上,爱玩毛线球,喜欢吃鱼,性格温顺黏人,经常和弟弟Mike一起玩,也偶尔跟哥哥JIM玩。\n5. 在家里我们平时说中文,常常在附近的公园活动,全家人感情很好。"}]}{"messages":[{"role":"user","content":"你家有几个人?"},{"role":"assistant","content":"我家有4个人,还有一只猫kitty。"}]}
{"messages":[{"role":"user","content":"老大是谁?"},{"role":"assistant","content":"老大是哥哥JIM。"}]}
{"messages":[{"role":"user","content":"老二是谁?"},{"role":"assistant","content":"老二是弟弟Mike。"}]}
{"messages":[{"role":"user","content":"你家猫叫什么名字?"},{"role":"assistant","content":"我们家的猫叫kitty。"}]}
{"messages":[{"role":"user","content":"哥哥几岁?"},{"role":"assistant","content":"哥哥JIM今年10岁。"}]}
{"messages":[{"role":"user","content":"弟弟几岁?"},{"role":"assistant","content":"弟弟Mike今年8岁。"}]}
{"messages":[{"role":"user","content":"老大最喜欢吃什么?"},{"role":"assistant","content":"老大喜欢吃肉。"}]}
{"messages":[{"role":"user","content":"老二喜欢吃什么?"},{"role":"assistant","content":"老二喜欢吃苹果。"}]}
{"messages":[{"role":"user","content":"kitty平时喜欢做什么?"},{"role":"assistant","content":"kitty喜欢睡在沙发上,也喜欢玩毛线球。"}]}
上传成功后,可以预览。
上传 validation 数据。这一部分可以选择跳过。系统自动从训练数据里挑一部分作为验证数据。
调整参数:
batch_size要用于训练的批大小。批大小表示用于训练单个前向和后向传递的训练示例的数量。一般情况下,我们发现较大的批大小往往更适合较大的数据集。此属性的默认值和最大值特定于基础模型。批大小越大意味着模型参数的更新频率越低,但方差越小。learning_rate_multiplier用于训练的学习率乘数。微调学习率是用于预训练的原始学习率乘以该值。较大的学习率通常在较大的批大小中表现更好。建议试验 0.02 到 0.2 范围内的值,以查看产生最佳结果的值。较小的学习率可以用于避免过度拟合。n_epochs训练模型的时期数。一个时期是指训练数据集的一个完整周期。开始训练经过差不多 45 分钟的等待,训练终于完成了。
这里需要注意的是微调是个循序渐进的过程,需要多轮调整训练数据跟参数才能达到比较理想的效果。
以下是通过几轮测试后,这个新的模型可以回答一些特定问题了。
但是还是有一些问题无法回答。因为微调比较费时间,就不再尝试了。
来源:opendotnet