Chapter 10

实战:微调一个领域专家模型

完整端到端项目:从数据收集到 Ollama 本地部署,构建一个真正好用的领域专家模型。以"中国劳动法律助手"为例。

项目目标与规格

目标:微调 Qwen2.5-7B 为中国劳动法律咨询助手

第一步:数据收集与构建

import anthropic
import json

client = anthropic.Anthropic()

LABOR_LAW_TOPICS = [
    "劳动合同签订与解除", "试用期规定", "工资待遇",
    "加班费计算", "工伤认定", "社保缴纳",
    "竞业限制", "劳动仲裁程序", "女职工保护", "裁员补偿"
]

def generate_qa_pair(topic: str) -> list:
    """为指定主题生成 5 个问答对"""
    response = client.messages.create(
        model="claude-opus-4-6",
        max_tokens=3000,
        messages=[{"role": "user", "content": f"""
针对主题"{topic}"生成5个真实劳动者可能问的问题及专业法律回答。
格式:JSON 数组,每条包含 instruction 和 output。
要求:
- 问题要真实具体(有场景细节)
- 回答要准确引用法条,给出实操建议
- 回答不少于 200 字"""}]
    )
    return json.loads(response.content[0].text)

# 生成训练数据
all_data = []
for topic in LABOR_LAW_TOPICS:
    pairs = generate_qa_pair(topic)
    all_data.extend(pairs)
    print(f"{topic}: {len(pairs)} 条")

# 加入系统提示
SYSTEM = "你是一位专业的中国劳动法律顾问,熟悉《劳动法》《劳动合同法》及相关司法解释。"
formatted = []
for item in all_data:
    formatted.append({
        "conversations": [
            {"from": "system", "value": SYSTEM},
            {"from": "human",  "value": item["instruction"]},
            {"from": "gpt",   "value": item["output"]}
        ]
    })

with open("labor_law_train.jsonl", "w") as f:
    for item in formatted:
        f.write(json.dumps(item, ensure_ascii=False) + "\n")

第二步:QLoRA 训练

from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth.chat_templates import get_chat_template
from unsloth import train_on_responses_only

# 加载 Qwen2.5-7B(Unsloth 预量化版)
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Qwen2.5-7B-Instruct-bnb-4bit",
    max_seq_length=2048,
    load_in_4bit=True
)

tokenizer = get_chat_template(tokenizer, chat_template="qwen-2.5")

model = FastLanguageModel.get_peft_model(
    model, r=16, lora_alpha=32,
    target_modules=["q_proj","k_proj","v_proj","o_proj",
                    "gate_proj","up_proj","down_proj"],
    use_gradient_checkpointing="unsloth", random_state=42
)

from datasets import load_dataset
dataset = load_dataset("json", data_files="labor_law_train.jsonl", split="train")

def apply_template(examples):
    texts = [tokenizer.apply_chat_template(
        c, tokenize=False, add_generation_prompt=False
    ) for c in examples["conversations"]]
    return {"text": texts}

dataset = dataset.map(apply_template, batched=True)

trainer = SFTTrainer(
    model=model, tokenizer=tokenizer,
    train_dataset=dataset, dataset_text_field="text",
    max_seq_length=2048,
    args=TrainingArguments(
        output_dir="./labor-law-model",
        num_train_epochs=3,
        per_device_train_batch_size=2,
        gradient_accumulation_steps=8,
        learning_rate=2e-4,
        lr_scheduler_type="cosine",
        bf16=True, logging_steps=20,
    )
)
trainer = train_on_responses_only(trainer,
    instruction_part="<|im_start|>user\n",
    response_part="<|im_start|>assistant\n"
)
trainer.train()

第三步:合并并转 GGUF

# 合并 LoRA 并保存
model.save_pretrained_merged("labor-law-merged", tokenizer, save_method="merged_16bit")

# 转换为 GGUF(Unsloth 内置支持)
model.save_pretrained_gguf("labor-law-q4", tokenizer, quantization_method="q4_k_m")
# 输出文件:labor-law-q4.gguf(约 4.5 GB)

第四步:Ollama 部署

# 创建 Modelfile
cat > Modelfile <<'EOF'
FROM ./labor-law-q4.gguf

SYSTEM """你是一位专业的中国劳动法律顾问,熟悉《劳动法》《劳动合同法》
及相关司法解释。回答问题时请准确引用法条,并给出实操建议。"""

PARAMETER temperature 0.3
PARAMETER top_p 0.9
EOF

# 创建 Ollama 模型
ollama create labor-law-expert -f Modelfile

# 测试
ollama run labor-law-expert "公司以试用期不合格为由解雇我,我有什么权利?"

效果验证

import requests

def ask_expert(question: str) -> str:
    response = requests.post(
        "http://localhost:11434/api/generate",
        json={"model": "labor-law-expert", "prompt": question, "stream": False}
    )
    return response.json()["response"]

# 测试用例
test_cases = [
    "被公司强制要求加班不给加班费怎么办?",
    "劳动合同到期公司不续签,我能拿到经济补偿金吗?",
    "工作满 10 年是否可以要求签无固定期限劳动合同?",
]

for q in test_cases:
    print(f"\nQ: {q}")
    print(f"A: {ask_expert(q)[:300]}...")
项目总结 完整流程:Claude 生成合成数据(3000条)→ Unsloth QLoRA 训练(Colab T4,约 2 小时)→ 合并 + GGUF 量化 → Ollama 本地部署。整个项目成本约 $5-15(API 调用费),即可获得一个专业领域助手。
课程完结 恭喜完成《LLM 微调实战》全部 10 章!从微调原理到生产部署,你已掌握完整的微调工程体系。下一步:用自己的真实业务数据,构建你的专属 AI 助手。