"Should we fine-tune?" usually comes up in the second week of an LLM project. The prompt is getting long, the outputs are not quite right, and someone remembers that you can train the model on your own data.

Sometimes that is the right call. More often the problem is missing context (retrieval) or a vague task definition (prompting and evals), and fine-tuning would only bake the confusion into weights.

This post is a cheatsheet for that decision, and then for the case where fine-tuning wins: how LoRA and QLoRA work, which knobs matter, a runnable recipe with Hugging Face PEFT and TRL, rough memory math, what the research says, and the failure modes that show up after training.

1. The vocabulary

Term Meaning Why it matters
Prompting Steering a fixed model with instructions, examples and context in the input Cheapest to change. Every fix ships in minutes.
RAG Retrieval-augmented generation: fetch relevant documents at query time and put them in the context The standard way to give a model knowledge it does not have, with citations and freshness.
Full fine-tuning Updating every weight of the model on your data Highest capacity, highest cost. Needs memory for weights, gradients and optimizer state.
PEFT Parameter-efficient fine-tuning: train a small number of extra or selected parameters, freeze the rest Makes fine-tuning possible on one GPU, and adapters are megabytes, not gigabytes.
SFT Supervised fine-tuning on input/target pairs (often chat transcripts) The default fine-tuning method. Teaches format, style and task behavior.
Preference tuning (DPO) Training on pairs of preferred vs. rejected answers For "this answer is better than that one" signals, when you cannot write a single target.
RFT Reinforcement fine-tuning: a grader scores model outputs and the model is optimized for that score For tasks with checkable answers. Needs a reliable grader more than lots of data.
LoRA Low-Rank Adaptation: learn each weight update as the product of two thin matrices The most widely used PEFT method.
QLoRA LoRA trained on top of a base model quantized to 4 bits Cuts memory again, so larger models fit on one GPU.
Catastrophic forgetting Losing general abilities while learning the new task The main hidden cost of fine-tuning. Measure it, do not assume it away.

2. Prompting vs RAG vs fine-tuning

The shortest rule: RAG changes what the model knows at answer time. Fine-tuning changes how the model behaves. Prompting does a bit of both, cheaply, until the prompt gets too long or too fragile.

Problem you see Likely fix Why
Model does not know your products, policies or recent data RAG Knowledge changes; retrieval updates instantly, gives citations, and respects access control per document.
Answers are right but format, tone or structure drift Prompting first, then SFT Clear instructions and examples fix most of it. Fine-tune when you need consistency at scale or a shorter prompt.
Task is narrow, high volume, and a big model with a long prompt is too slow or expensive Fine-tune a smaller model Distilling a good prompted behavior into a small model is one of the most reliable wins.
Model must follow a domain-specific output style or label set exactly SFT (plus structured outputs if it is JSON) Hundreds of consistent examples beat a page of instructions.
Answers are verifiable (tests pass, number matches) and quality is the bottleneck RFT Optimizes directly for the grader.
Requirements are still changing weekly Prompting Every fine-tune freezes this week's definition of the task.
You do not have an eval yet Build the eval Without it you cannot tell whether any option helped.

What the research says about knowledge injection

Two results are worth knowing before you try to "teach the model our docs" with fine-tuning:

  • Retrieval beats fine-tuning for facts. Ovadia et al. (December 2023) compared unsupervised fine-tuning and RAG for injecting knowledge, and found RAG consistently ahead, for knowledge seen in pre-training and for entirely new facts. Fine-tuning learned new facts poorly, though exposing the model to several paraphrases of each fact helped.
  • New facts in SFT data can increase hallucination. Gekhman et al. (May 2024) found that fine-tuning examples containing knowledge the model did not already have are learned much more slowly, and once learned, they increase the model's tendency to hallucinate. Their reading: fine-tuning mostly teaches a model to use what it already knows.

Practical consequence: fine-tune for behavior, retrieve for knowledge. The common production shape is a fine-tuned model that is good at answering from retrieved context, not one that memorized the wiki.

3. How LoRA works

A transformer layer has large weight matrices, for example a 4,096 x 4,096 attention projection. Full fine-tuning learns an update to all of it. LoRA (Hu et al., June 2021) assumes the update has low rank and learns it as two thin matrices instead:

h = W0 x + (alpha / r) * B A x

W0 : frozen pretrained weight, d x k
A  : trainable, r x k   (random init)
B  : trainable, d x r   (zero init, so training starts exactly at the base model)
r  : rank, typically 8-64, much smaller than d and k

For a 4,096 x 4,096 matrix at r = 16, that is about 131 thousand trainable parameters instead of about 16.8 million, under 1%.

What the paper reported for GPT-3 175B compared with full fine-tuning with Adam:

Claim Number
Trainable parameters about 10,000x fewer
GPU memory during training about 3x less (1.2 TB down to 350 GB)
Checkpoint size (r = 4, query and value only) 350 GB down to 35 MB
Quality on par with or better than full fine-tuning on their benchmarks
Inference latency none added, because B A can be merged into W0

The original paper adapted only the attention query and value matrices. Later practice, including the QLoRA paper, found that applying LoRA to all linear layers in the transformer block matters more than the exact rank.

QLoRA in one table

QLoRA (Dettmers et al., May 2023) keeps the LoRA adapters in 16-bit but stores the frozen base model in 4 bits:

Idea What it does
NF4 (4-bit NormalFloat) A 4-bit data type designed for normally distributed weights, better than plain 4-bit floats or ints
Double quantization Quantizes the quantization constants too, saving a bit more memory per parameter
Paged optimizers Uses unified memory to absorb optimizer-state spikes instead of crashing with out-of-memory

Headline results: fine-tuning a 65B model on a single 48 GB GPU while matching 16-bit fine-tuning on their tasks, and a model (Guanaco) that reached 99.3% of ChatGPT's score on the Vicuna benchmark after 24 hours on one GPU. That benchmark used model-based judging, so read it as "close", not "equal".

Variants worth recognizing

Variant Idea When to try it
rsLoRA (November 2023) Scale by alpha / sqrt(r) instead of alpha / r When you raise rank and see no gain; it keeps higher ranks learning. use_rslora=True in PEFT.
DoRA (February 2024) Splits each weight into magnitude and direction, applies LoRA to the direction When plain LoRA lags full fine-tuning. use_dora=True in PEFT; slower to train.
LoRA+ (February 2024) Different learning rates for A and B Small, cheap gains in training speed and quality.

4. The hyperparameters that matter

Knob What it controls Practical starting point
r (rank) Capacity of each adapter 16. Go to 32-64 for harder tasks or larger data; lower rarely saves much.
lora_alpha Scale of the update (alpha / r) Often set to r or 2 * r. Change it together with the learning rate, not independently.
target_modules Which layers get adapters "all-linear" in PEFT. Attention-only is cheaper but usually weaker.
lora_dropout Regularization on the adapter input 0.0-0.1. Matters more on small datasets.
Learning rate Step size Around 1e-4 to 2e-4 is a common LoRA range; full fine-tuning uses much lower rates.
Epochs Passes over the data 1-3. Watch eval loss; more epochs on small data is the fastest way to overfit.
Data Everything A few hundred clean, consistent examples beat thousands of noisy ones.

On data size, OpenAI's fine-tuning guide is a good calibration point even if you train elsewhere: a hard minimum of 10 examples, and a recommendation to start with about 50 well-crafted demonstrations, evaluate, then add more.

5. A runnable QLoRA recipe (PEFT, TRL, bitsandbytes)

Versions current at the time of writing: PEFT 0.19.1 (April 2026), TRL 1.5.1 (May 2026), bitsandbytes 0.49.2 (February 2026). Pin them; these libraries rename arguments often.

uv pip install "peft==0.19.1" "trl==1.5.1" "bitsandbytes==0.49.2" transformers datasets accelerate

The dataset is a JSONL file of chat transcripts, one per line:

{"messages": [{"role": "system", "content": "Classify the support ticket. Reply with one label."}, {"role": "user", "content": "I was charged twice for May."}, {"role": "assistant", "content": "billing_duplicate_charge"}]}
import torch
from datasets import load_dataset
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from trl import SFTConfig, SFTTrainer

model_id = "Qwen/Qwen2.5-7B-Instruct"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
)

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    dtype=torch.bfloat16,
    device_map="auto",
)

peft_config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    target_modules="all-linear",
    task_type="CAUSAL_LM",
)

data = load_dataset("json", data_files={"train": "train.jsonl", "eval": "eval.jsonl"})

args = SFTConfig(
    output_dir="out/ticket-classifier-lora",
    num_train_epochs=2,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    lr_scheduler_type="cosine",
    warmup_ratio=0.03,
    max_length=1024,
    bf16=True,
    gradient_checkpointing=True,
    logging_steps=10,
    eval_strategy="steps",
    eval_steps=50,
    save_strategy="steps",
    save_steps=50,
)

trainer = SFTTrainer(
    model=model,
    args=args,
    train_dataset=data["train"],
    eval_dataset=data["eval"],
    processing_class=tokenizer,
    peft_config=peft_config,
)
trainer.model.print_trainable_parameters()
trainer.train()
trainer.save_model("out/ticket-classifier-lora/final")  # saves only the adapter

To serve without the PEFT wrapper, merge the adapter into a 16-bit copy of the base model (not the 4-bit one):

import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM

base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-7B-Instruct", dtype=torch.bfloat16)
merged = PeftModel.from_pretrained(base, "out/ticket-classifier-lora/final").merge_and_unload()
merged.save_pretrained("out/ticket-classifier-merged")

Or keep adapters separate: inference servers such as vLLM can serve many LoRA adapters on one base model, which is how per-customer or per-task variants stay cheap.

6. Rough memory math

Back-of-the-envelope numbers for a 7B model, before activations (which grow with batch size and sequence length):

Setup What sits in GPU memory Rough total (planning estimate)
Inference, bf16 2 bytes per weight about 14 GB
Full fine-tuning, mixed precision with Adam weights, gradients, fp32 master weights and two optimizer moments: about 16 bytes per weight about 112 GB, multi-GPU territory
LoRA on a bf16 base frozen weights (2 bytes each) plus a small adapter with its optimizer state about 15-16 GB
QLoRA on a 4-bit base about 0.5 bytes per frozen weight plus quantization overhead and the adapter under 10 GB

7. What the research says about LoRA vs full fine-tuning

"LoRA matches full fine-tuning" is true for many instruction-tuning and classification tasks. It is less true when the target domain is far from pre-training.

Biderman et al., LoRA Learns Less and Forgets Less (May 2024), compared LoRA and full fine-tuning on code and math with large training sets:

  • LoRA substantially underperformed full fine-tuning on the target domain.
  • LoRA preserved the base model's performance outside the target domain better, and did so better than common regularizers such as weight decay and dropout.
  • Full fine-tuning learned weight updates with a rank 10-100x higher than typical LoRA configurations, a plausible reason for the gap.

How to use that:

  • For narrow behavior (format, style, labels, tool-call patterns), LoRA is usually enough, and the reduced forgetting is a feature.
  • For teaching a new domain at scale, expect a gap; try higher rank, all-linear targets, DoRA, or full fine-tuning if you have the compute.
  • Either way, evaluate general ability before and after, not just the target task.

8. Hosted fine-tuning in mid-2026

Platform What is offered Notes
OpenAI Supervised fine-tuning, DPO, and reinforcement fine-tuning (RFT opened for o4-mini to verified organizations in May 2025) On May 7, 2026, OpenAI notified developers that it is winding down self-serve fine-tuning, starting with no access for organizations that have never used it. Existing fine-tuned models keep serving until their base model is deprecated. Check the deprecations page before planning new work on it.
Amazon Bedrock (Claude 3 Haiku) Supervised fine-tuning of Claude 3 Haiku Preview July 2024, generally available November 2024 in US West (Oregon).
Open-weight models Anything above, on your own or rented GPUs Most control and portability: the adapter is a file you own.

The lesson: a hosted fine-tune ties your behavior to one vendor's base model and lifecycle. Keep data, eval set and recipe in version control so you can reproduce the result elsewhere.

9. Failure modes after training

Symptom Likely cause Fix
Great on eval, poor in production Eval data leaked from train, or eval does not match real traffic Split by source or time, not randomly; sample eval from production logs.
Model repeats phrases from training data Overfitting on a small dataset Fewer epochs, more diverse examples, early stopping on eval loss.
General ability or safety behavior degraded Forgetting Mix in general instruction data, lower learning rate, smaller rank, run a general benchmark before and after.
More confident wrong facts Training on knowledge the model did not have Move facts to retrieval; train on answering from context.
Fine-tune is no better than the prompt Data inconsistent, or the prompt was already near the ceiling Audit labels; compare against a few-shot baseline with the same eval.
Behavior changes after a base model update Adapters are tied to the exact base weights Retrain on the new base; never load an adapter onto a different base.

Why this matters

  • Most "fine-tune it" requests are retrieval or prompt problems. Diagnosing that first saves weeks.
  • Fine-tuning teaches behavior, not facts. Research on knowledge injection points to RAG for facts and fine-tuning for how to use them.
  • LoRA and QLoRA make fine-tuning a single-GPU job. The barrier is now data quality and evaluation, not hardware.
  • LoRA forgets less, and learns less. Pick it for narrow behavior; expect a gap on large new domains.
  • Portability is a design choice. Owning data, recipe and adapter protects you from vendor and base-model changes.

Final Thoughts

Prompting, retrieval and fine-tuning are not rungs on a ladder. They are tools for different problems: unclear instructions, missing knowledge, and inconsistent behavior. Most good systems use all three, in that order of effort.

When you do fine-tune, LoRA and QLoRA make the training the easy part. The hard part is the same as everywhere else in AI engineering: a clean dataset, an honest eval, and a before-and-after comparison that includes what you might have broken.

Sources