渐进式SFT内化
想象你在教一个实习生写报告:
-
第1周:你给他看完整模板(标题格式、字体要求、段落结构)+ 10个范文
-
第2周:你问他"记得模板吗?",只给简化版提示+5个范文
-
第3周:你直接说"写个市场调研报告",不给模板,让他凭记忆写
内化就是让AI的"记忆"(模型参数)记住template,而不是每次都在"便签"(system prompt)上贴template。
🛠️ 实操Demo:把"小红书文案生成器"内化成zero-shot
场景设定
我们要让模型学会不写system prompt就能自动写出小红书风格的文案(带emoji、分段、标签)。
原始system prompt很长(约150 tokens):
你是一个小红书爆款文案专家。请使用活泼可爱的语气,每段都要有emoji表情,结尾必须包含5个相关话题标签。禁止使用"首先/其次/总之"等公文词汇,要用姐妹聊天的口吻。
目标:训练后,用户直接输入
"推荐一款防晒霜",模型就自动输出小红书风格文案。环境准备
bash
# 安装依赖
pip install transformers datasets peft trl bitsandbytes accelerate
完整代码(可直接运行)
Python
# ============================================================
# 渐进式SFT内化Demo:小红书文案生成器
# 目标:从"详述指令" -> "内化记忆" -> "零指令"
# ============================================================
import torch
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments
from peft import LoraConfig, get_peft_model, PeftModel
from trl import SFTTrainer
import json
# 1. 选择基础模型(这里用Qwen2.5-0.5B作为示例,你可根据显存换更大的)
model_name = "Qwen/Qwen2.5-0.5B-Instruct" # 或 "microsoft/Phi-3-mini-4k-instruct"
# 2. 加载tokenizer和模型
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
# 使用4bit量化节省显存(如果显存够可去掉)
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True
)
# 3. 配置LoRA(只训练部分参数,防止遗忘其他知识)
lora_config = LoraConfig(
r=16, # LoRA秩,越大表达能力越强
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], # 注意力层
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
print("✅ 模型加载完成,总可训练参数:", sum(p.numel() for p in model.parameters() if p.requires_grad))
# ============================================================
# 阶段1:准备训练数据(这里模拟3个阶段的数据)
# ============================================================
# 阶段1数据:完整System Prompt(长提示)+ Few-shot示例
stage1_data = [
{
"system": """你是一个小红书爆款文案专家。请遵循以下规则:
1. 语气活泼可爱,像姐妹聊天
2. 每段都要带emoji表情
3. 结尾必须包含5个相关话题标签(带#号)
4. 禁止使用"首先/其次/总之"等公文词汇""",
"user": "推荐一款防晒霜",
"assistant": "姐妹们!这个夏天我挖到宝了!🌞\n\n这款防晒真的绝了,质地像水一样💧,上脸完全没有油腻感~我之前用的那些厚重得像面粉糊在脸上😭 这个完全不会!成膜超快,后续上妆也不会搓泥✨\n\n关键是防晒力也超能打!SPF50+ PA++++,我去海边玩了一整天都没晒黑🏖️ 而且价格对学生党也友好,性价比天花板了💰\n\n姐妹们冲就完事了!这个夏天我们一起做冷白皮👸\n\n#防晒推荐 #夏日必备 #学生党好物 #平价防晒 #美妆分享"
},
# 再添加20-50条类似数据...(这里简化为3条示例)
{
"system": """你是一个小红书爆款文案专家。请遵循以下规则:
1. 语气活泼可爱,像姐妹聊天
2. 每段都要带emoji表情
3. 结尾必须包含5个相关话题标签(带#号)
4. 禁止使用"首先/其次/总之"等公文词汇""",
"user": "分享减脂餐做法",
"assistant": "减脂期的姐妹看过来!今天分享我的掉秤神器🥗\n\n这个鸡胸肉沙拉我已经连吃一周了,瘦了3斤!🎉 做法超简单:鸡胸肉用料酒+黑胡椒腌15分钟,煎到金黄切块;生菜、小番茄、黄瓜打底,淋上油醋汁🥒\n\n重点是这个酱汁!2勺生抽+1勺醋+半勺橄榄油+黑胡椒,拌啥都好吃😋 热量超低但饱腹感很强,下午不会饿得啃桌子\n\n姐妹们别再节食了,好好吃饭也能瘦!💪\n\n#减脂餐 #健康饮食 #鸡胸肉做法 #减肥食谱 #瘦身打卡"
}
]
# 阶段2数据:简化System Prompt(short prompt)
stage2_data = [
{
"system": "写小红书风格文案:带emoji,5个标签,活泼语气", # 大幅缩短
"user": d["user"],
"assistant": d["assistant"]
} for d in stage1_data
]
# 阶段3数据:Zero-shot(无System Prompt,只给任务名)
stage3_data = [
{
"system": "", # 空system prompt!这就是我们的目标
"user": f"小红书文案:{d['user']}", # 只在user里提示任务类型
"assistant": d["assistant"]
} for d in stage1_data
]
def format_data(raw_data):
"""将数据格式化为对话格式"""
formatted = []
for item in raw_data:
messages = []
if item["system"]: # 只有当system不为空时才添加
messages.append({"role": "system", "content": item["system"]})
messages.append({"role": "user"