RAG · Guide
RAG vs. Fine-Tuning: Choosing the Right Approach
Retrieval and fine-tuning solve different problems. This guide breaks down what each one actually changes, where each tends to fail, and how to decide with evidence instead of instinct.
- Author
- Priya Raman (sample)
- Published
- Reading time
- 9 min read
| Requirement | Prompt | RAG | Fine-tune |
|---|---|---|---|
| Knowledge changes often | weak fit | strong fit | weak fit |
| Answers must cite sources | weak fit | strong fit | weak fit |
| Consistent style or format | partial fit | partial fit | strong fit |
| Narrow, repetitive task | partial fit | weak fit | strong fit |
| Low setup effort | strong fit | partial fit | weak fit |
● strong fit · ◐ partial · ○ weak
When a model doesn't know enough about your domain, two options come up almost immediately: give it the right information at request time with retrieval-augmented generation (RAG), or change the model itself with fine-tuning. Teams often frame this as a one-time architectural choice. In practice it's a question about what kind of gap you have, and the answer is frequently “retrieval first, fine-tuning maybe later, for a narrower reason.”
This guide walks through what each approach actually changes, the failure modes of each, and a checklist you can run before committing engineering time.
What each approach actually changes
RAG changes the input. At request time you search a corpus — documents, tickets, product data — and place the most relevant passages into the prompt. The model's weights are untouched; it reasons over text you hand it. Update the corpus and the next request sees the new information.
Fine-tuning changes the model. You train on examples of inputs and desired outputs, and the weights shift toward producing outputs like those examples. It is good at teaching behavior: a consistent format, a house style, a classification scheme, the shape of a good answer. It is a poor and expensive way to teach facts, because facts absorbed into weights are hard to update, hard to attribute, and easy to blend into confident-sounding errors.
When RAG is the better fit
Retrieval is usually the right starting point when your knowledge changes, when answers need to be traceable to a source, or when different users are allowed to see different documents.
- Freshness matters. Pricing, policies, inventory, and internal docs change weekly. Re-indexing a document is cheap; retraining a model is not.
- Answers need citations. Because the source passages are in the prompt, you can ask the model to cite them and verify those citations programmatically.
- Access control is per user. You can filter retrieval by tenant, role, or document permissions. Weights can't enforce that boundary.
- The corpus is large or long-tailed. No training run will reliably memorize thousands of rarely asked details, but a search index can surface them on demand.
RAG has its own failure modes, and most of them live in the retrieval step rather than the model. Poor chunking splits the answer across passages, weak queries miss the relevant document, and too many loosely related passages dilute the context. When a RAG system gives a wrong answer, check whether the right passage was retrieved before you touch the prompt.
When fine-tuning earns its cost
Fine-tuning becomes worth considering when you have a stable, well-defined task, a meaningful number of high-quality examples, and evidence that prompting alone has plateaued.
- Consistent output shape. A classifier with a fixed label set or an extractor that must always emit the same structure can become more reliable with targeted examples.
- Tone and style at scale. If every response must follow a specific voice and long style instructions are eating your context budget, fine-tuning can move that behavior into the model.
- Latency and cost. A smaller fine-tuned model can sometimes match a larger general model on a narrow task, which may reduce per-request cost and latency. Verify this on your own eval set; it is not guaranteed.
Risks to plan for
Fine-tuning introduces a training pipeline, a dataset you must curate and version, and a model artifact you must evaluate and redeploy whenever the base model changes. Narrow training data can also degrade general capabilities the product quietly relied on. Budget for that ongoing ownership, not just the first training run.
Side-by-side comparison
| Concern | RAG | Fine-tuning |
|---|---|---|
| Primary purpose | Supply knowledge at request time | Shape behavior, format, and style |
| Updating information | Re-index changed documents | Rebuild dataset and retrain |
| Traceability | Answers can cite retrieved sources | No direct link from output to training data |
| Access control | Filter retrieval per user or tenant | Not enforceable in weights |
| Upfront effort | Ingestion, chunking, indexing, retrieval tuning | Example curation, training runs, model evaluation |
| Ongoing cost | Index storage and longer prompts | Retraining and redeploying as needs or base models change |
| Typical failure | Relevant passage not retrieved | Confident answers drifting from current facts |
Combining both approaches
The approaches are not mutually exclusive. A common mature pattern is a RAG system whose generator has been fine-tuned to use retrieved context well: cite passages in a fixed format, say “I don't know” when the context doesn't contain the answer, and stay within a defined tone. Retrieval supplies the facts; fine-tuning supplies the discipline. Reach for this only after the RAG baseline is measured and the remaining failures are clearly behavioral.
Whatever you choose, make the decision with the same eval set run against each candidate. The snippet below shows the shape of that comparison. The functions are placeholders for your own application code.
from collections.abc import Callablefrom dataclasses import dataclass # Placeholders for your own code: an eval set loader, a grader,# and one answer function per candidate approach.from app.evals import Case, grade, load_casesfrom app.pipelines import answer_prompt_only, answer_with_rag @dataclassclass Result: name: str pass_rate: float failed_ids: list[str] def evaluate(name: str, answer: Callable[[str], str], cases: list[Case]) -> Result: failed = [c.id for c in cases if not grade(c, answer(c.question))] return Result(name, 1 - len(failed) / len(cases), failed) if __name__ == "__main__": cases = load_cases("evals/product_qa.jsonl") # Start with the cheapest candidate; add a fine-tuned one only if needed. for name, fn in {"prompt_only": answer_prompt_only, "rag": answer_with_rag}.items(): r = evaluate(name, fn, cases) print(f"{r.name:<12} pass={r.pass_rate:.0%} failed={r.failed_ids[:5]}")A short decision checklist
- Write down the specific failure you're trying to fix, with three to five real examples.
- Classify each example: missing knowledge, wrong behavior or format, or both.
- Build a small eval set (even 30–50 cases is a useful start) and measure a prompt-only baseline.
- If failures are mostly missing knowledge, build a RAG baseline and check retrieval quality separately from answer quality.
- If failures are mostly behavioral, iterate on instructions and few-shot examples before considering training.
- Consider fine-tuning only when the task is stable, you have a curated example set, and prompting has measurably plateaued.
- Whatever you ship, keep the eval set and rerun it whenever prompts, data, or models change.
Examples and figures in this article are illustrative. Adapt thresholds and tooling to your own system and data.