主軸二的最後一個技術主題。前七天我們讓模型「知道」(RAG)、「能做」(Agent),今天讓它「像我們要的樣子」。
我把微調放在最後,是刻意的——因為它是最後才該考慮的手段。
一個我經常被問的問題,以及一個經常錯誤的答案:
「我們公司有很多內部文件,是不是該微調一個自己的模型?」
答案通常是「不是」。 因為提問者真正想解決的是「讓模型知道公司的事」,而這是 RAG 的工作,不是微調的工作。
微調解決的是另一類問題:讓模型用你要的格式、風格、術語回答。分清楚這兩件事,能省下你三個月的時間與可觀的 GPU 費用。
📊 職缺訊號
「模型微調與客製化」只出現在 13.9% 的生成式 AI 職缺中,是八項任務中最低的。這個數字很誠實地反映了實務:多數應用不需要微調。但它出現時通常在資深職缺,因為它要求你能判斷「該不該做」——這比「會不會做」更難。

圖 23-1:模型表現不佳時的手段選擇(示意決策流程)。微調在最右下角——它是最後一個選項,不是第一個。
| 手段 | 解決 | 不解決 | 成本 |
|---|---|---|---|
| 提示工程 | 格式、簡單風格、單點任務 | 複雜格式的穩定性 | 最低 |
| RAG | 事實知識、時效性、可追溯 | 風格、語氣、輸出格式 | 中 |
| 微調 | 風格、格式、領域術語、任務特化 | 注入新知識(效果差且不可追溯) | 高 |
「微調不適合注入知識」這句話值得展開。 你可以硬用微調把公司文件塞進模型,但會遇到三個問題:模型會用「機率上合理」的方式重組事實(也就是幻覺)、無法追溯來源、文件更新就要重訓。同樣的需求,RAG 全部都做得更好。
如果決定要微調,LoRA 幾乎是唯一合理的起點。它的核心觀念是:模型適應新任務時所需的權重變化,其實是低秩的——換句話說,那個巨大的變化矩陣可以用兩個瘦長的小矩陣相乘來近似。

圖 23-2:LoRA 的參數量與顯存效益(8B 模型、32 層、4 個投影,依公式精算)。左圖:r=8 時可訓練參數僅約 840 萬,是全參數的 0.1%。右圖:QLoRA 讓 8B 模型的訓練顯存需求落在單張消費級顯卡可負擔的範圍。
具體算一次(這也是面試會考的):
每個 LoRA 模組的參數量 = r × (d_in + d_out)
8B 模型:d = 4096、32 層、對 q/k/v/o 四個投影加 LoRA
→ 模組數 = 32 × 4 = 128
→ r = 8 時:128 × 8 × (4096 + 4096) ≈ 8.4M 個參數
→ 佔全參數比例 = 8.4M / 8.03B ≈ 0.10%
顯存的差別更關鍵:全參數微調要存權重、梯度、以及 Adam 的兩個動量狀態,8B 模型約需 96 GB;LoRA 只需要為那 0.1% 的參數存梯度與動量,加上 4-bit 量化的基底權重(QLoRA),總需求可壓到 10 GB 上下——這就是「單張消費級顯卡能微調 8B 模型」的來源。
"""prepare_data.py —— 微調資料的品質遠比數量重要。"""
import json
# 格式必須符合模型的 chat template,不同模型不一樣
examples = [
{"messages": [
{"role": "system", "content": "你是法律事務所的書狀助理,"
"用本所慣用格式與用語草擬文件。"},
{"role": "user", "content": "幫我擬一份租賃契約終止通知"},
{"role": "assistant", "content": "受文者:○○○ 君\n主旨:..."}, # ← 真實的範例輸出
]},
# ... 50–500 筆
]
with open("train.jsonl", "w", encoding="utf-8") as f:
for ex in examples:
f.write(json.dumps(ex, ensure_ascii=False) + "\n")
四個資料準備的原則:
"""train_lora.py —— 用 TRL + PEFT 做 LoRA 監督微調。"""
from datasets import load_dataset
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from trl import SFTTrainer, SFTConfig
import torch
MODEL_ID = "Qwen/Qwen2.5-1.5B-Instruct" # 從小模型開始驗證流程
# QLoRA:以 4-bit 載入基底模型,大幅降低顯存
bnb = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, quantization_config=bnb,
device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
lora = LoraConfig(
r=8, # 秩:8–16 適合多數風格/格式任務;越大越貴且易過擬合
lora_alpha=16, # 慣例是 r 的 2 倍
lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
task_type="CAUSAL_LM",
)
trainer = SFTTrainer(
model=model,
train_dataset=load_dataset("json", data_files="train.jsonl")["train"],
peft_config=lora,
processing_class=tokenizer,
args=SFTConfig(
output_dir="./lora-out",
num_train_epochs=3, # 小資料集 2–4 輪即可,太多會過擬合
per_device_train_batch_size=2,
gradient_accumulation_steps=8,
learning_rate=2e-4, # LoRA 的學習率比全參數微調高一個量級
logging_steps=10,
bf16=True,
seed=42, # 可重現(Day 05 的第五根柱子)
),
)
trainer.train()
trainer.save_model("./lora-out") # 只存 adapter,通常只有幾十 MB
💡 沒有 GPU 怎麼辦
用 Google Colab 或 Kaggle 的免費 T4(16 GB)即可跑 1.5B 模型的 QLoRA。先用小模型把整條流程跑通——資料格式、訓練、評估、部署——再考慮換大模型。多數人卡住的是流程,不是算力。
"""evaluate_lora.py —— 沒有對照組的微調評估沒有意義。"""
cases = load_holdout() # 訓練時沒看過的資料
for name, mdl in [("基礎模型", base_model), ("微調後", tuned_model)]:
fmt_ok = sum(check_format(mdl.generate(c["input"])) for c in cases) / len(cases)
judge = sum(llm_judge_score(mdl.generate(c["input"]), c["expected"])
for c in cases) / len(cases)
print(f"{name}:格式合規率 {fmt_ok:.1%}、風格評分 {judge:.2f}")
# 也要檢查「災難性遺忘」——微調後是否失去了原本的通用能力
for q in GENERAL_ABILITY_PROBES: # 一般常識、推理、多語能力的題目
print(q, "→", tuned_model.generate(q))
災難性遺忘是最常被忽略的檢查。 模型可能把你要的格式學得很好,卻失去了原本的推理或多語能力。微調後一定要跑一組「與微調任務無關」的題目確認沒有退化。
| 情境 | 建議 | 理由 |
|---|---|---|
| 要模型知道公司政策 | RAG | 可更新、可追溯、成本低 |
| 要模型用固定的公文格式 | 先提示 + few-shot,不穩定再微調 | 提示通常就夠了 |
| 要模型使用大量業界術語 | 微調(或 RAG 提供術語表) | 術語是「怎麼說」,屬於風格範疇 |
| 要壓低推論成本 | 微調小模型取代大模型 | 這是微調最被低估的用途 |
| 要模型學會新的推理能力 | 換模型或拆解任務 | 微調小資料集無法賦予新能力 |
| 資料每週更新 | RAG | 微調的更新週期跟不上 |
📌 微調最被低估的用途:成本優化
假設你的任務用大模型每次要 $X,用小模型只要 $X/20 但品質不夠。用大模型的輸出當訓練資料,微調小模型(蒸餾),常常能讓小模型在這個特定任務上達到接近大模型的表現。
對高頻、單一用途的任務(分類、擷取、標準格式生成),這個做法的投資報酬率非常高——而且它與 RAG 不衝突,可以疊加使用。
最後,微調也要 MLOps。 這是雙主軸在此交會的地方:資料集要版本化(Day 09)、訓練要追蹤(Day 10)、模型要註冊(Day 10)、部署要走同一套流程(Day 12–13)。微調不是一次性的實驗,是一條要維護的管線。