Showing posts with label Fine-Tuning. Show all posts
Showing posts with label Fine-Tuning. Show all posts

Tuesday, April 14, 2026

Fine-Tuning LLMs in 2026: When to Fine-Tune, When to Use RAG, and When to Just Prompt Better

Hero image showing a neural network being fine-tuned with targeted gradient flows

Introduction

The question comes up in every AI architecture conversation: should we fine-tune a model or use RAG?

It's the wrong question. Fine-tuning and RAG solve different problems, they're not competing strategies. The real question is: what is actually causing your model to underperform? Is it a knowledge problem (missing information), a behavior problem (wrong tone, format, or style), or a reasoning problem (the base model isn't capable of the task)?

RAG solves knowledge problems. It injects external, up-to-date information into the model's context at query time. It's runtime retrieval.

Fine-tuning solves behavior problems. It changes how the model responds — its style, its output format, its reasoning patterns — by training on examples of the behavior you want.

Prompting solves a surprising number of both. Before reaching for either, the correct answer is often more carefully designed prompts with better examples and clearer instructions.

This post is for engineers and ML practitioners who need to make the right call for their specific use case. We'll cover what fine-tuning actually changes inside the model, how LoRA makes it practical at production scale, when each approach is the correct choice, and the production considerations that determine whether a fine-tuned model is an asset or a maintenance burden.

Fine-Tuning vs RAG vs Prompting Decision Matrix

What Fine-Tuning Actually Changes

When you fine-tune a language model, you're adjusting the model's weights — the billions of numerical parameters that determine how the model responds to input. Training on new examples updates those weights to make the model more likely to produce the types of outputs you showed it and less likely to produce outputs that differ.

This is fundamentally different from RAG, which doesn't change the model at all. RAG changes the model's input (what information is in the context). Fine-tuning changes the model itself (how it processes and responds to any input).

What fine-tuning improves:
- Output format consistency — models that reliably produce JSON, specific markdown formats, or structured templates
- Domain-specific tone and style — a customer service bot that always uses company language, a medical summarizer that uses clinical terminology correctly
- Task specialization — models that have internalized specialized reasoning patterns (legal document analysis, code generation in a specific framework)
- Reduced prompt length — behaviors that require lengthy few-shot examples in a prompt can be internalized through fine-tuning, reducing per-request token cost

What fine-tuning doesn't improve:
- Knowledge freshness — fine-tuned knowledge is frozen at training time. A model fine-tuned on your product docs in January won't know about the March product update.
- Factual grounding — fine-tuning can teach a model how to reason, but it still hallucinates facts it doesn't have in training
- Long-tail knowledge — fine-tuning requires substantial data. For niche domains with limited examples, RAG with retrieval is more reliable

The Three Fine-Tuning Approaches

Full Fine-Tuning (Rarely Practical in 2026)

Full fine-tuning updates all model weights. For a 70B parameter model at fp16, that's 140GB of model weights, gradients, and optimizer state — easily 400-600GB of GPU memory during training. At $30,000 per H100, the economics rarely work outside of large AI labs.

Full fine-tuning also risks catastrophic forgetting: the new training overwrites general capabilities as the model specializes. A general-purpose model becomes narrow.

For most teams, full fine-tuning is theoretical.

Parameter-Efficient Fine-Tuning (PEFT)

PEFT methods update only a small fraction of the model's parameters — leaving most weights frozen and training only small adapter layers. The result: comparable quality improvement at a fraction of the compute and memory cost.

The dominant PEFT method is LoRA (Low-Rank Adaptation).

LoRA: The Practical Fine-Tuning Method

LoRA's insight: large weight matrices have low intrinsic rank during fine-tuning. The updates needed to specialize a model for a task are much lower-dimensional than the full weight matrix. Instead of updating a full weight matrix W (e.g., 4096×4096), LoRA decomposes the update into two small matrices: W + ΔW, where ΔW = A × B, and A and B have much smaller dimensions (4096×r and r×4096, where rank r is typically 4-64).

This reduces trainable parameters from millions to thousands while capturing nearly all the task-specific information needed.

QLoRA: quantized LoRA. The base model weights are quantized to 4-bit, and LoRA adapters are trained on top. This enables fine-tuning 70B models on consumer hardware (two A100 40GB GPUs, or even a single A100 80GB). The quality degradation from 4-bit quantization is typically small enough that QLoRA results are competitive with full fine-tuning for most tasks.

# Fine-tuning with PEFT + LoRA
# pip install transformers peft datasets accelerate bitsandbytes

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
import torch

# Load base model in 4-bit for QLoRA
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3-8B-Instruct",
    load_in_4bit=True,
    torch_dtype=torch.float16,
    device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B-Instruct")
tokenizer.pad_token = tokenizer.eos_token

# Configure LoRA adapters
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,                          # Rank — higher = more parameters, more capacity
    lora_alpha=32,                 # Scaling factor (usually 2× rank)
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],  # Which layers to adapt
    lora_dropout=0.05,
    bias="none",
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 3,407,872 || all params: 8,033,669,120 || trainable%: 0.04242

# Training
training_args = TrainingArguments(
    output_dir="./fine-tuned-llama",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,  # Effective batch size = 16
    warmup_steps=100,
    learning_rate=2e-4,
    fp16=True,
    logging_steps=25,
    save_strategy="epoch",
    report_to="tensorboard",
)

trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,    # Your formatted dataset
    tokenizer=tokenizer,
    max_seq_length=2048,
)
trainer.train()

# Save adapter weights only (not the full base model)
model.save_pretrained("./lora-adapters")

The trainable parameter count — 0.04% of the full model — illustrates LoRA's efficiency. You're training 3.4M parameters instead of 8 billion, yet achieving meaningful task-specific improvement.

graph LR subgraph "Full Fine-Tuning" A[8B parameters] --> B[All weights updated] B --> C[400GB+ GPU memory] C --> D[Expensive + slow] end subgraph "LoRA Fine-Tuning" E[8B parameters] --> F[Base weights FROZEN] F --> G[3.4M adapter params updated] G --> H[~40GB GPU memory] H --> I[Practical on 1-2 GPUs] end style D fill:#ff6b6b style I fill:#51cf66

Dataset Quality: The Actual Bottleneck

The most common fine-tuning mistake: not enough data, or data that's the wrong shape. LoRA can learn from hundreds of examples — but those examples must precisely demonstrate the behavior you want.

Quality > quantity. 200 carefully curated examples of the exact input/output pattern you want the model to learn will outperform 2,000 noisy examples with inconsistent formatting, mixed tones, or off-target outputs.

Dataset format for instruction fine-tuning:

# Training data format: instruction/input/output triplets
training_examples = [
    {
        "instruction": "Classify this customer message by severity and category",
        "input": "My account has been locked and I can't log in. I have an urgent presentation in 2 hours and need access immediately.",
        "output": '{"severity": "critical", "category": "account_access", "urgency": "immediate", "sentiment": "distressed", "recommended_action": "escalate_to_agent"}',
    },
    {
        "instruction": "Classify this customer message by severity and category",
        "input": "Can you update my billing address?",
        "output": '{"severity": "low", "category": "billing", "urgency": "routine", "sentiment": "neutral", "recommended_action": "self_service"}',
    },
    # ...200-500 more examples
]

# Format into chat template
def format_example(example):
    return f"""<|system|>
You are a customer support classifier. Always output valid JSON.
<|user|>
{example['instruction']}

{example['input']}
<|assistant|>
{example['output']}"""

Data collection strategies:
- Distillation from larger models: generate examples using Claude Opus or GPT-4, then fine-tune a smaller model to replicate that behavior. Cost-effective way to transfer capability.
- Human annotation: for high-stakes tasks, have domain experts label examples. Slower and more expensive, but higher quality for nuanced domains.
- Synthetic data generation: for tasks with clear rules (format conversion, classification, templated generation), generate data programmatically.

flowchart TD A[Define target behavior] --> B[Collect/generate examples] B --> C{Enough examples?} C -->|< 100| D[Collect more or use few-shot prompting instead] C -->|100-500| E[Minimum viable for LoRA] C -->|500+| F[Good dataset] E --> G[Manual quality review] F --> G G --> H{Consistent format?} H -->|No| I[Fix formatting first] H -->|Yes| J[Split train/eval 90/10] J --> K[Run fine-tuning] K --> L[Eval on held-out set] L --> M{Meets quality bar?} M -->|No| N[Diagnose: data quality or more epochs?] M -->|Yes| O[Deploy adapter] style D fill:#ffd43b style I fill:#ffd43b style O fill:#51cf66

Fine-Tuning vs RAG vs Prompting: The Decision Matrix

Criterion Better Prompt RAG Fine-Tuning
Missing recent knowledge
Knowledge base > context window
Consistent output format ✓ (few-shot) ✓✓
Domain-specific style/tone ✓ (system prompt) ✓✓
Reduce per-request token cost
Internalize reasoning patterns
Low latency (no retrieval step)
Knowledge is verifiable/citable
Handles data you can't share externally

The right architecture for most production AI applications combines all three: a carefully designed system prompt establishes persona and constraints, RAG injects relevant factual context, and a fine-tuned adapter shapes the output format and style. They're layers, not alternatives.

DPO: Alignment Fine-Tuning Without Reinforcement Learning

RLHF (Reinforcement Learning from Human Feedback) was the original method for aligning model behavior — teaching models to be helpful, harmless, and honest based on human preference signals. RLHF is complex: it requires training a separate reward model, managing a reinforcement learning loop, and dealing with training instability.

DPO (Direct Preference Optimization), introduced in 2023 and now the dominant alignment method for small-team fine-tuning, simplifies this to a standard supervised learning problem. Instead of a reward model and RL loop, DPO directly optimizes on preference data: pairs of (chosen, rejected) responses to the same prompt.

from trl import DPOTrainer, DPOConfig

# Preference dataset format
preference_data = [
    {
        "prompt": "How do I center a div in CSS?",
        "chosen": "Use flexbox: set `display: flex; justify-content: center; align-items: center;` on the parent. This is the modern, reliable approach that works across all current browsers.",
        "rejected": "You can use margin: auto but that only works sometimes. There's also table-cell but nobody does that anymore. The old float trick doesn't really work. Honestly just Google it.",
    },
    # ... more preference pairs
]

dpo_config = DPOConfig(
    beta=0.1,   # Temperature for the DPO objective — controls how strongly to prefer chosen vs rejected
    learning_rate=5e-7,
    num_train_epochs=1,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,
)

dpo_trainer = DPOTrainer(
    model=model,
    ref_model=ref_model,  # A frozen copy of the base model
    args=dpo_config,
    train_dataset=preference_data,
    tokenizer=tokenizer,
)
dpo_trainer.train()

DPO is particularly effective for: reducing verbosity, improving response quality on open-ended tasks, adjusting model persona, and reducing refusal rates on edge cases the base model over-refuses.

Serving Fine-Tuned Models

The LoRA adapter weights are typically small (50-200MB for rank-16 adapters on a 7-8B model) compared to the base model (14-16GB at fp16). Production serving strategies:

Single adapter: merge the LoRA weights into the base model once training is complete. model.merge_and_unload() in PEFT produces a single model file that serves like a normal model — no adapter-handling overhead at inference time.

Multiple adapters, shared base: vLLM supports serving a single base model with multiple LoRA adapters loaded simultaneously. Requests specify which adapter to use. Memory efficient: the 14GB base model is loaded once, and each adapter adds 50-200MB.

# vLLM with multiple LoRA adapters
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3-8B-Instruct \
  --enable-lora \
  --lora-modules customer-service=./adapters/customer-service \
                  code-review=./adapters/code-review \
                  medical-notes=./adapters/medical-notes \
  --max-loras 3

Request routing specifies the adapter at the API level — different endpoints or different model parameter values route to the appropriate adapter, all served from the same GPU.

Production Considerations

Evaluation before deployment: fine-tuning can improve specific tasks while degrading general capability. Define an evaluation set before training and measure both target task performance and a general capability benchmark (MMLU, or a custom benchmark reflecting your use case mix) after each training run.

Training and evaluation data contamination: if your evaluation set contains any examples from training, your metrics are meaningless. Use strict train/eval splits and verify there's no leakage.

Model drift over time: fine-tuned models can become stale as the underlying domain changes. Schedule periodic re-training runs as new data accumulates. Track performance on a fixed evaluation set over time to detect degradation.

Cost accounting: for teams considering fine-tuning to reduce API costs (calling a fine-tuned 7B model instead of a frontier model), the break-even calculation needs to account for training costs, serving infrastructure, and the quality gap. A fine-tuned 7B model rarely matches GPT-4 or Claude Opus 4 on complex reasoning — only on narrow tasks where the training data is high quality and the task is well-defined.

Evaluation: Measuring Whether Fine-Tuning Actually Worked

Fine-tuning without rigorous evaluation is expensive guessing. Before training, define the evaluation criteria precisely. After training, measure against them on a held-out test set that has no overlap with training data.

Automatic metrics for structured outputs: if your fine-tuned model produces JSON, code, or templated text, exact-match accuracy on the eval set is your primary metric. "Did the model produce valid JSON?" and "Does the JSON contain the required fields?" are binary, automatable checks.

LLM-as-judge for open-ended outputs: for tasks where quality is hard to measure programmatically — summarization, tone, style, helpfulness — use a larger frontier model (Claude Opus 4 or GPT-4o) to evaluate outputs against a rubric. This approach scales to thousands of examples without human annotation. Define the rubric precisely: don't ask "is this good?" but "on a scale of 1-5, does this response use the company's brand voice as described in [criteria]?"

def evaluate_fine_tuned_model(
    eval_dataset: list[dict],
    model_name: str,
    judge_model: str = "claude-opus-4-6",
) -> dict:
    """
    Evaluate fine-tuned model on held-out test set.
    Returns accuracy, quality scores, and failure analysis.
    """
    results = []

    for example in eval_dataset:
        # Get fine-tuned model output
        prediction = run_fine_tuned_model(model_name, example["instruction"], example["input"])

        # Exact match check for structured outputs
        exact_match = prediction.strip() == example["output"].strip()

        # LLM judge for quality
        judge_prompt = f"""
        Task: {example["instruction"]}
        Input: {example["input"]}
        Expected output: {example["output"]}
        Actual output: {prediction}

        Rate the actual output on these criteria (1-5 each):
        1. Format correctness (follows the required format exactly)
        2. Content accuracy (facts/logic are correct)
        3. Style compliance (matches the expected tone and language)

        Output JSON: {{"format": N, "accuracy": N, "style": N, "reasoning": "..."}}
        """

        judge_response = run_judge_model(judge_model, judge_prompt)
        scores = json.loads(judge_response)

        results.append({
            "exact_match": exact_match,
            **scores,
            "prediction": prediction,
            "expected": example["output"],
        })

    return {
        "exact_match_accuracy": sum(r["exact_match"] for r in results) / len(results),
        "avg_format_score": sum(r["format"] for r in results) / len(results),
        "avg_accuracy_score": sum(r["accuracy"] for r in results) / len(results),
        "avg_style_score": sum(r["style"] for r in results) / len(results),
        "failure_cases": [r for r in results if not r["exact_match"]],
    }

Regression testing: a fine-tuned model might improve at the target task while regressing on general capabilities. Always run both task-specific eval and a general capability benchmark. If general capability drops more than 3-5% on your benchmark, investigate before deploying — the training data or learning rate may be causing catastrophic forgetting.

A/B testing in production: for models serving real users, shadow traffic testing or gradual rollout (5% → 25% → 100%) is the gold standard. Real user behavior reveals failure modes that offline eval misses.

Common Fine-Tuning Mistakes

Training on too little data without checking eval quality: 50 examples often isn't enough. 200-500 is a more reliable minimum. If your eval accuracy isn't improving after 3 epochs on 50 examples, the limiting factor is data quantity, not model capacity.

Inconsistent output format in training data: if some examples produce JSON with double quotes and others with single quotes, some with trailing commas and some without, the model learns inconsistency. Normalize all training data formatting before training.

Using production traffic directly as training data without filtering: real user requests include adversarial inputs, edge cases, and off-topic queries. Training on raw production traffic teaches the model those behaviors too. Filter aggressively for clean, canonical examples of the target behavior.

Setting the learning rate too high: high learning rates cause catastrophic forgetting — the model "unlearns" general capabilities to specialize in the training task. For LoRA fine-tuning, 1e-4 to 2e-4 is a typical starting range. Reduce by half if you see general capability degradation.

Forgetting to convert the model to inference format: LoRA adapters trained on 4-bit quantized models must be either merged (model.merge_and_unload()) or served via a LoRA-aware serving stack (vLLM with --enable-lora). Deploying the adapter-only weights without the base model doesn't work.

Conclusion

Fine-tuning is not a silver bullet and it's not always the answer. For most teams, the diagnostic hierarchy is: try a better prompt first (system prompt, chain-of-thought, few-shot examples). If knowledge is the gap, add RAG. If behavior is consistently wrong regardless of what information you provide, fine-tuning addresses the root cause.

LoRA and QLoRA have removed the GPU infrastructure barrier that made fine-tuning impractical for most teams. Training a task-specific adapter on a 7B base model on a rented cloud GPU is now a routine operation, not a research project.

The teams that use fine-tuning well treat it as part of a system — not a replacement for careful prompt design, good data, and rigorous evaluation.


Sources & References

  1. Hu et al. — "LoRA: Low-Rank Adaptation of Large Language Models"
  2. Dettmers et al. — "QLoRA: Efficient Finetuning of Quantized LLMs"
  3. Rafailov et al. — "Direct Preference Optimization"
  4. HuggingFace PEFT Documentation
  5. TRL (Transformer Reinforcement Learning)
  6. vLLM LoRA Serving

About the Author

Toc Am

Founder of AmtocSoft. Writing practical deep-dives on AI engineering, cloud architecture, and developer tooling. Previously built backend systems at scale. Reviews every post published under this byline.

LinkedIn X / Twitter

Published: 2026-05-05 · Written with AI assistance, reviewed by Toc Am.

Get These In Your Inbox

Weekly deep-dives on AI engineering, no fluff. Join the newsletter →

Subscribe (free)

Or grab the book ($39, ~100 pages) · Buy me a coffee

Buy Me a Coffee · 🔔 YouTube · 💼 LinkedIn · 🐦 X/Twitter

Monday, April 6, 2026

Building a Domain-Specific AI with Open-Source Models

Building a Domain-Specific AI Hero

Building a Domain-Specific AI with Open-Source Models

Level: Professional | Topic: AI Architecture | Read Time: 9 min


You have read about open-source models, local inference, fine-tuning, and RAG as individual techniques. This article brings them together into a complete architecture for building a production-grade, domain-specific AI system using entirely open-source components.

No cloud APIs. No vendor lock-in. Full data sovereignty.

graph LR
  A[Domain Data\nCollection] --> B[Data Cleaning\nFormatting]
  B --> C[Choose Strategy\nFine-Tune vs RAG vs Both]
  C --> D[Training /\nIndexing]
  D --> E[Evaluation]
  E --> F[Domain Expert\nReview]
  F --> G[Production]

The Architecture

Architecture Diagram

A production domain AI system has four layers:

Layer 1: Base Model Selection

Choose your foundation model based on your hardware and quality requirements:

  • 3B-8B parameters (8-16 GB RAM): Llama 3.2, Phi-3, Mistral 7B — fast inference, good for focused tasks
  • 13B-34B parameters (32 GB RAM): Llama 3.1 13B, Mixtral 8x7B — significantly better reasoning
  • 70B+ parameters (64+ GB RAM or GPU cluster): Llama 3.1 70B — near-frontier quality

For most domain-specific tasks, a fine-tuned 7B model will outperform a general-purpose 70B model. Start small.

Layer 2: Fine-Tuning Pipeline

Prepare your training data in instruction-response format:

{"instruction": "Summarize this patient note", "input": "Patient presents with...", "output": "Assessment: 45yo male with..."}

Use QLoRA for cost-effective training:
- Rank: 16-32
- Learning rate: 2e-4
- Epochs: 2-3
- Training examples: 1,000-10,000
- Tools: Unsloth or Axolotl for fastest training

Evaluate on a held-out test set before deploying.

Layer 3: RAG Knowledge Base

Your fine-tuned model knows how to behave. RAG gives it specific knowledge:

  1. Embed your documents using an embedding model (all-MiniLM-L6-v2 or nomic-embed-text)
  2. Store in a vector database (ChromaDB for local, Pinecone for managed)
  3. Retrieve at inference time: top-k relevant chunks, injected into the prompt
  4. Rerank results using a cross-encoder for improved relevance

Layer 4: Inference Server

Deploy the complete system:

  • Ollama or llama.cpp server: Serve the fine-tuned model via REST API
  • Application layer: Python/Node.js service that orchestrates RAG retrieval + model inference
  • Monitoring: Log all queries and responses for quality evaluation and continuous improvement

Example: Legal Document Assistant

A law firm wants an AI that can analyze contracts, identify risks, and draft clauses.

  1. Base model: Llama 3.2 8B (runs on a MacBook Pro)
  2. Fine-tuning: 5,000 examples of contract analysis with attorney-approved outputs
  3. RAG: Firm's contract database + relevant case law + regulatory guidelines
  4. Result: A specialized legal AI that understands the firm's style, has access to all precedent documents, and runs entirely on-premise

Cost: One-time training cost plus hardware. No per-query API fees. No data leaving the building.


Production Considerations

Quality assurance: Every fine-tuned model needs an evaluation pipeline. Use automated metrics (BLEU, ROUGE for text generation; accuracy for classification) plus human review on a random sample.

Continuous improvement: Log all inputs and outputs. Periodically review for quality issues. Retrain with corrected examples when you find systematic errors.

Fallback strategy: For queries outside the model's domain, detect low confidence and route to a human expert or a larger general-purpose model.

Version control: Treat LoRA adapters like code. Version them, store them in Git LFS, and maintain a rollback strategy.


The Open-Source Stack

Component Tool Cost
Base model Llama 3.2 / Mistral Free
Fine-tuning Unsloth + QLoRA Free (GPU time)
Embeddings nomic-embed-text Free
Vector DB ChromaDB Free
Inference Ollama / llama.cpp Free
Orchestration LangChain / custom Python Free

Total software cost: $0. The only costs are hardware and the time to prepare training data.


Next Steps

  1. Identify a specific domain task where a general model underperforms
  2. Collect 1,000+ examples of ideal input-output pairs
  3. Fine-tune a 7B model using QLoRA
  4. Add RAG for domain documents
  5. Evaluate, iterate, deploy

The tools are ready. The models are ready. The only missing piece is your domain expertise.


Sources & References:
1. Hugging Face — "Datasets Library" — https://huggingface.co/docs/datasets
2. LangChain — "RAG with Custom Data" — https://python.langchain.com/docs/concepts/rag/
3. Ollama — "Running Local Models" — https://ollama.com/


Published by AmtocSoft | amtocsoft.blogspot.com
Level: Professional | Topic: Domain-Specific AI Architecture


Tools mentioned in this post

Disclosure: the links below are affiliate links. If you sign up via them, we earn a small commission at no extra cost to you. This helps fund the writing of more posts like this one.

  • Pinecone — production vector database. Sign up
  • LangChain — LangSmith observability tier. Sign up
  • Hugging Face — Pro / Enterprise tier. Sign up

About the Author

Toc Am

Founder of AmtocSoft. Writing practical deep-dives on AI engineering, cloud architecture, and developer tooling. Previously built backend systems at scale. Reviews every post published under this byline.

LinkedIn X / Twitter

Published: 2026-04-12 · Written with AI assistance, reviewed by Toc Am.

Get These In Your Inbox

Weekly deep-dives on AI engineering, no fluff. Join the newsletter →

Subscribe (free)

Or grab the book ($39, ~100 pages) · Buy me a coffee

Buy Me a Coffee · 🔔 YouTube · 💼 LinkedIn · 🐦 X/Twitter

Fine-Tuning vs RAG: When to Use Which

Fine-Tuning vs RAG Hero

Fine-Tuning vs RAG: When to Use Which

Level: Advanced | Topic: Fine-Tuning vs RAG | Read Time: 7 min


Two techniques dominate the conversation about customizing LLMs: fine-tuning and Retrieval-Augmented Generation (RAG). Both make models more useful for specific tasks. But they solve fundamentally different problems, and using the wrong one wastes time and money.

This guide provides a clear decision framework for choosing between them.

graph TB
  A[Need to Customize AI?] --> B{Is Data Static?}
  B -->|Yes| C[Fine-Tuning]
  B -->|No / Dynamic| D[RAG]
  A --> E{Need Both?}
  E -->|Yes| F[Hybrid\nFine-Tune + RAG]

What Each Technique Does

RAG adds external knowledge at inference time. Before the model generates a response, RAG searches a knowledge base, retrieves relevant documents, and includes them in the prompt. The model's weights remain unchanged.

Fine-tuning changes the model's behavior by updating its weights with new training data. The model permanently learns new patterns, styles, or domain knowledge.

The distinction matters: RAG teaches the model what to know. Fine-tuning teaches the model how to behave.


When to Use RAG

Architecture Diagram

RAG is the right choice when:

  • Knowledge changes frequently: Product catalogs, documentation, news, pricing — anything that updates regularly
  • You need citations: RAG naturally provides source documents for every answer
  • Your knowledge base is large: RAG can search millions of documents without increasing model size
  • Accuracy is critical: Grounding responses in retrieved documents reduces hallucinations
  • You need to get started quickly: RAG requires no training, just a vector database and embeddings

Common RAG use cases: customer support chatbots, document Q&A, knowledge base search, legal research, internal wikis.


When to Use Fine-Tuning

Fine-tuning is the right choice when:

  • You need a specific output format: Always return JSON, always use a template, always follow a rubric
  • You need a specific tone or style: Brand voice, medical writing style, legal prose
  • You need improved reasoning in a domain: Medical diagnosis, code review, financial analysis
  • Latency matters: Fine-tuned models respond in one pass; RAG adds retrieval latency
  • You want a smaller, faster model: Fine-tune a 3B model to outperform a general 70B on your task

Common fine-tuning use cases: code generation for specific frameworks, clinical note summarization, sentiment analysis in a specific domain, structured data extraction.


The Decision Matrix

Criterion Choose RAG Choose Fine-Tuning
Knowledge freshness Dynamic, changes often Static domain knowledge
Training data available Not enough examples 1,000+ quality examples
Output format needs Standard text Specific structure required
Deployment speed Need it now Can invest training time
Cost sensitivity Low ongoing cost Upfront training cost
Model behavior change No Yes

The Best Answer: Use Both

The most effective production systems combine both techniques:

  1. Fine-tune the base model on your domain to improve its reasoning and output format
  2. Add RAG to give it access to current knowledge and specific documents
  3. Engineer prompts to guide the fine-tuned model's behavior at inference time

Example: A medical AI that is fine-tuned on clinical notes (behavior), uses RAG to retrieve patient records (knowledge), and has a system prompt defining the output template (format).


Cost Comparison

Approach Upfront Cost Ongoing Cost Maintenance
RAG only Vector DB setup Embedding + retrieval per query Update documents
Fine-tuning only GPU training time Inference compute Retrain periodically
Both Higher initial Moderate Both maintenance streams

For most teams, starting with RAG and adding fine-tuning when needed is the pragmatic path.


Sources & References:
1. Lewis et al. — "Retrieval-Augmented Generation" (2020) — https://arxiv.org/abs/2005.11401
2. Hu et al. — "LoRA: Low-Rank Adaptation" (2021) — https://arxiv.org/abs/2106.09685
3. LangChain — "RAG Documentation" — https://python.langchain.com/docs/concepts/rag/


Published by AmtocSoft | amtocsoft.blogspot.com
Level: Advanced | Topic: Fine-Tuning vs RAG

About the Author

Toc Am

Founder of AmtocSoft. Writing practical deep-dives on AI engineering, cloud architecture, and developer tooling. Previously built backend systems at scale. Reviews every post published under this byline.

LinkedIn X / Twitter

Published: 2026-04-11 · Written with AI assistance, reviewed by Toc Am.

Get These In Your Inbox

Weekly deep-dives on AI engineering, no fluff. Join the newsletter →

Subscribe (free)

Or grab the book ($39, ~100 pages) · Buy me a coffee

Buy Me a Coffee · 🔔 YouTube · 💼 LinkedIn · 🐦 X/Twitter

LoRA and QLoRA Explained: Fine-Tuning AI on a Budget

LoRA and QLoRA Explained Hero

LoRA and QLoRA Explained: Fine-Tuning AI on a Budget

Level: Advanced | Topic: Fine-Tuning | Read Time: 8 min


Traditional fine-tuning updates every parameter in a model. For a 7-billion parameter model, that means storing and updating 7 billion floating-point numbers. This requires multiple high-end GPUs and significant memory.

LoRA changed that. Low-Rank Adaptation is a technique that makes fine-tuning accessible to anyone with a single consumer GPU. QLoRA takes it further by adding quantization to the mix.

This article explains both techniques and shows why they have become the default approach for fine-tuning open-source models.

graph TB
  W[Original Weight Matrix W] --> F[Frozen\nNo Updates]
  W --> LR[Low-Rank Path]
  LR --> A[A Matrix\n4096 x r]
  A --> B[B Matrix\nr x 4096]
  F --> M[Merge: W + BA]
  B --> M
  M --> O[Adapted Output]

The Problem with Full Fine-Tuning

A 7B parameter model in float16 requires approximately 14 GB of GPU memory just to store the weights. During training, you also need memory for gradients and optimizer states, which typically triples the requirement to 42+ GB. That exceeds the capacity of most consumer GPUs.

For a 70B parameter model, full fine-tuning requires a cluster of A100 GPUs. For most developers and organizations, this is prohibitively expensive.


LoRA: The Key Insight

Architecture Diagram

LoRA is based on a simple but powerful observation: when you fine-tune a large language model, the weight updates tend to be low-rank. In other words, the changes can be approximated by much smaller matrices.

Instead of updating the full weight matrix W (which might be 4096 x 4096), LoRA freezes the original weights and trains two small matrices A and B:

  • A: 4096 x r (where r is typically 8, 16, or 32)
  • B: r x 4096

The effective update is the product A x B, which has the same dimensions as W but is parameterized by far fewer numbers. For rank r=16, you are training 131,072 parameters instead of 16,777,216. That is a 128x reduction.


What This Means in Practice

Metric Full Fine-Tuning LoRA (r=16)
Trainable parameters 7B (100%) ~55M (0.8%)
GPU memory required 42+ GB 8-12 GB
Training time (7B) Hours on A100 cluster 30-60 min on single GPU
Storage per adapter 14 GB 50-200 MB
Quality Baseline 95-99% of full fine-tuning

The quality trade-off is remarkably small. Research consistently shows LoRA achieving within a few percentage points of full fine-tuning on most benchmarks.


QLoRA: Adding Quantization

QLoRA combines LoRA with 4-bit quantization of the base model. Instead of loading the frozen weights in float16 (2 bytes per parameter), QLoRA loads them in 4-bit precision (0.5 bytes per parameter).

This reduces the memory footprint by another 4x. A 7B model that requires 14 GB in float16 needs only 3.5 GB in 4-bit quantization. Combined with LoRA's small adapter matrices, you can fine-tune a 7B model on a GPU with 6 GB of VRAM.

The key innovation is that QLoRA uses a technique called NormalFloat4 (NF4), which is information-theoretically optimal for normally distributed weights. Combined with double quantization (quantizing the quantization constants), it achieves quality nearly identical to float16 LoRA.


When to Use LoRA vs QLoRA

Use LoRA when: You have a GPU with 12+ GB VRAM and want the highest quality fine-tuning with minimal trade-offs.

Use QLoRA when: You have a consumer GPU (6-8 GB VRAM) and need to fine-tune within memory constraints. Or when fine-tuning larger models (13B, 70B) on limited hardware.

Use full fine-tuning when: You have enterprise GPU resources and need absolute maximum quality, or you are training a model from scratch.


Tools for LoRA Fine-Tuning

The ecosystem has matured rapidly:

  • Unsloth: Fastest LoRA training, 2-5x speedup over standard implementations
  • Hugging Face PEFT: The reference implementation, integrates with all HF models
  • Axolotl: Simplified config-driven fine-tuning with LoRA/QLoRA support
  • LLaMA-Factory: GUI-based fine-tuning with dozens of model templates

Practical Tips

  1. Start with rank r=16. Increase to 32 or 64 only if quality is insufficient.
  2. Apply LoRA to all linear layers, not just attention. Recent research shows this improves quality.
  3. Use a learning rate of 1e-4 to 3e-4. LoRA is less sensitive to learning rate than full fine-tuning.
  4. Train for 1-3 epochs. More epochs risk overfitting on small datasets.
  5. Use at least 1,000 high-quality training examples. Quality matters more than quantity.

Sources & References:
1. Hu et al. — "LoRA: Low-Rank Adaptation of Large Language Models" (2021) — https://arxiv.org/abs/2106.09685
2. Dettmers et al. — "QLoRA: Efficient Finetuning of Quantized Language Models" (2023) — https://arxiv.org/abs/2305.14314
3. Hugging Face — "PEFT: Parameter-Efficient Fine-Tuning" — https://huggingface.co/docs/peft


Published by AmtocSoft | amtocsoft.blogspot.com
Level: Advanced | Topic: Fine-Tuning, LoRA

About the Author

Toc Am

Founder of AmtocSoft. Writing practical deep-dives on AI engineering, cloud architecture, and developer tooling. Previously built backend systems at scale. Reviews every post published under this byline.

LinkedIn X / Twitter

Published: 2026-04-10 · Written with AI assistance, reviewed by Toc Am.

Get These In Your Inbox

Weekly deep-dives on AI engineering, no fluff. Join the newsletter →

Subscribe (free)

Or grab the book ($39, ~100 pages) · Buy me a coffee

Buy Me a Coffee · 🔔 YouTube · 💼 LinkedIn · 🐦 X/Twitter

What is Fine-Tuning? Customizing AI Models for Your Data

What is Fine-Tuning Hero

What is Fine-Tuning? Customizing AI Models for Your Data

Level: Beginner | Topic: Fine-Tuning | Read Time: 6 min


You have used ChatGPT or a local model like Llama and gotten decent results. But what if you need the model to speak in your company's voice, understand your industry's jargon, or follow your specific output format every time?

That is where fine-tuning comes in. It is the process of taking a pre-trained AI model and teaching it new behaviors using your own data.

graph LR
  A[Base Model] --> B[Training Dataset]
  B --> C[Fine-Tuning Process\nLoRA / Full]
  C --> D[Evaluation]
  D --> E[Merged Model]
  E --> F[Deployment]

The Cooking Analogy

Think of a pre-trained model like a culinary school graduate. They know how to cook. They understand flavors, techniques, and presentation. But they have never cooked your grandmother's recipes.

Fine-tuning is like giving that chef your family cookbook. They do not forget how to cook. They just learn your specific dishes on top of everything they already know. The result: a chef who combines world-class technique with your exact preferences.


How Fine-Tuning Works

Architecture Diagram

A pre-trained model like Llama 3.2 has already been trained on trillions of tokens from the internet. It understands language, reasoning, and a broad range of knowledge.

Fine-tuning adds a second, smaller training phase where you feed the model examples of the specific behavior you want:

  1. Collect training data: Pairs of inputs and desired outputs in your domain
  2. Format the data: Convert to the model's expected format (usually instruction-response pairs)
  3. Run training: Update the model weights using your examples
  4. Evaluate: Test the fine-tuned model against held-out examples

The model learns to pattern-match your specific use case while retaining its general knowledge.


What Fine-Tuning Can Do

  • Adopt a specific tone: Make the model write in your brand voice
  • Learn domain knowledge: Medical terminology, legal language, financial analysis
  • Follow output formats: Always return JSON, always use bullet points, always cite sources
  • Improve accuracy: On your specific task, fine-tuning often outperforms prompting
  • Reduce hallucinations: In a narrow domain, a fine-tuned model hallucinates less than a general one

What Fine-Tuning Cannot Do

  • It cannot teach the model entirely new factual knowledge (use RAG for that)
  • It cannot make a small model perform like a large one
  • It does not work well with tiny datasets (you need at least hundreds of examples)
  • It requires compute resources (though modern techniques like LoRA make this affordable)

Fine-Tuning vs Prompt Engineering vs RAG

Approach Best For Cost Complexity
Prompt Engineering Quick customization, one-off tasks Free Low
RAG Adding current knowledge, document Q&A Low-Medium Medium
Fine-Tuning Changing model behavior, domain specialization Medium Medium-High

The three approaches are complementary. Many production systems use all three: a fine-tuned model with RAG for knowledge and carefully engineered prompts for each task.


Getting Started

If you are new to fine-tuning, here is the recommended path:

  1. Start with prompt engineering. Many problems can be solved with better prompts.
  2. If prompting is not enough, try RAG. Add your documents to a vector database and retrieve them at inference time.
  3. If you need the model to fundamentally change its behavior, fine-tune using LoRA (covered in our next article).

The barrier to fine-tuning has dropped dramatically. With tools like Unsloth, Axolotl, and Hugging Face TRL, you can fine-tune a 7B model on a single GPU in under an hour.


Sources & References:
1. Hugging Face — "Fine-Tuning a Pretrained Model" — https://huggingface.co/docs/transformers/training
2. Unsloth — "Fine-Tune LLMs 2x Faster" — https://unsloth.ai/
3. Axolotl — "Fine-Tuning Framework" — https://github.com/axolotl-ai-cloud/axolotl


Published by AmtocSoft | amtocsoft.blogspot.com
Level: Beginner | Topic: Fine-Tuning

About the Author

Toc Am

Founder of AmtocSoft. Writing practical deep-dives on AI engineering, cloud architecture, and developer tooling. Previously built backend systems at scale. Reviews every post published under this byline.

LinkedIn X / Twitter

Published: 2026-04-09 · Written with AI assistance, reviewed by Toc Am.

Get These In Your Inbox

Weekly deep-dives on AI engineering, no fluff. Join the newsletter →

Subscribe (free)

Or grab the book ($39, ~100 pages) · Buy me a coffee

Buy Me a Coffee · 🔔 YouTube · 💼 LinkedIn · 🐦 X/Twitter

Attention Is All You Need, Explained Simply

We published a plain-language walkthrough of the 2017 transformer paper — queries, keys, values, multi-head attention, and why no-recurrence...