Executive Snapshot
| Dimension | Prompt Engineering | RAG | Fine-Tuning |
|---|---|---|---|
| What it changes | The instructions and examples the model sees | The context supplied at inference time | The model weights themselves |
| Solves | Capability elicitation, format, task framing | Knowledge the model does not have or cannot have | Persistent behaviour, style, tone, narrow-domain reliability |
| Time to first result | Minutes | Days to weeks | Weeks |
| Marginal cost | Effectively free beyond token spend | Vector store, embeddings, retrieval engineering, ongoing index maintenance | Training compute, dataset curation, evaluation, redeployment per base-model revision |
| Knowledge freshness | Whatever fits in the prompt | Live — reindex and the answer changes | Frozen at training time |
| Data governance surface | Prompt logs | The index, its ACLs, and every document in it | The training set, permanently baked into weights |
| Reversibility | Instant | Fast (reindex, re-rank, change chunking) | Retrain or roll back to the base model |
| Failure mode when misused | Prompt bloat, brittle instruction stacking | Retrieving the wrong thing confidently | Expensive, stale, hallucinated "knowledge" |
Every cost and timeline above is a planning range for a typical enterprise team, not a quote. Model providers revise pricing, training options, and availability regularly — verify current provider documentation before you build a business case on any figure here.
TL;DR
- They are not competing options. Prompt engineering changes instructions, RAG changes context, fine-tuning changes weights. Most production applications use two of the three, and many use all three in different layers.
- Start with prompting. It is the only approach with a near-zero marginal cost and instant reversibility, and it resolves a surprising share of "the model can't do this" problems that get escalated straight to fine-tuning.
- Reach for RAG when the problem is knowledge, especially knowledge that changes: policies, tickets, product data, anything with a revision date.
- Reach for fine-tuning when the problem is behaviour — a house format the model keeps drifting from, a domain vocabulary it mangles, a tone the business insists on across thousands of outputs.
- Fine-tuning for knowledge is the industry's most expensive anti-pattern. It bakes facts into weights that cannot be updated, audited, or access-controlled, and it does not reliably eliminate hallucination.
- Evaluate before you switch approaches. Without a scored evaluation set, an approach change is a guess with a budget attached, and you will not be able to prove whether it helped.
- Enterprise constraints usually decide it. Data governance in the index, PII in the training set, and the model-update treadmill matter more to your architecture review than a few points of benchmark accuracy.
Introduction
An internal AI application gives a wrong answer, and someone in the room says "we should fine-tune it." That sentence is the single most common source of wasted AI budget in enterprise IT, because more often than not the wrong answer had nothing to do with the model's weights.
The three approaches operate at three different layers, and the useful question is never "which is best." It is: which layer is actually broken? A model that produces valid JSON but cites a policy withdrawn last quarter has a knowledge problem. A model that finds the right policy and then writes a rambling three-paragraph essay when you needed four bullet points has an instruction problem. A model that gets both right but calls your product "the platform" when the style guide says it must be named in full, every time, in every one of forty thousand generated support replies, has a behaviour problem.
This article defines each approach precisely, walks the decision drivers that separate them, gives you honest cost profiles rather than vendor ones, and closes with a decision framework and the enterprise constraints that usually settle the argument before the technical merits do.
What Each Approach Actually Changes
Prompt Engineering — changing the instructions
Prompt engineering shapes what the model is asked to do without changing anything about the model or its available information. It has grown well beyond "write a better sentence" and now covers four distinct techniques worth naming separately.
System prompts establish persistent role, constraints, and operating rules for every request in an application. This is where house style, refusal boundaries, output conventions, and tool-use policy belong. A well-written system prompt is a specification, not a personality sketch — it says what the output must contain, what it must never contain, and how to behave when the input is ambiguous.
Few-shot examples demonstrate the mapping from input to output rather than describing it. For anything with a non-obvious output shape — a triage classification, a structured summary, a specific ticket-note format — two or three worked examples usually outperform a paragraph of prose describing the same thing. Examples are also the strongest signal in a prompt, which cuts both ways: the model matches their length, tone, and structure, so a stale example freezes stale behaviour into the system.
Structured outputs constrain the response to a schema so downstream code can parse it reliably. Most major providers now support some form of schema-constrained output or strict tool-parameter validation, which removes an entire class of brittle post-processing: regex extraction, retry-on-parse-failure loops, and the stop-sequence tricks that older integrations still carry around. If your codebase has a json.loads() inside a retry loop, that is a prompt-layer problem with a platform-layer fix.
Task decomposition splits work the model handles poorly in one shot into steps it handles well. Extract, then classify, then draft — three cheap calls with checkable intermediate outputs frequently beat one expensive call whose failure you cannot localise.
The reason to start here is not that prompting is glamorous. It is that prompting is the only layer where you can test a hypothesis in ten minutes and revert it in one.
RAG — changing the context
Retrieval-Augmented Generation retrieves relevant material at inference time and places it in the prompt, so the model answers from documents rather than from memory. The pipeline is conceptually simple and operationally deep: ingest documents, chunk them, embed the chunks, store them with metadata, retrieve on query, optionally re-rank, then assemble the surviving chunks into context.
What RAG genuinely gives you is a set of properties fine-tuning cannot:
- Freshness. Reindex a document and the next answer reflects it. No retraining, no redeployment.
- Attribution. You can show the user which source produced the answer, which is often a hard requirement in regulated environments rather than a nice-to-have.
- Access control. Retrieval can be filtered by the requesting user's permissions before anything reaches the model. Weights cannot be filtered at all.
- Removability. A document deleted from the index is genuinely gone from future answers.
What RAG does not give you for free is quality. Retrieval quality is an engineering discipline in its own right: chunk size and overlap, whether to embed summaries alongside raw text, hybrid keyword-plus-vector search, metadata filtering, re-ranking, and knowing when to retrieve nothing at all. The default failure is not "no answer" — it is a confident answer built on three chunks that were superficially similar to the question and substantively irrelevant.
Security trimming belongs in the query, not in a post-filter on the answer:
# Filter at retrieval time, using the caller's identity — never after generation.
# By the time text reaches the model, an access decision has already been made.
results = index.search(
query_vector=embed(user_question),
top_k=8,
filter={
"tenant_id": user.tenant_id,
"classification": {"$in": user.clearances}, # e.g. ["public", "internal"]
"group_ids": {"$overlaps": user.group_ids}, # ACLs copied at ingest
"effective_date": {"$lte": today},
"superseded": False,
},
)
# Retrieval returning zero rows is a valid, correct outcome.
# Say so, rather than answering from the model's own parametric memory.
if not results:
return "No accessible source document covers this question."
Fine-Tuning — changing the weights
Fine-tuning continues training a base model on your own examples, adjusting weights so the resulting model behaves differently by default. The mainstream technique in enterprise settings is parameter-efficient fine-tuning — training a small set of adapter weights rather than the full network — which is dramatically cheaper than full fine-tuning and is what most managed services expose.
Fine-tuning is genuinely the right tool for a specific and narrower set of problems than its reputation suggests:
- Format and structure adherence the model keeps drifting from despite clear instructions, at a scale where prompt tokens for examples become material.
- Tone and voice that must be consistent across very high volumes of output.
- Domain vocabulary and conventions — regulatory phrasing, clinical shorthand, internal ticket taxonomies — where the base model's general-purpose habits are subtly wrong.
- Latency and cost reduction by moving a long, example-heavy prompt into the weights, so each request sends fewer tokens.
- Task specialisation on a smaller model, letting a cheaper model match a larger one on one narrow job.
Notice that none of those are "teaching the model facts."
The Decision Drivers
Three questions separate the approaches more reliably than any benchmark.
Is the missing thing information? If the correct answer depends on something the model was never trained on, or something that changed after training, or something that differs per customer, you have a retrieval problem. Adding instructions will not conjure the information, and training on it will freeze a snapshot of it.
Is the missing thing behaviour? If the model has all the information and still produces output in the wrong shape, register, or level of detail, you have a prompting problem first and possibly a fine-tuning problem second. The order matters: prompt until you plateau, then measure whether the plateau is high enough. If a strong system prompt plus few-shot examples gets you to ninety percent format compliance and the business needs ninety-nine, that gap is what fine-tuning is for.
Is the missing thing capability? Sometimes the model simply cannot do the task well at the reasoning depth requested. That is not a prompting or retrieval failure. The remedies are a more capable model, more inference-time reasoning effort where the provider exposes it, or decomposing the task into steps the current model handles reliably. Fine-tuning a weaker model rarely closes a genuine reasoning gap; it mostly makes the weaker model fail in a more consistent house style.
Cost Profiles, Honestly
Vendor comparisons tend to price the compute and ignore the labour. The labour is the cost.
Prompt engineering is effectively free at the margin. You pay for the tokens you were already paying for, plus a modest increase for examples and instructions — partly recoverable through prompt caching if your provider supports it and your prompt prefix is stable. The real cost is attention: someone has to own the prompt, version it, and re-test it when the model changes. Budget for that ownership and it stays cheap; leave it unowned and it silently rots into a pile of contradictory instructions nobody dares delete.
RAG has a genuine infrastructure bill — a vector store or search service, embedding generation at ingest and query time, and compute for re-ranking — but the infrastructure is usually the smaller half. The larger half is retrieval-quality engineering and ongoing index maintenance: connectors that keep sources current, handling of deletions and permission changes, chunking strategies revisited as document types change, and a monitoring story for "the index went stale and nobody noticed." Plan for a permanent part-time owner, not a project with an end date.
Fine-tuning carries the most under-estimated cost, and almost none of it is the training run. Dataset curation dominates: assembling, cleaning, de-duplicating, and reviewing enough high-quality examples that the model learns the pattern rather than the noise. Then evaluation, because a fine-tuned model that is better on your target metric and quietly worse on everything else is a real and common outcome. Then the recurring cost nobody puts in the business case: every base-model revision restarts the cycle. When the provider ships a better base model, your tuned model does not inherit the improvement. You re-tune, re-evaluate, and re-deploy, or you stay on an ageing base while your competitors move.
That treadmill is the single strongest argument for keeping fine-tuning as the last mile rather than the foundation.
The "Fine-Tuning for Knowledge" Anti-Pattern
The most persistent misconception in enterprise AI is that fine-tuning is how you teach a model your company's information. It is worth being precise about why this fails.
- It does not reliably work. Facts injected via fine-tuning are absorbed as statistical tendencies, not as retrievable records. The model becomes more likely to produce something that looks like your documentation, which is not the same as producing what your documentation says.
- It does not stop hallucination — it can worsen it. Training a model to answer confidently in a domain teaches confident phrasing along with the content. When the pattern is present but the specific fact is not, you get a fluent, well-formatted, wrong answer.
- It cannot be access-controlled. Anything in the training set is available to every user of that model. There is no per-user filtering of weights. If your corpus mixes classifications, fine-tuning collapses that boundary permanently.
- It cannot be updated or retracted. A policy revision means a retraining cycle. A document that should never have been included means retraining from a corrected dataset — there is no delete.
- It has no attribution. You cannot show a user the source, because there isn't one.
RAG has the inverse properties on all five points. That is the whole argument. If your requirement contains the words "current," "per-user," "auditable," or "must cite," it is a retrieval requirement.
The legitimate overlap is thin but real: fine-tuning can teach a model the shape of your domain — its vocabulary, its document conventions, how a well-formed answer in your field reads — while RAG supplies the facts. Shape in the weights, facts in the context.
The Decision Framework
Run this per capability, not per application. A single product often lands in three different places for three different features.
flowchart TD
A[Output is wrong] --> B{Missing facts}
B -->|Yes| C[Use RAG]
B -->|No| D{Wrong format or tone}
D -->|Yes| E{Prompt closed the gap}
E -->|Yes| F[Prompt engineering]
E -->|No| G[Fine-tune the last mile]
D -->|No| H{Task too hard}
H -->|Yes| I[Stronger model or decompose]
H -->|No| F
C --> J[Re-measure on the eval set]
F --> J
G --> J
I --> J
The loop back to measurement is the part teams skip. Every branch is a hypothesis, and the eval set is how you find out whether the hypothesis was right before the change reaches production.
The Hybrid Reality
Ask a working team what they run in production and the answer is almost never one technique.
The common enterprise shape is prompting plus RAG, with a carefully written system prompt that tells the model how to use retrieved context, what to do when retrieval returns nothing, and how to structure its citations. This combination covers the large majority of internal knowledge assistants, support-deflection tools, and document-analysis workflows.
Fine-tuning enters as the last mile, typically after the prompt-and-retrieval system is already in production and its remaining failures have been characterised. By that point you have something you did not have at the start: real traffic, real failure examples, and a labelled dataset that is a by-product of operating the system rather than a project you had to fund separately. Fine-tuning from production data you already collected is a fundamentally better proposition than fine-tuning from a dataset someone assembled speculatively in week two.
There is also a cost-shaped hybrid worth knowing: fine-tune a smaller, cheaper model on a narrow, high-volume task that a larger model currently handles with a long prompt. You move the prompt into the weights, drop the per-request token count, and often improve latency. That is an optimisation to reach for once volume justifies it — not an architecture to start from.
Evaluate Before You Switch Approaches
Changing approach without an evaluation set is not engineering. Before you spend a fine-tuning budget, you need to be able to answer: what percentage of representative cases does the current system get right, and by what definition of right?
Start with a modest, versioned set of cases drawn from real usage — fifty is enough to be useful, a few hundred is comfortable — each with an input, an expected property, and a check that can be scored automatically where possible.
[
{
"id": "policy-current-001",
"input": "What is the current expense limit for domestic travel?",
"expects": { "cites_doc": "TRAVEL-POLICY-v7", "contains": "per diem" },
"must_not_contain": ["v6", "superseded"],
"tests": "knowledge freshness"
},
{
"id": "format-triage-014",
"input": "Printer offline in the Dublin office, third time this week.",
"expects": { "json_schema": "triage_v2", "severity": "medium" },
"tests": "output structure"
},
{
"id": "refusal-oos-003",
"input": "Draft a termination letter for an underperforming employee.",
"expects": { "refuses": true, "routes_to": "HR" },
"tests": "scope boundary"
}
]
Then run every candidate configuration against the same set and compare like with like:
import json, statistics
CASES = json.load(open("evals/cases.json"))
def score(case, output):
"""Return 1.0 / 0.0 per case. Keep checks mechanical wherever possible;
reserve model-graded scoring for genuinely subjective criteria."""
checks = []
exp = case["expects"]
if "contains" in exp:
checks.append(exp["contains"].lower() in output.text.lower())
if "cites_doc" in exp:
checks.append(exp["cites_doc"] in output.citations)
if "json_schema" in exp:
checks.append(validates(output.text, exp["json_schema"]))
for banned in case.get("must_not_contain", []):
checks.append(banned.lower() not in output.text.lower())
return 1.0 if checks and all(checks) else 0.0
def evaluate(variant_name, run):
"""`run` is any callable taking a question and returning an output object —
prompt-only, prompt+RAG, or a fine-tuned variant. Same cases, same scorer."""
scores = [score(c, run(c["input"])) for c in CASES]
by_test = {}
for c, s in zip(CASES, scores):
by_test.setdefault(c["tests"], []).append(s)
print(f"{variant_name}: overall {statistics.mean(scores):.1%}")
for test, values in sorted(by_test.items()):
print(f" {test:24} {statistics.mean(values):.1%} (n={len(values)})")
evaluate("prompt-only", run_prompt_only)
evaluate("prompt+rag", run_with_retrieval)
evaluate("prompt+rag+tuned", run_tuned)
The per-category breakdown is the point. An aggregate score that improves while your scope-boundary category quietly regresses is exactly the outcome that reaches production and then reaches your incident review. Categories also tell you which layer to change: a knowledge-freshness category failing while structure passes is a retrieval finding, not a prompting one.
Enterprise Concerns That Usually Decide It
Data governance in the RAG index. The index inherits every access-control question your source systems have, and adds a few. Copy ACLs at ingest and filter at query time; re-sync permissions on a schedule, because a user removed from a group in the source system remains able to retrieve that group's documents until the index learns about it. Handle deletions explicitly. Log which documents were retrieved for which user, because "what did the system show them" is the first question any investigation asks. Treat the index as a system of record for access purposes, not as a cache.
PII in training sets. A fine-tuning dataset assembled from production traffic will contain personal data unless someone actively removes it, and once trained, it cannot be removed without retraining. Build de-identification into the dataset pipeline rather than reviewing samples afterwards, document lawful basis before collection rather than during audit, and keep the dataset itself under the same retention and access controls as the source data. Check your provider's terms on whether submitted training data is used for their own model improvement — the answer varies by provider and by tier, and it is a question your legal team will ask.
The model-update treadmill. Base models improve on a cadence measured in months. A prompt-and-RAG system generally inherits those improvements by changing a model identifier and re-running the eval set. A fine-tuned system does not: it needs re-tuning, re-evaluation, and re-deployment before it can move, and until it does, it sits on an ageing base. Factor a recurring re-tuning cycle into the running cost of any fine-tuned component, and hold that cost against the benefit before you commit.
Provider availability differs, and it moves. Managed fine-tuning is offered on Azure OpenAI for a subset of models, with the available models, training methods, regional availability, and deployment options changing over time. Anthropic's platform emphasises prompting, tool use, and retrieval patterns; check current Anthropic documentation for what customisation options are available to your account type rather than assuming parity with other vendors. Open-weight models hosted on your own infrastructure or via a managed endpoint give you the broadest fine-tuning freedom and hand you the corresponding operational burden — serving, scaling, evaluation, and security are all yours. Because all three of these landscapes shift, verify current provider documentation for supported models, regions, quotas, and pricing before committing to an architecture, and again before you sign anything.
Pitfalls to Avoid
- Jumping to fine-tuning after a single bad demo. Characterise the failure first. Most "the model can't do this" reports are prompt or retrieval findings.
- Building RAG without measuring retrieval separately. If you only score the final answer, you cannot tell a retrieval failure from a generation failure. Score whether the right chunk was retrieved as its own metric.
- Treating chunking as a solved default. Chunk size, overlap, and boundary strategy interact with your document types. The defaults in a tutorial were tuned for that tutorial's corpus.
- Letting the system prompt accumulate. Instructions added to patch individual incidents pile into a contradictory wall. Periodically audit and delete; a prompt written against last year's model is often actively harmful against this year's.
- Fine-tuning on a dataset assembled in a hurry. A few hundred inconsistent examples teach inconsistency very effectively.
- No rollback plan for a tuned model. Keep the base-model configuration deployable and tested, so a regression is a switch rather than a project.
- Comparing approaches on different test sets. The only fair comparison is the same cases, the same scorer, the same day.
Troubleshooting
The answer is fluent, confident, and factually wrong
Check retrieval before you touch anything else. Log the retrieved chunks for the failing query and read them. Usually one of three things is true: nothing relevant was retrieved and the model answered from memory, something superficially similar was retrieved, or the right chunk was retrieved but ranked below the context cutoff. Only the third is a ranking problem; the first is a prompt problem (the model should decline) and the second is an embedding or filtering problem.
The model ignores retrieved context and answers from its own knowledge
A system-prompt issue. State explicitly that answers must come from the provided context, and that "no relevant source was found" is a valid and preferred response. Then verify the context is actually reaching the model in the position you think it is — a context block appended after a long instruction stack is easy to under-weight.
Output format is right in testing and wrong in production
Production inputs are messier than test inputs. Add the messy cases to the eval set, then use schema-constrained output if your provider supports it rather than adding more prose instructions about formatting.
The fine-tuned model is better on the target task and worse elsewhere
Expected, and the reason a broad evaluation set matters. Either narrow the deployment so the tuned model handles only its specialised task and a general model handles the rest, or rebalance the training data to include general examples.
Answers went stale after a policy update
An ingestion pipeline problem, not a model problem. Check when the source was last crawled, whether the superseded version was removed rather than merely supplemented, and whether the retrieval filter excludes superseded records. Two live versions of one policy in an index is a very common cause of confident contradictions.
A user retrieved a document they should not have seen
Compare the ACLs copied at ingest with the current permissions in the source system, and check whether filtering happens at query time or after generation. Post-generation filtering does not help — the content already reached the model and, in most designs, the response.
Key Takeaways
- Prompt engineering changes instructions, RAG changes context, fine-tuning changes weights. Diagnose which layer is broken before choosing a remedy.
- Prompting is the cheapest and most reversible lever, and it resolves more problems than its reputation suggests. Exhaust it first.
- RAG is the correct answer whenever the requirement involves freshness, per-user access, attribution, or the ability to retract information.
- Fine-tuning is for behaviour, format, tone, and domain conventions — plus cost and latency optimisation on high-volume narrow tasks. It is not how you teach a model facts.
- The real cost of fine-tuning is dataset curation, evaluation, and the recurring re-tuning cycle every time the base model improves.
- Production systems are hybrids: prompting and RAG as the foundation, fine-tuning as a deliberate last mile once you have real failure data.
- An evaluation set with per-category scoring is the prerequisite for every approach decision. Without it, you cannot prove a change helped.
Next Steps
- Classify your current failures for one week. Tag each one as missing information, wrong behaviour, or insufficient capability. The distribution tells you where to invest.
- Build a fifty-case evaluation set from real traffic, with categories that map to those failure types, and check it into version control alongside the prompt.
- Score your current system and record the baseline before changing anything.
- Exhaust the prompt layer — a specification-grade system prompt, two or three current few-shot examples, and schema-constrained output where your provider supports it. Re-score.
- If freshness or attribution is failing, build retrieval and measure retrieval accuracy as its own metric, separate from answer quality.
- Only then consider fine-tuning, using failure examples your production system has already collected, and price the recurring re-tuning cycle into the business case before you start.
- Verify provider specifics — supported models, fine-tuning availability, regions, quotas, data-handling terms — against current documentation, because all four change.
Related Articles
- LangGraph vs CrewAI: Choosing an Agent Framework in 2026 — the orchestration layer above these three techniques
- Prompt Caching with the Anthropic SDK: Cut Token Costs by 90% — how to make a large, stable prompt prefix affordable
- Missing AI Guardrails: When Your Copilot Serves Data Users Shouldn't See — what happens when retrieval-time access control is an afterthought
- Multi-Vendor LLM Orchestration: The Advocate-Adjudicator Pattern — routing work across providers when no single model wins
Last reviewed: 2026-08-09 | Provider capabilities for fine-tuning, structured outputs, and prompt caching change frequently across Azure OpenAI, Anthropic, and open-weight hosting platforms. Verify supported models, regions, quotas, and data-handling terms against current provider documentation before committing to an architecture.
Leave a Reply