← Back to Technical Library

Fine-Tuning vs RAG vs Prompt Engineering

The Complete Decision Framework for LLM Customization -- When to Use Each, When to Combine, and When to Walk Away

Fine-Tuning vs RAG vs Prompt Engineering

Choosing the Right LLM Customization Strategy -- A Practitioner's Guide

📄 Technical Guide ⏱️ 28 min read 📂 Core AI Concepts

When organizations decide to customize a large language model for their specific use case, they face a critical decision: prompt engineering, retrieval-augmented generation (RAG), or fine-tuning? These are not competing technologies -- they are complementary tools that solve different problems at different cost points. This guide provides a complete decision framework, real cost numbers, code examples, and practical guidance for choosing the right approach (or combination) for your use case. The uncomfortable truth: most teams that reach for fine-tuning should be using RAG or prompt engineering instead.

Fine-TuningRAGLoRAPrompt EngineeringDecision Framework
🎯 Bottom Line: Start with prompt engineering. If you need current or proprietary knowledge, add RAG. Only fine-tune when you need to change the model's behavior, tone, or format in ways that prompting cannot reliably achieve. The vast majority of production LLM applications -- 80% or more -- are best served by prompt engineering alone or prompt + RAG. Fine-tuning is the right answer for a narrow set of problems: domain-specific jargon adaptation, consistent output formatting at scale, reducing token costs on high-volume tasks, and embedding a "house style" that persists across all interactions.

The Three Approaches at a Glance

Before diving into each approach in detail, here is the executive summary. These three methods exist on a spectrum of cost, effort, and capability. They are not mutually exclusive -- the most sophisticated production systems combine all three.

Dimension Prompt Engineering RAG Fine-Tuning
What it changes Input text sent to the model Context provided to the model at inference time Model weights (internal parameters)
Primary use case Task instructions, few-shot examples, output formatting Grounding in proprietary/current knowledge Behavior, tone, style, format adaptation
Time to implement Days to weeks Weeks to months
Cost per query Low (input tokens cost money) Medium (retrieval + input tokens)
Upfront cost $500 - $5,000 (infra setup) $50 - $50,000 (GPU + data prep)
Knowledge updates Update the prompt text Re-train the model (expensive)
Expertise required Intermediate (embeddings, vector DBs, retrieval) Advanced (ML engineering, data curation)
Hallucination risk High (no grounding) Medium (knowledge is baked in, not retrieved)
When to choose Default. Always start here. You need factual, updatable knowledge You need behavioral/style change at scale
The Escalation Principle: Always escalate from the cheapest, simplest approach to the next one only when you have evidence that the current approach is insufficient. Prompt engineering → prompt + RAG → prompt + RAG + fine-tuning. Skipping steps wastes money and time. A team that jumps straight to fine-tuning without first exhausting prompt engineering and RAG will almost certainly produce a worse, more expensive system than one that follows the escalation path.

Prompt Engineering: The First and Best Tool

What Is Prompt Engineering?

Prompt engineering is the practice of designing the input text (the "prompt") sent to a language model to produce the desired output. It is the lightest-weight customization method: you change nothing about the model itself. You only change what you feed it. Despite the hype around fine-tuning and RAG, prompt engineering remains the single most impactful and cost-effective technique for improving LLM output quality.

Modern models -- especially GPT-4, Claude 3.5, and Llama 3 at 70B+ -- are remarkably capable at following instructions. A well-crafted prompt can produce behavior that many teams mistakenly assume requires fine-tuning: consistent formatting, specific tones, multi-step reasoning, and even domain-specific responses when paired with context.

Core Prompt Engineering Techniques

  • Zero-shot prompting: Give the model a direct instruction with no examples. Surprisingly effective on modern models. "Summarize this article in 3 bullet points."
  • Few-shot prompting: Provide 2-5 examples of input → output pairs before the actual task. The model learns the pattern from examples. This is the workhorse of production prompt engineering.
  • Chain-of-thought (CoT): Ask the model to reason step-by-step before giving an answer. Dramatically improves accuracy on math, logic, and multi-step reasoning tasks. "Think through this step by step."
  • Role prompting: Assign the model a persona. "You are a senior cybersecurity analyst reviewing this code." This shapes tone, vocabulary, and the lens through which the model interprets the task.
  • Structured output instructions: Specify exact output format. "Respond in valid JSON with keys: title, summary, tags (array)." Modern models comply reliably when the instruction is explicit.
  • System prompts: A persistent instruction that frames all subsequent interactions. Used in chat applications to set behavior, constraints, and persona across an entire conversation.
  • Constraint prompting: Explicitly state what NOT to do. "Do not use external knowledge. Only use information from the provided context." This is critical for reducing hallucinations.
  • Decomposition: Break a complex task into smaller sub-tasks, each handled by a separate prompt. A "router" prompt classifies the input, then specialized prompts handle each category.

When Prompt Engineering Is Sufficient

Prompt engineering alone is the right answer when:

  • The task is well-defined and the model already has the underlying capability. Summarization, translation, code review, and question answering from provided context are all tasks that modern models handle with prompting alone.
  • Output formatting is the primary need. If you need JSON, XML, markdown, or a specific template, a clear prompt instruction works 95%+ of the time on modern models.
  • The knowledge base is small or static enough to fit in the context window. With 128K-token context windows now standard, you can paste entire documents into the prompt.
  • You are prototyping. Prompt engineering lets you iterate in minutes. Fine-tuning iteration takes days. RAG setup takes hours. For exploration, prompting is unmatched.
  • Cost sensitivity is high. Prompting has zero setup cost. You only pay for tokens used.
  • The model already understands the domain. Medical, legal, and coding tasks are well-represented in pre-training data. General medical reasoning often works without fine-tuning.

Limits of Prompt Engineering

Prompt engineering has real limits. Knowing them is essential for deciding when to escalate:

  • Context window limits: Even at 128K tokens, you cannot fit an entire knowledge base into a prompt. If you need the model to answer questions from 10,000 documents, prompting alone cannot work. This is where RAG becomes essential.
  • Inconsistency at scale: A prompt that works 95% of the time fails 5% of the time. In production at high volume, that 5% can be thousands of bad outputs. Fine-tuning can reduce variance, though it does not eliminate it.
  • Token costs: Repeating a 2,000-token system prompt on every API call costs money. At 1M calls/month, a 2K-token system prompt at $15/M input tokens costs $30,000/month. Fine-tuning can internalize those instructions, eliminating the repeated cost.
  • Inability to teach new capabilities: Prompting cannot teach a model to perform a task it fundamentally cannot do. If the model lacks the reasoning pattern, no prompt will create it. Fine-tuning can sometimes bridge this gap, but often the model architecture itself is the limit.
  • Style and tone consistency: While role prompts help, they are not perfectly reliable. A model prompted to "write like Hemingway" will approximate Hemingway but drift. Fine-tuning on 1,000 Hemingway passages produces more consistent style.
  • Domain-specific jargon: Specialized vocabulary (medical, legal, technical) that the model saw rarely in training may be used imprecisely. Fine-tuning on domain text improves fluency with jargon.
The 90% Rule: For 90% of use cases, prompt engineering -- possibly with few-shot examples and a well-crafted system prompt -- is the right starting point and often the right ending point. The temptation to jump to more complex methods is driven by the perception that "simple" means "unprofessional." It does not. A well-engineered prompt on a capable model is a production-grade solution.

A Practical Prompt Engineering Example

Here is a production-grade system prompt for a customer support assistant. Note the structure: role, constraints, output format, and explicit guardrails. This prompt alone, on GPT-4 or Claude 3.5, will outperform most fine-tuned smaller models:

SYSTEM: You are a customer support assistant for Acme Corp, a SaaS project management platform. Your role is to help users resolve issues with their accounts, billing, and product features. # CONSTRAINTS - Only answer questions about Acme Corp products and services. - If you do not know an answer, say "I don't have that information. Let me connect you with a human agent." Never guess. - Do not discuss competitors, pricing comparisons, or provide discounts unless explicitly authorized. - Keep responses under 150 words unless the user asks for detail. - Always end with: "Is there anything else I can help you with?" # OUTPUT FORMAT - Use a friendly, professional tone. - Use bullet points for multi-step instructions. - Bold key terms using markdown. # FEW-SHOT EXAMPLES User: How do I reset my password? Assistant: **To reset your password:** 1. Go to the login page at acme.com/login 2. Click **"Forgot password?"** below the sign-in form 3. Enter your account email address 4. Check your inbox for a reset link (valid for 30 minutes) 5. Follow the link to set a new password Is there anything else I can help you with? User: Do you integrate with Slack? Assistant: Yes! Acme Corp has a native Slack integration that lets you receive task notifications and create tasks directly from Slack messages. You can enable it under **Settings → Integrations → Slack**. Is there anything else I can help you with?

This prompt is approximately 350 tokens. On GPT-4o at $5/M input tokens, processing 100,000 conversations/month costs $175/month in input token costs for the system prompt. That is trivially cheap. There is no fine-tuning cost, no GPU cost, no data labeling cost. This is why prompt engineering is the default.

Retrieval-Augmented Generation (RAG)

What Is RAG?

Retrieval-Augmented Generation (RAG) is an architecture that combines a language model with an external knowledge store. Instead of relying solely on the knowledge baked into the model during pre-training, RAG retrieves relevant documents from a database at query time and inserts them into the model's context window. The model then generates its answer grounded in those retrieved documents.

RAG solves the fundamental limitation of LLMs: their knowledge is frozen at training time. A model trained in 2024 cannot answer questions about events in 2026. A model trained on public data cannot answer questions about your company's internal HR policies. RAG bridges this gap by externalizing knowledge -- the model becomes a reasoning engine that reads from your document store, not a static encyclopedia.

RAG Architecture: The Five Components

A production RAG system has five distinct components. Each is a potential point of failure and a potential point of optimization:

Component What It Does Common Choices
1. Document Store Stores your knowledge base (PDFs, docs, wikis, databases) PostgreSQL + pgvector, Pinecone, Weaviate, Qdrant, Milvus, Chroma
2. Embedding Model Converts text into vector representations (embeddings) for semantic search OpenAI text-embedding-3-small/large, BGE-large, E5-large-v2, Nomic Embed, Cohere embed-v3
3. Retrieval System Finds the most relevant documents for a given query using vector similarity Cosine similarity search, hybrid (keyword + vector), BM25 + vector fusion, re-ranking with Cohere Rerank or bge-reranker
4. Prompt Assembly Combines retrieved documents with the user query into a model-ready prompt Template with context block, system instructions, and guardrails
5. Generation Model Reads the assembled prompt and generates an answer GPT-4o, Claude 3.5 Sonnet, Llama 3 70B (local), Mistral Large, Gemini 1.5 Pro

The RAG Pipeline Step by Step

Here is what happens when a user asks "What is our company's remote work policy?" to a RAG system:

  • Step 1 -- Query embedding: The user's question is passed through the embedding model, producing a vector (e.g., 1536 dimensions for OpenAI's text-embedding-3-small).
  • Step 2 -- Vector search: The vector database finds the top-K most similar document chunks using cosine similarity. Typically K=3 to K=10. This takes 10-50ms.
  • Step 3 -- (Optional) Re-ranking: A cross-encoder re-ranks the retrieved chunks for relevance. This improves precision significantly, adding 50-200ms latency.
  • Step 4 -- Prompt assembly: The retrieved chunks are inserted into a prompt template: "Based on the following documents, answer the user's question. [DOCUMENTS]. Question: [QUERY]"
  • Step 5 -- Generation: The LLM reads the assembled prompt and generates an answer grounded in the retrieved documents.
  • Step 6 -- Citation: The system attaches source references to the answer so the user can verify the information.
Why RAG Beats Fine-Tuning for Knowledge: Fine-tuning bakes knowledge into model weights. When that knowledge changes, you must retrain. RAG externalizes knowledge into a document store. When knowledge changes, you update the documents. The model stays the same. For any use case where knowledge changes -- which is most use cases -- RAG is structurally superior to fine-tuning for knowledge injection.

When to Use RAG

  • Proprietary knowledge: Your company's documentation, policies, product catalogs, support tickets, internal wikis. The model has never seen this data. RAG is the only viable approach (fine-tuning would require constant retraining).
  • Current information: News, stock prices, weather, regulatory updates. Any data that changes over time. RAG retrieves the latest version from your store.
  • Large knowledge bases: When your corpus exceeds the model's context window (which is almost always, for real document collections). RAG scales to millions of documents.
  • Verifiable answers: RAG can cite sources. "According to Document X, section 3.2..." This is critical for legal, medical, and compliance use cases where traceability matters.
  • Reducing hallucinations: Grounding the model in retrieved documents dramatically reduces fabrication. The model has something concrete to read rather than generating from potentially unreliable internal knowledge.
  • Multi-source synthesis: When answers need to combine information from multiple documents (e.g., "Compare our Q3 and Q4 revenue per region"), RAG retrieves all relevant chunks and the model synthesizes them.

When RAG Alone Is Not Enough

RAG is not a silver bullet. It has its own limitations:

  • Retrieval failure: If the retrieval system cannot find the right documents, the model has nothing to ground on. This is the #1 failure mode in RAG systems. Improving retrieval (better chunking, re-ranking, hybrid search) is usually more impactful than swapping models.
  • Format and style consistency: RAG handles knowledge but not behavior. If you need the model to always respond in a specific format or tone, RAG alone will not enforce it reliably. This is where fine-tuning or strong prompt engineering is needed.
  • Complex reasoning over retrieved data: If the answer requires multi-hop reasoning (e.g., "Find all employees who worked on Project X, then check their certifications against our compliance requirements"), simple RAG may not retrieve all necessary pieces. Advanced RAG with query decomposition or agentic retrieval can help, but adds complexity.
  • Latency: RAG adds retrieval latency (50-200ms) on top of generation latency. For real-time applications, this can be noticeable. Caching frequent queries mitigates this.

Document Chunking: The Hidden Complexity

The most overlooked aspect of RAG is chunking -- how you split documents into retrievable pieces. Bad chunking destroys RAG quality. Good chunking makes it shine:

  • Fixed-size chunking: Split every N tokens (e.g., 512). Simple but can cut sentences and paragraphs mid-thought. A reasonable baseline.
  • Sentence/paragraph chunking: Split on natural boundaries. Better semantic coherence but variable chunk sizes.
  • Document-aware chunking: Use document structure (headers, sections, markdown). Preserves context. Best for structured documents like manuals and wikis.
  • Overlapping chunks: Include 50-100 tokens of overlap between adjacent chunks. Prevents losing context at chunk boundaries. A widely used best practice.
  • Small-to-big: Retrieve small chunks (for precise matching) but return the surrounding larger section (for complete context). Improves both retrieval precision and generation quality.
Chunking Is Not Optional Optimization: Chunking strategy has a larger impact on RAG quality than the choice of LLM or embedding model. We have seen RAG systems go from 40% answer accuracy to 85% accuracy purely by changing chunk size from 256 tokens to 512 tokens with 100-token overlap. No model change, no fine-tuning. Just better chunking. If your RAG system is underperforming, fix retrieval and chunking before anything else.

Fine-Tuning: The Heavy Artillery

What Is Fine-Tuning?

Fine-tuning is the process of continuing the training of a pre-trained language model on a smaller, task-specific dataset. Unlike prompt engineering (which changes the input) or RAG (which changes the context), fine-tuning changes the model's internal weights. The model learns from your data and its behavior shifts as a result.

Fine-tuning is powerful but expensive, time-consuming, and often unnecessary. The key insight: fine-tuning is for behavior, not for knowledge. If you want the model to know things, use RAG. If you want the model to behave differently -- to always respond in a specific format, to adopt a particular tone, to follow complex instructions without lengthy prompts -- fine-tuning is the right tool.

Types of Fine-Tuning

Not all fine-tuning is created equal. The three main approaches differ dramatically in cost, hardware requirements, and use cases:

Type What It Does VRAM Needed (7B model) Cost (cloud GPU) Best For
Full Fine-Tuning Updates all model weights. The model is permanently modified. 80-120 GB (2x A100 80GB or 4x A6000) Research, maximum quality, when you have the budget
LoRA (Low-Rank Adaptation) Trains small adapter matrices on top of frozen weights. Original model is unchanged; adapter is merged or loaded separately. 16-24 GB (1x A6000 or RTX 4090) Most production fine-tuning. Style, format, tone adaptation.
QLoRA (Quantized LoRA) Same as LoRA but base model is 4-bit quantized during training. Dramatically reduces VRAM. Budget fine-tuning, consumer GPUs, experimentation

Full Fine-Tuning

Full fine-tuning updates every parameter in the model. For a 7B parameter model, that means computing gradients for 7 billion weights on every training step. This requires enormous VRAM -- not just for the weights themselves, but for optimizer states (Adam keeps 2 additional copies), gradients, and activations. A 7B model in FP16 needs 14GB for weights, 14GB for gradients, 28GB for Adam optimizer states, and 10-20GB for activations. Total: 66-76GB minimum.

Full fine-tuning produces the highest quality results because the model has maximum flexibility to adapt. However, it also has the highest risk of catastrophic forgetting -- the model can lose capabilities it had before fine-tuning. For a 70B model, full fine-tuning requires multi-GPU setups (8x A100 80GB) and costs thousands of dollars per run. For most production use cases, LoRA achieves 95%+ of the quality at 5% of the cost.

LoRA (Low-Rank Adaptation)

LoRA is the most important advance in practical fine-tuning since the transformer architecture itself. The key insight: when fine-tuning a model for a specific task, the weight changes (the "delta") have low intrinsic rank. Instead of updating the full weight matrix W, LoRA adds a low-rank decomposition: W + ΔW = W + B×A, where A and B are small matrices (rank r, typically 8-64).

For a 4096×4096 weight matrix, full fine-tuning updates 16.7M parameters. LoRA with rank 16 updates only 2 × 4096 × 16 = 131K parameters -- a 128x reduction. The base model weights stay frozen. Only the small A and B matrices are trained. After training, the adapter (A × B) can be saved as a small file (10-100MB) and merged into the base model or loaded dynamically.

  • VRAM efficient: Only optimizer states for the small adapters are needed, not the full model. A 7B model can be LoRA-tuned on a single 24GB GPU.
  • Small adapter files: A LoRA adapter for a 7B model is typically 10-100MB, versus 14GB for the full model. This makes adapters easy to distribute, version, and swap.
  • Multiple adapters: You can train separate LoRA adapters for different tasks and swap them at inference time. One base model, many adapters -- each adding a different capability.
  • Quality: LoRA matches or closely approximates full fine-tuning quality for most tasks. The gap is typically 1-3% on benchmarks, often indistinguishable in production.
  • No catastrophic forgetting: Because the base model is frozen, its original capabilities are preserved. The adapter adds capabilities without removing them.

QLoRA (Quantized LoRA)

QLoRA, introduced by Dettmers et al. in 2023, is LoRA with a twist: the base model is quantized to 4-bit (NF4 -- NormalFloat 4) during training. This reduces the memory needed for the frozen base model from 14GB (FP16) to 3.5GB (4-bit) for a 7B model. Combined with the small LoRA adapter memory, a 7B model can be fine-tuned in 6-10GB of VRAM -- a single consumer GPU or even Google Colab's free tier.

QLoRA democratized fine-tuning. Before QLoRA, fine-tuning a 7B model required $10,000+ GPUs. After QLoRA, anyone with an RTX 3090 or a $10/month Colab subscription can fine-tune. The quality is slightly below full LoRA (due to 4-bit quantization noise), but the difference is small enough that QLoRA is the default recommendation for most practitioners.

QLoRA Key Techniques: QLoRA uses three innovations: (1) NF4 (NormalFloat 4-bit) -- a quantization format optimized for normally-distributed weights, (2) Double Quantization -- quantizing the quantization constants themselves to save additional memory, and (3) Paged Optimizers -- using NVIDIA unified memory to prevent out-of-memory errors during optimizer state updates. These three together enable 7B fine-tuning on 6GB VRAM.

When to Fine-Tune

Fine-tuning is the right choice only when you have clear evidence that prompt engineering and RAG are insufficient. The valid use cases are narrower than most people think:

  • Consistent output formatting at high volume: If you need the model to produce a specific structured format (JSON, XML, custom schema) on millions of calls and prompt instructions are not reliable enough, fine-tuning on 500-1,000 formatted examples can push reliability from 95% to 99.5%+.
  • Style and tone adaptation: Fine-tuning on 1,000-5,000 examples of your desired writing style (legal briefs, medical reports, brand voice) produces more consistent style than prompt instructions alone.
  • Reducing inference costs: Fine-tuning a smaller model (7B) on outputs from a larger model (GPT-4) can produce a model that performs nearly as well at a fraction of the inference cost. This is "distillation via fine-tuning."
  • Domain-specific language fluency: Medical, legal, or highly technical domains where the model's pre-training data is insufficient. Fine-tuning on domain text improves the model's fluency with specialized vocabulary and reasoning patterns.
  • Reducing prompt token costs: If your system prompt is 2,000 tokens and you make millions of calls, fine-tuning can internalize those instructions, reducing each call's input cost to near zero.
  • Custom classification or extraction: Fine-tuning on labeled examples for a specific classification task (sentiment, intent, entity extraction with custom entity types) often outperforms few-shot prompting, especially for niche categories.

The Decision Framework

This is the decision matrix we use with clients. It compares all three approaches across the dimensions that matter for production decisions: cost, time, expertise, maintenance, and use case fit.

Dimension Prompt Engineering RAG Fine-Tuning
Upfront Cost $500 - $5,000 (infra, embeddings, dev time) $50 - $50,000 (GPU, data labeling, ML eng time)
Ongoing Cost (per 1M queries) $5-$50 (API token costs) $10-$100 (API + vector DB + embeddings) $2-$30 (shorter prompts, but hosting/model cost)
Time to First Result 1-3 days 1-4 weeks (data prep + training + eval)
Time to Iterate Hours (update docs, re-index) Days to weeks (retrain, re-evaluate)
Expertise Needed Intermediate -- embeddings, vector DBs, Python Advanced -- ML engineering, data curation, eval
Maintenance Burden Medium -- keep docs updated, monitor retrieval quality High -- retrain when base model updates or data drifts
Knowledge Freshness Static (only what's in the prompt) Static (frozen at training time)
Hallucination Risk High -- no grounding Medium -- baked-in knowledge, no source citation
Source Citation No No -- knowledge is in weights, not citable
Output Format Consistency Medium (95% with good prompts) Medium (depends on prompt, not retrieval)
Style/Tone Consistency Medium (role prompts help but drift) Medium (same as prompt engineering)
Scalability of Knowledge Limited by context window Limited by training data and model capacity
Best Use Case General tasks, formatting, reasoning Q&A over proprietary knowledge, docs Style/format adaptation, cost reduction at scale
Worst Use Case Answering from a 10,000-doc knowledge base Teaching a new writing style or format Injecting frequently-updated knowledge

The Decision Flowchart

Use this sequential decision process for any new LLM application:

  • Step 1: Can a well-crafted prompt solve this? → If yes, done. Use prompt engineering.
  • Step 2: Does the model need knowledge it was not trained on? → Add RAG. Retrieve relevant documents and include them in the prompt.
  • Step 3: Does the model need to behave differently (style, format, tone) in ways that prompting cannot reliably enforce? → Consider fine-tuning. But first, try harder prompts and few-shot examples.
  • Step 4: Are you processing millions of calls where token cost savings from shorter prompts would justify training cost? ← Fine-tuning may be economically justified.
  • Step 5: Do you need all three? → Fine-tune for behavior, use RAG for knowledge, use prompt engineering for task instructions. This is the hybrid approach used by the most sophisticated production systems.
🎯 The 80/20 Rule of LLM Customization: 80% of use cases need only prompt engineering. 15% need prompt + RAG. 5% need fine-tuning (usually with RAG). If you are considering fine-tuning, pressure-test that decision: have you truly exhausted prompt engineering? Have you tried RAG? Do you have 500+ high-quality training examples? Do you have an evaluation framework to measure improvement? If any answer is "no," you are not ready to fine-tune.

Hybrid Approaches

The most effective production LLM systems combine multiple approaches. The three methods solve different problems, so they compose naturally. Here are the proven hybrid patterns:

Pattern 1: Prompt Engineering + RAG

This is the most common production pattern. RAG handles knowledge retrieval; prompt engineering handles task instructions, output formatting, and guardrails. The system prompt defines behavior ("You are a technical support assistant. Answer based on the provided documents. If the answer is not in the documents, say you don't know."). RAG retrieves and injects relevant documents. The model follows the prompt instructions using the retrieved context.

  • Use case: Customer support bot, internal knowledge base Q&A, documentation assistant.
  • Why it works: RAG provides the knowledge; prompts provide the behavior. Neither alone is sufficient.
  • Cost: Low to moderate. No training cost. API + vector DB costs only.
  • Complexity: Moderate. You need a retrieval pipeline and good prompt engineering.

Pattern 2: Fine-Tuning + RAG

Fine-tune the model for behavior (format, tone, domain fluency), then use RAG for knowledge retrieval at inference time. The fine-tuned model is better at following instructions and producing the right output format; RAG ensures it has the right information. This is the pattern used by enterprise systems that need both consistent behavior and current knowledge.

  • Use case: Medical documentation assistant (fine-tuned for medical report format, RAG for patient records and clinical guidelines).
  • Why it works: Fine-tuning cannot inject all medical knowledge and keep it current. RAG cannot teach the model to write in clinical documentation format. Together, they solve both problems.
  • Cost: High upfront (fine-tuning + RAG infra), moderate ongoing.
  • Complexity: High. Requires ML expertise for fine-tuning and retrieval engineering for RAG.

Pattern 3: Prompt Engineering + Fine-Tuning

Fine-tune the model to improve instruction following and format consistency, then use prompt engineering for task-specific instructions at inference time. This pattern is used when a base model is not reliable enough at following complex instructions, but the task itself varies enough that you still need flexible prompting.

  • Use case: Multi-purpose assistant that needs to handle 20+ different task types, each with its own prompt template, but all requiring consistent output formatting.
  • Why it works: Fine-tuning improves the model's baseline instruction-following ability; prompts handle task-specific variation.
  • Cost: Moderate upfront (fine-tuning), low ongoing.
  • Complexity: Moderate. No RAG infrastructure needed.

Pattern 4: All Three (Prompt + RAG + Fine-Tuning)

The full stack: fine-tune for domain behavior, RAG for knowledge, prompt engineering for task-specific instructions. This is what the most sophisticated enterprise systems do. It is also the most expensive and complex to build and maintain.

  • Use case: Enterprise-grade legal AI: fine-tuned on legal document format and reasoning, RAG over case law and statutes, prompt-engineered for specific task types (contract review, brief drafting, legal research).
  • Why it works: Each layer handles what it does best. Fine-tuning for deep behavioral adaptation, RAG for the massive and constantly-updating legal knowledge base, prompts for task routing and specific instructions.
  • Cost: Very high upfront, high ongoing.
  • Complexity: Very high. Requires a team with ML, retrieval, and prompt engineering expertise.
Hybrid Pattern Behavior Source Knowledge Source Typical Cost When to Use
Prompt + RAG Prompt instructions RAG retrieval Most common. Knowledge-heavy, behavior-simple.
Fine-Tune + RAG Fine-tuned weights RAG retrieval High Need consistent format AND current knowledge.
Prompt + Fine-Tune Fine-tuned + prompt Model's pre-training Medium Need better instruction following, no external docs.
All Three Fine-tuned + prompt RAG retrieval Very High Enterprise scale, maximum quality required.
Start Simple, Add Complexity Only When Justified: Every additional layer adds cost, latency, and maintenance burden. A prompt + RAG system that handles 90% of your needs is better than an all-three system that handles 95% but costs 5x more to build and maintain. Measure the gap. Only add complexity when the quality improvement justifies the cost.

Cost Comparison with Real Numbers

Costs are the deciding factor for most organizations. Here are real-world cost breakdowns as of mid-2026, using current API pricing and GPU rental rates. All numbers are for a 7B parameter model and 100,000 queries/month as a reference workload.

API Costs (Using Hosted Models)

Model Input Cost (per 1M tokens) Output Cost (per 1M tokens) Cost per Query (avg 500 in, 200 out) Monthly Cost (100K queries)
GPT-4o $5.00 $15.00 $0.0055 $550
GPT-4o-mini $0.15 $0.60
Claude 3.5 Sonnet $3.00 $15.00 $0.0045 $450
Claude 3 Haiku $0.25 $1.25 $0.0004 $40
Llama 3 70B (via Groq) $0.59 $0.79 $0.0005 $50
Google Gemini 1.5 Flash $0.075 $0.30

Note: These are base generation costs. For RAG, add the cost of embedding the query (negligible -- $0.0001 per query) and any vector database hosting fees ($20-$200/month for most managed services). For fine-tuned models hosted on your own GPU, see the next section.

GPU Costs for Fine-Tuning

GPU VRAM Rental Cost (per hour) What It Can Fine-Tune Typical Training Time (7B, LoRA) Cost per Training Run
RTX 4090 (local) 24 GB ~$0.40 (electricity + depreciation) 7B LoRA, 7B QLoRA 3-8 hours
A6000 (rental) 48 GB $0.80-$1.50 7B LoRA, 13B QLoRA 2-6 hours $1.60 - $9.00
A100 80GB (rental) 80 GB $2.00-$4.00 7B full FT, 70B QLoRA 2-5 hours $4.00 - $20.00
H100 80GB (rental) 80 GB $3.00-$8.00 7B full FT, 70B LoRA 1-3 hours $3.00 - $24.00
8x A100 80GB (rental) 640 GB $16-$32 70B full FT 4-12 hours
Google Colab Free (T4) 16 GB $0 7B QLoRA (barely) 6-12 hours
Google Colab Pro (A100) 40-80 GB $10/month subscription 7B LoRA, 13B QLoRA 3-8 hours

GPU Costs for Hosting (Inference)

If you fine-tune a model, you need to host it. This is the hidden cost that many teams overlook:

Hosting Option Model Size Monthly Cost (24/7) Throughput Cost per 100K Queries
RTX 4090 (local/self-hosted) 7B (Q4) ~$100 (electricity) ~50-100 queries/min
RunPod A6000 rental 7B (FP16) or 13B (Q4) ~$580-$1,080 ~100-200 queries/min ~$580-$1,080
vLLM on A100 (cloud) 7B-13B (FP16) ~$1,440-$2,880 ~200-500 queries/min ~$1,440-$2,880
Ollama (local, any GPU) 7B (Q4) $0 (own hardware) ~20-80 queries/min
The Hosting Cost Trap: Fine-tuning advocates often cite the low training cost ($5-$20 for a LoRA run) but ignore the ongoing hosting cost. A fine-tuned 7B model hosted on a cloud A100 costs $1,440+/month -- more than 100K GPT-4o-mini queries ($20/month). Fine-tuning only saves money if your query volume is high enough that the per-query savings offset hosting costs. The break-even point is typically 500K-2M queries/month, depending on the model sizes being compared.

Total Cost of Ownership (12-Month Estimate)

For a system processing 100,000 queries/month over 12 months, here is the total cost of ownership for each approach:

Approach Setup Cost Monthly Operating Cost 12-Month Total Notes
Prompt Engineering (GPT-4o-mini) Cheapest. Just API calls.
Prompt Engineering (GPT-4o) $0 $550 $6,600 Premium quality. Still no setup cost.
RAG (GPT-4o-mini + Pinecone) $1,000-$3,000 (dev time) $80-$150 $2,000-$4,800 Vector DB + embeddings + API. Grounded answers.
RAG (GPT-4o + Pinecone) $1,000-$3,000 $610-$710 $8,300-$11,500 Premium quality + knowledge grounding.
Fine-Tuned (LoRA, self-hosted) $2,000-$10,000 (data prep + ML eng) $100-$1,500 (hosting) $3,200-$28,000 High setup, variable hosting. Best at very high volume.
Fine-Tuned + RAG (self-hosted) $5,000-$20,000 $200-$2,000 $7,400-$44,000 Maximum quality and control. Enterprise scale.
🎯 Cost Summary: For most workloads under 500K queries/month, prompt engineering with a strong hosted API (GPT-4o-mini or Claude 3 Haiku) is the cheapest option by an order of magnitude. RAG adds modest cost for significant quality gains on knowledge tasks. Fine-tuning only becomes cost-competitive at very high query volumes (1M+/month) where the per-query cost savings from self-hosting offset the infrastructure and development costs.

Time Investment Comparison

Cost is not just money -- it is also engineering time. Here is the time investment for each approach:

Phase Prompt Engineering RAG Fine-Tuning
Initial build 1-3 days 1-2 weeks (data prep) + 1-3 days (training)
Evaluation setup 2-4 hours 1-2 days 3-5 days (need eval set for training + testing)
Iteration cycle 1-4 hours 1-3 days (retrain + re-eval)
Monthly maintenance 4-8 hours (doc updates, retrieval monitoring) 8-20 hours (model updates, eval, monitoring)
Time to production 1-2 weeks 4-8 weeks

Common Misconceptions

The LLM customization space is full of myths. These misconceptions cause organizations to waste money, time, and engineering effort on the wrong solutions. Here are the most damaging ones:

Misconception 1: "Fine-Tuning Is Always Better"

Reality: Fine-tuning is better for a narrow set of problems (behavior, style, format). For knowledge injection, RAG is structurally superior. For general tasks, prompt engineering on a capable model is often indistinguishable from fine-tuning in quality, at a fraction of the cost. In published benchmarks, RAG outperforms fine-tuning on knowledge tasks by 20-40%, while fine-tuning outperforms RAG on format/style tasks by 5-15%.

The "fine-tuning is always better" myth persists because it feels more sophisticated. Training a custom model sounds more impressive than writing a good prompt. But sophistication is in the results, not the method. A well-prompted GPT-4o will outperform a fine-tuned 7B model on almost any task, at lower cost.

Misconception 2: "RAG Is Just Search"

Reality: RAG is not search. Search returns documents. RAG returns answers. The critical difference is the generation step: RAG uses an LLM to read retrieved documents, synthesize information across multiple sources, and generate a coherent answer in natural language. Traditional search (even semantic search) returns a ranked list of documents and leaves the synthesis to the user.

Additionally, RAG includes components that pure search does not: query transformation (rewriting user queries for better retrieval), re-ranking (using cross-encoders to improve precision), chunking strategies (splitting documents for optimal retrieval), and citation/grounding (ensuring answers are traceable to sources). Calling RAG "search with an LLM on top" is technically true but massively understates the engineering complexity.

Misconception 3: "You Need Fine-Tuning for Domain-Specific Tasks"

Reality: Modern foundation models (GPT-4o, Claude 3.5, Llama 3 70B) are already trained on vast amounts of domain-specific data -- medical literature, legal cases, code, financial reports. For most domain tasks, a well-crafted prompt (with domain-specific instructions and few-shot examples) performs comparably to a fine-tuned model. Fine-tuning becomes necessary only when the domain is so specialized that the model's pre-training data is insufficient (e.g., proprietary internal systems, highly niche technical domains).

Test this yourself: before fine-tuning, try your domain task with GPT-4o and a detailed domain-specific prompt. If the output quality is acceptable, you do not need to fine-tune.

Misconception 4: "Fine-Tuning Eliminates Hallucinations"

Reality: Fine-tuning can actually increase hallucinations if the training data contains errors or if the model overfits to patterns that do not generalize. The only reliable way to reduce hallucinations is grounding -- providing the model with source material at inference time and instructing it to use only that material. That is what RAG does. Fine-tuning changes behavior; RAG provides grounding. If hallucination reduction is your goal, RAG (not fine-tuning) is the answer.

Misconception 5: "RAG Solves Everything"

Reality: RAG is only as good as its retrieval system. If the retrieval system cannot find the right documents, the model will hallucinate or say "I don't know" even when the answer exists in your knowledge base. A RAG system with poor chunking, a weak embedding model, or no re-ranking will perform worse than a good prompt engineering setup. RAG is not a magic wand -- it is a pipeline that must be engineered and tuned.

Misconception 6: "Prompt Engineering Is Just Writing Good Instructions"

Reality: Production prompt engineering involves systematic testing, A/B comparison, edge case handling, and iteration. It is closer to software engineering than creative writing. Advanced techniques include chain-of-thought, self-consistency (sampling multiple responses and majority-voting), tree-of-thought, and prompt chaining (decomposing tasks into multi-step pipelines). A well-engineered prompt system is a production asset that should be version-controlled, tested, and monitored.

Misconception 7: "You Need Millions of Examples to Fine-Tune"

Reality: For LoRA/QLoRA fine-tuning, 500-5,000 high-quality examples are often sufficient. Quality matters far more than quantity. 1,000 carefully curated, properly formatted examples will outperform 50,000 noisy, inconsistent ones. The key is having examples that clearly demonstrate the behavior you want. For instruction-tuning (the most common fine-tuning type), the format is typically: instruction, input (optional), output.

Misconception 8: "Fine-Tuned Models Are Smaller and Therefore Cheaper"

Reality: A fine-tuned 7B model requires GPU hosting, which costs $100-$2,800/month depending on the setup. A hosted API model (GPT-4o-mini) costs $20/month for 100K queries. The fine-tuned model is only cheaper when query volume is high enough to offset the hosting cost. For most small-to-medium applications, hosted APIs are cheaper even at equivalent quality. Calculate the break-even point before committing to self-hosting.

The Most Expensive Misconception: "We need to fine-tune our own model for data privacy." In most cases, this is false. Enterprise API providers (OpenAI, Anthropic, Google) offer zero-retention contracts and data processing agreements that legally prevent your data from being used for training. A fine-tuned self-hosted model provides no meaningful privacy advantage over a properly contracted API, while costing 10-100x more to build and maintain. Only fine-tune for privacy if you have a hard regulatory requirement (HIPAA with BAA, FedRAMP, air-gapped systems) that legally prohibits any external API calls.

CLI & Code Examples for Each Approach

Here are practical, runnable examples for each approach. These are designed to be starting points -- copy them, modify them, and test them.

1. Prompt Engineering with Ollama (Local)

Ollama lets you run LLMs locally. Here is prompt engineering with a system prompt and few-shot examples using the Ollama CLI and API:

# Install Ollama (one-time) curl -fsSL https://ollama.com/install.sh | sh # Pull a model ollama pull llama3:8b # Simple prompt via CLI ollama run llama3:8b "Explain quantum entanglement in 3 sentences." # System prompt with few-shot examples via API curl http://localhost:11434/api/chat -d '{ "model": "llama3:8b", "stream": false, "messages": [ { "role": "system", "content": "You are a technical writer. Convert user descriptions into clear, concise API documentation. Format: endpoint, method, parameters, response." }, { "role": "user", "content": "Get user by ID" }, { "role": "assistant", "content": "## Get User by ID\n\n- **Endpoint:** /api/users/{id}\n- **Method:** GET\n- **Parameters:** id (integer, required) - The user's unique identifier\n- **Response:** 200 OK with user object" }, { "role": "user", "content": "Create new order" } ] }' # Create a custom Modelfile with persistent system prompt # Save as Modelfile: FROM llama3:8b SYSTEM """ You are a SQL query assistant. Convert natural language questions to SQL for a PostgreSQL database with tables: users (id, name, email, created_at), orders (id, user_id, total, status, created_at), products (id, name, price). Always return only the SQL query, no explanation. """ # Build and run the custom model ollama create sql-assistant -f Modelfile ollama run sql-assistant "Show me all users who ordered in the last 7 days"

2. Prompt Engineering with OpenAI API (Python)

pip install openai import openai import json client = openai.OpenAI(api_key="your-api-key") # Structured output with system prompt response = client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "system", "content": """You are a data extraction assistant. Extract information from the user's text and respond as valid JSON with these keys: - name: string - email: string - phone: string or null - company: string or null Respond with ONLY the JSON, no other text.""" }, { "role": "user", "content": "Hi, I'm Jane Smith. You can reach me at jane@example.com or 555-0123. I work at Acme Corp." } ], temperature=0.1 # Low temp for consistency ) data = json.loads(response.choices[0].message.content) print(data) # {'name': 'Jane Smith', 'email': 'jane@example.com', # 'phone': '555-0123', 'company': 'Acme Corp'}

3. Simple RAG with curl (No Framework)

Here is a minimal RAG implementation using OpenAI's embeddings API and a simple in-memory vector store. No framework needed for a prototype:

pip install openai numpy import openai import numpy as np import json client = openai.OpenAI(api_key="your-api-key") # --- Step 1: Prepare your document store --- documents = [ "Our remote work policy allows employees to work from home up to 3 days per week. Full-time remote requires manager approval and a documented business case.", "PTO accrual: Employees accrue 15 days of PTO per year for years 1-3, 20 days for years 4-7, and 25 days for 8+ years. PTO can be carried over up to 5 days per year.", "The expense reimbursement process: Submit receipts within 30 days via the Expensify app. Manager approval required for expenses over $500. Reimbursement processed in the next pay cycle.", ] # --- Step 2: Embed all documents --- def embed(text): resp = client.embeddings.create( model="text-embedding-3-small", input=text ) return resp.data[0].embedding # Pre-compute document embeddings doc_embeddings = [embed(doc) for doc in documents] doc_embeddings = np.array(doc_embeddings) # --- Step 3: Retrieve relevant documents --- def retrieve(query, top_k=2): query_emb = np.array(embed(query)) # Cosine similarity scores = doc_embeddings @ query_emb / ( np.linalg.norm(doc_embeddings, axis=1) * np.linalg.norm(query_emb) ) top_idx = np.argsort(scores)[-top_k:][::-1] return [documents[i] for i in top_idx] # --- Step 4: Generate answer with retrieved context --- def rag_answer(query): retrieved = retrieve(query) context = "\n\n".join(retrieved) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "system", "content": f"""Answer the user's question based ONLY on the following context. If the answer is not in the context, say "I don't have that information." Context: {context}""" }, {"role": "user", "content": query} ], temperature=0.1 ) return response.choices[0].message.content # --- Step 5: Test it --- print(rag_answer("How many days can I work from home?")) # "Employees can work from home up to 3 days per week. # Full-time remote requires manager approval." print(rag_answer("How much PTO do I get after 5 years?")) # "Employees accrue 20 days of PTO per year for years 4-7."

4. RAG with curl (Bash-Only, Using API)

For a pure shell-based RAG prototype (useful for testing and CI/CD):

#!/bin/bash # Minimal RAG in bash - embeds query, retrieves, # and generates answer API_KEY="your-openai-api-key" QUERY="$1" # Step 1: Embed the query QUERY_EMB=$(curl -s https://api.openai.com/v1/embeddings \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"text-embedding-3-small\", \"input\": \"$QUERY\" }" | jq -r '.data[0].embedding') # Step 2: Search vector DB (example with Pinecone) # Replace with your actual Pinecone key and index URL RESULTS=$(curl -s "https://your-index.pinecone.io/query" \ -H "Api-Key: your-pinecone-key" \ -H "Content-Type: application/json" \ -d "{ \"vector\": $QUERY_EMB, \"topK\": 3, \"includeMetadata\": true }") # Step 3: Extract text from results CONTEXT=$(echo "$RESULTS" | jq -r \ '.matches[].metadata.text' | head -3) # Step 4: Generate answer curl -s https://api.openai.com/v1/chat/completions \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"gpt-4o-mini\", \"messages\": [ { \"role\": \"system\", \"content\": \"Answer based on this context only. If not in context, say I don't know.\n\n$CONTEXT\" }, { \"role\": \"user\", \"content\": \"$QUERY\" } ], \"temperature\": 0.1 }" | jq -r '.choices[0].message.content'

5. LoRA Fine-Tuning with Unsloth (Recommended)

Unsloth is 2x faster than HuggingFace transformers for LoRA training and uses less memory. This is the recommended way to fine-tune in 2026:

pip install unsloth from unsloth import FastLanguageModel import torch from trl import SFTTrainer from transformers import TrainingArguments from datasets import load_dataset # --- Step 1: Load model with LoRA --- model, tokenizer = FastLanguageModel.from_pretrained( model_name = "unsloth/llama-3-8b-bnb-4bit", # 4-bit QLoRA max_seq_length = 2048, dtype = None, # auto load_in_4bit = True, # QLoRA mode ) # --- Step 2: Add LoRA adapters --- model = FastLanguageModel.get_peft_model( model, r = 16, # LoRA rank (8, 16, 32, 64) target_modules = [ "q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj", ], lora_alpha = 16, # Usually 2x rank lora_dropout = 0, # 0 for optimized bias = "none", use_gradient_checkpointing = "unsloth", random_state = 3407, ) # --- Step 3: Prepare training data --- # Format: JSONL with "instruction", "input", "output" fields # Example dataset.jsonl: # {"instruction": "Classify sentiment", "input": "Great product!", "output": "positive"} # {"instruction": "Classify sentiment", "input": "Terrible service", "output": "negative"} dataset = load_dataset("json", data_files="dataset.jsonl", split="train") # Format prompt template alpaca_prompt = """Below is an instruction that describes a task, paired with an input. Write a response. ### Instruction: {} ### Input: {} ### Output: {}""" def formatting_func(examples): return [alpaca_prompt.format( examples["instruction"][i], examples["input"][i], examples["output"][i] ) for i in range(len(examples))] # --- Step 4: Train --- trainer = SFTTrainer( model = model, tokenizer = tokenizer, train_dataset = dataset, formatting_func = formatting_func, max_seq_length = 2048, args = TrainingArguments( per_device_train_batch_size = 2, gradient_accumulation_steps = 4, warmup_steps = 5, max_steps = 60, # Adjust for your dataset learning_rate = 2e-4, fp16 = not torch.cuda.is_bf16_supported(), bf16 = torch.cuda.is_bf16_supported(), logging_steps = 10, output_dir = "outputs", save_steps = 50, ), ) trainer.train() # --- Step 5: Save the LoRA adapter --- model.save_pretrained("my-lora-adapter") tokenizer.save_pretrained("my-lora-adapter") # --- Step 6: (Optional) Save merged model --- # This merges LoRA weights into base model model.save_pretrained_merged("my-merged-model", tokenizer, save_method = "merged_16bit")

6. LoRA Fine-Tuning with Axolotl (CLI-Based)

Axolotl is a CLI-based training tool that uses YAML configs. Simpler for repeatable training runs:

# Install Axolotl pip install axolotl[all] # Create config file: config.yml cat > config.yml << 'EOF' base_model: unsloth/llama-3-8b-bnb-4bit model_type: LlamaForCausalLM tokenizer_type: AutoTokenizer # LoRA settings adapter: qlora lora_r: 16 lora_alpha: 32 lora_dropout: 0.05 lora_target_modules: - q_proj - k_proj - v_proj - o_proj # Training settings sequence_len: 2048 sample_packing: true train_on_inputs: false micro_batch_size: 2 gradient_accumulation_steps: 4 num_epochs: 3 learning_rate: 0.0002 warmup_steps: 10 optimizer: adamw_torch lr_scheduler: cosine # Data datasets: - path: dataset.jsonl type: alpaca field_instruction: instruction field_input: input field_output: output output_dir: ./lora-output EOF # Start training accelerate launch -m axolotl.cli.train config.yml # Merge LoRA into base model python -m axolotl.cli.merge_lora config.yml # Export to GGUF for Ollama # (requires llama.cpp convert script) python convert_lora_to_gguf.py \ --base model.gguf \ --adapter lora-output/adapter_model.bin \ --output my-finetuned.gguf

7. Full Fine-Tuning with HuggingFace Transformers

For when you need maximum quality and have the GPU budget. This requires 2x A100 80GB or equivalent for a 7B model:

pip install transformers accelerate deepspeed import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling, ) from datasets import load_dataset # Load model in full precision model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-3-8B", torch_dtype=torch.bfloat16, device_map="auto", # Requires 2+ GPUs for 8B model in full FT ) tokenizer = AutoTokenizer.from_pretrained( "meta-llama/Llama-3-8B" ) tokenizer.pad_token = tokenizer.eos_token # Load and tokenize dataset dataset = load_dataset("json", data_files="dataset.jsonl", split="train") def tokenize(examples): return tokenizer( examples["text"], truncation=True, max_length=2048, padding="max_length", ) dataset = dataset.map(tokenize, batched=True) # Training arguments training_args = TrainingArguments( output_dir="./full-finetune-output", num_train_epochs=3, per_device_train_batch_size=1, gradient_accumulation_steps=16, learning_rate=2e-5, # Lower LR for full FT warmup_steps=100, logging_steps=10, save_steps=500, bf16=True, gradient_checkpointing=True, # DeepSpeed config for multi-GPU deepspeed="ds_config.json", ) trainer = Trainer( model=model, args=training_args, train_dataset=dataset, data_collator=DataCollatorForLanguageModeling( tokenizer, mlm=False ), ) trainer.train() model.save_pretrained("./my-full-finetuned-model")

8. Running a Fine-Tuned Model with Ollama

After fine-tuning and converting to GGUF, you can serve the model locally with Ollama:

# Create a Modelfile for your fine-tuned model cat > Modelfile << 'EOF' FROM ./my-finetuned.gguf TEMPLATE """{{ if .System }}<|system|> {{ .System }}<|end|> {{ end }}<|user|> {{ .Prompt }}<|end|> <|assistant|> """ PARAMETER stop "<|end|>" PARAMETER stop "<|user|>" PARAMETER temperature 0.3 PARAMETER top_p 0.9 EOF # Create the Ollama model ollama create my-custom-model -f Modelfile # Run it ollama run my-custom-model "Your query here" # Serve via API (same as any Ollama model) curl http://localhost:11434/api/chat -d '{ "model": "my-custom-model", "stream": false, "messages": [ {"role": "user", "content": "Your query here"} ] }'

When NOT to Fine-Tune (Most Cases)

This section is deliberately prominent because the most common mistake in LLM customization is fine-tuning when you should not. Here are the scenarios where fine-tuning is the wrong answer:

Scenario Why Fine-Tuning Is Wrong What to Do Instead
Injecting knowledge Knowledge in weights is frozen. Updates require retraining. No source citation.
Frequently changing data Model is outdated the moment training finishes. Constant retraining is impractical.
Low query volume (<10K/month) Training + hosting cost far exceeds API costs. No ROI.
No evaluation framework You cannot measure improvement. You will ship a model you cannot verify.
Fewer than 500 training examples Insufficient data for meaningful behavioral change. Model will overfit or not learn.
Task is well-handled by base model If GPT-4o + good prompt already works, fine-tuning adds cost without benefit.
Need for explainability/citations Fine-tuned models cannot cite sources. Knowledge is baked in, not traceable.
Team lacks ML expertise Fine-tuning without ML knowledge produces worse models, not better ones.
Need to switch models frequently Fine-tuning locks you to one base model. Switching means retraining.
Privacy/compliance (usually) Enterprise API contracts (zero-retention, DPA) usually suffice. Self-hosting is rarely legally required.
Prototyping/POC Fine-tuning iteration takes days. Prototyping needs minutes.
The Fine-Tuning Anti-Checklist: Do NOT fine-tune if ANY of the following are true:
✗ You have not tried prompt engineering with GPT-4o or Claude 3.5
✗ You have not tried RAG for knowledge-based tasks
✗ You have fewer than 500 high-quality training examples
✗ You have no evaluation dataset (50-200 examples with expected outputs)
✗ Your query volume is under 10K/month
✗ Your primary need is "knowing things" (use RAG)
✗ Your data changes more than once per quarter
✗ You cannot articulate what specific behavior the fine-tuned model should exhibit that prompting cannot achieve
✗ You do not have a GPU or budget for cloud GPU rental ($5-$50/run)
✗ You plan to skip evaluation and "just see if it works"
The One Valid Reason Most Teams Fine-Tune: Cost reduction at high volume. If you are processing 1M+ queries/month and a fine-tuned 7B model can replace GPT-4o at 1/10th the per-query cost, the math works. Training cost: $20 (QLoRA). Hosting cost: $100-$1,500/month. Savings vs GPT-4o API: $5,500/month - $1,500/month = $4,000/month. ROI in days. But this only works at scale. Below 100K queries/month, the API is cheaper.

Data Requirements for Fine-Tuning

If you have decided to fine-tune, your data is the single most important factor. Bad data produces a bad model, no matter how good your training setup is. Here is what you need:

Quantity: How Much Data Do You Need?

Fine-Tuning Type Minimum Viable Recommended Diminishing Returns Notes
Instruction tuning (LoRA) 100 examples 10,000+ examples Quality > quantity. 1,000 excellent examples beat 10,000 mediocre ones.
Instruction tuning (QLoRA) 100 examples 5,000+ examples Slightly less data needed due to 4-bit noise tolerance.
Full fine-tuning 1,000 examples 5,000-50,000 examples 100,000+ examples Full FT can absorb more data. Risk of catastrophic forgetting increases.
Domain adaptation (continued pretraining) 10,000 tokens 1M-100M tokens 500M+ tokens Raw domain text. For learning domain language, not specific tasks.
Style/tone adaptation 200 examples 10,000+ examples Examples should span diverse topics in the target style.
Format/structured output 200 examples 5,000+ examples Include edge cases and variations. Consistency is critical.

Quality: What Makes Good Training Data?

Data quality is more important than data quantity. Five quality dimensions matter:

  • Correctness: Every output must be the right answer. A single wrong example teaches the model the wrong behavior. Review every example manually for small datasets (<1,000).
  • Consistency: If you want JSON output, every single example must produce valid JSON. If one example has malformed JSON, the model learns that malformed JSON is sometimes acceptable.
  • Diversity: Examples should cover the full range of inputs the model will encounter in production. If all your examples are short queries, the model will struggle with long ones. Include edge cases, unusual inputs, and boundary conditions.
  • Format adherence: The format of your training data IS the format the model will learn. If you train on lowercase outputs, the model will produce lowercase. If you train on verbose explanations, the model will be verbose. Your data format is your specification.
  • No contradictions: If example A says "always cite sources" and example B has no citations, the model learns conflicting behavior. Audit your dataset for contradictions.

Format: How to Structure Training Data

The most common format for instruction tuning is JSONL (JSON Lines), with each line being one training example. Here are the standard formats:

Alpaca Format (Most Common)

# dataset.jsonl - one JSON object per line {"instruction": "Classify the sentiment of this text", "input": "The product arrived broken and late.", "output": "negative"} {"instruction": "Classify the sentiment of this text", "input": "Absolutely love this! Best purchase ever.", "output": "positive"} {"instruction": "Extract entities from this text", "input": "Apple announced the iPhone 15 in September 2023.", "output": "{\"organizations\": [\"Apple\"], \"products\": [\"iPhone 15\"], \"dates\": [\"September 2023\"]}"}

ChatML / Conversation Format

# conversation format (for chat models) {"messages": [ {"role": "system", "content": "You are a helpful coding assistant."}, {"role": "user", "content": "Write a Python function to reverse a string."}, {"role": "assistant", "content": "def reverse_string(s):\n return s[::-1]"} ]} {"messages": [ {"role": "system", "content": "You are a helpful coding assistant."}, {"role": "user", "content": "What is a decorator in Python?"}, {"role": "assistant", "content": "A decorator is a function that takes another function and extends its behavior without explicitly modifying it..."} ]}

Raw Text Format (For Domain Adaptation)

# Raw text -- one document per line or file # Used for continued pretraining / domain adaptation The patient presented with acute chest pain radiating to the left arm, consistent with ACS. ECG showed ST elevation in leads II, III, aVF, indicating inferior MI. Troponin I was elevated at 12.3 ng/mL... # Each line or file is a separate document # No instruction/output format needed # The model learns domain language patterns

Data Preparation Best Practices

  • Deduplicate: Remove exact and near-duplicate examples. Duplicates cause the model to over-weight those patterns.
  • Balance categories: If you have 800 positive sentiment examples and 50 negative, the model will be biased toward positive. Aim for roughly balanced categories.
  • Filter by length: Remove examples with empty outputs, extremely long outputs (>2048 tokens), or extremely short outputs (<5 tokens) unless they are intentionally edge cases.
  • Check tokenization: Ensure your examples fit within your model's max sequence length (typically 2048-8192 tokens). Truncation during training can destroy output quality.
  • Hold out test data: Reserve 10-20% of your data as a test set. Never train on it. Use it only for evaluation. Without a held-out test set, you cannot measure real improvement.
  • Include negative examples: For tasks where the model should sometimes say "I don't know" or "I cannot help with that," include examples of those refusals. Otherwise the model will attempt to answer everything.
  • Human review: For datasets under 1,000 examples, review every single example manually. For larger datasets, review a random sample of 100-200 examples.
The Garbage-In-Garbage-Out Law of Fine-Tuning: Fine-tuning amplifies the patterns in your data. If your data is noisy, the model becomes noisy. If your data is inconsistent, the model becomes inconsistent. If your data contains errors, the model learns errors -- and will reproduce them more reliably than a base model would. This is the danger of fine-tuning: it does not fix data quality problems, it amplifies them. Spend more time on data quality than on any other aspect of fine-tuning.

Where to Get Training Data

  • Manual annotation: Write examples by hand. Slow but highest quality. Best for small datasets (100-500 examples).
  • Production logs: Use real user queries and ideal responses from your existing system. This is the gold standard -- it reflects actual usage.
  • Synthetic data generation: Use GPT-4o or Claude 3.5 to generate training examples. Fast and scalable, but requires careful review. Quality can be excellent if the generation prompt is well-designed. Tools like Self-Instruct and Evol-Instruct can help.
  • Distillation: Use outputs from a larger model (GPT-4o) as training data for a smaller model (Llama 3 8B). This transfers capability while reducing inference cost. Very effective and widely used.
  • Public datasets: HuggingFace Datasets, OpenAssistant, Dolly, Alpaca. Good starting points but may not match your specific use case. Filter and adapt them.
  • Crowdsourcing: Platforms like Scale AI, Surge AI, or Prolific for larger annotation tasks. Cost: $1-$5 per example depending on complexity.

Evaluation: Proving Your Fine-Tuned Model Is Better

Without evaluation, you cannot know if fine-tuning helped or hurt. This is the most commonly skipped step and the most damaging omission:

  • Held-out test set: 50-200 examples not used in training. Run the base model and fine-tuned model on these. Compare outputs. Use human judgment or LLM-as-judge to score.
  • LLM-as-judge: Use GPT-4o to compare base vs. fine-tuned outputs. Prompt: "Which response is better? A or B. Consider accuracy, format, and helpfulness." Cost: ~$0.01 per comparison. Fast and surprisingly reliable.
  • Automated metrics: Exact match (for classification), BLEU/ROUGE (for generation), BERTScore (for semantic similarity). Useful but limited. Human review is still the gold standard.
  • Production A/B testing: Route 10% of traffic to the fine-tuned model, 90% to the base. Compare user satisfaction, task completion rates, and error rates. The ultimate test.
  • Regression testing: Ensure the fine-tuned model still handles tasks the base model could do. Fine-tuning can break existing capabilities (catastrophic forgetting). Test on a diverse task set, not just your target task.

References & Further Reading

Source Attribution

Source: Avondale.AI Technical Documentation Library
Category: Core AI Concepts
Type: Technical Reference Guide
License: CC BY 4.0

Foundational Papers

  • Hu et al. (2021). "LoRA: Low-Rank Adaptation of Large Language Models." arXiv:2106.09685 -- The original LoRA paper.
  • Dettmers et al. (2023). "QLoRA: Efficient Finetuning of Quantized LLMs." arXiv:2305.14314 -- QLoRA and NF4 quantization.
  • Lewis et al. (2020). "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks." arXiv:2005.11401 -- The original RAG paper.
  • Wei et al. (2022). "Chain-of-Thought Prompting Elicits Reasoning in Large Language Models." arXiv:2201.11903 -- CoT prompting.
  • Brown et al. (2020). "Language Models are Few-Shot Learners." arXiv:2005.14165 -- GPT-3 paper, few-shot prompting.
  • Ouyang et al. (2022). "Training language models to follow instructions with human feedback." arXiv:2203.02155 -- RLHF and instruction tuning.
  • Gao et al. (2023). "Retrieval-Augmented Generation for Large Language Models: A Survey." arXiv:2312.10997 -- Comprehensive RAG survey.
  • Wang et al. (2023). "Self-Instruct: Aligning Language Models with Self-Generated Instructions." arXiv:2212.10560 -- Synthetic data generation.

Tools & Frameworks

Further Reading

Suggested Citation:
Fine-Tuning vs RAG vs Prompt Engineering: The Complete Decision Framework. Avondale.AI Technical Documentation Library. Accessed June 2026. https://avondale.ai/technical/fine-tuning-vs-rag.html