You’ve got a problem that needs an LLM to solve it. Now you’re staring at three paths: fine-tune a model, engineer a better prompt, or build a retrieval-augmented generation (RAG) pipeline. Each one costs different amounts of time and money. Each one fails in different ways. Picking wrong burns weeks.
The Core Tension: Behavior vs Knowledge vs Both
Before you choose, understand what each approach actually changes.
Prompt engineering modifies how a model reasons through a single request. You’re not changing the model’s weights. You’re changing the input.
RAG changes what context the model sees. You retrieve relevant documents or data, inject them into the prompt, and let the model work from that grounded information instead of relying on training data from 6 months ago.
Fine-tuning changes the model itself. You retrain weights on task-specific examples until the model internalize patterns you care about. This is the only approach that actually makes the model remember something new.
These aren’t competitors. They’re layers. And most production systems use two or all three.
When Prompt Engineering Wins (It’s Often Enough)
Start here. Seriously. Prompt engineering is free if you’re already paying for API access.
It works when:
- The model already knows how to solve the problem — it just needs clearer instructions
- Failures are inconsistent reasoning, not missing knowledge
- Your task involves reasoning over information the model was trained on
Example: You need Claude Sonnet 4 to extract structured data from customer emails. Raw prompt fails 15% of the time because the model skips fields or hallucinates values.
Bad prompt:
Extract customer data from this email:
{email_text}
Improved prompt:
Extract customer data from this email. Return valid JSON only. If a field is not present in the email, use null. Do not invent values.
Required fields: name, email, phone, company, issue_category
Email:
{email_text}
JSON:
The second version drops error rate to 3% in most cases. No retraining. No vector databases. Just specificity about format, constraints, and what to do when information is absent.
Cost: 30 minutes of iteration.
When RAG Fixes What Prompting Can’t
RAG isn’t for reasoning problems. It’s for knowledge problems.
Use RAG when:
- The model doesn’t have the information it needs (it’s in your docs, your database, your Slack history, released after the model’s training cutoff)
- You need the model to cite sources or reference specific documents
- Your knowledge base changes faster than model updates (quarterly product docs, live pricing, customer-specific policies)
Real scenario: Support team needs an LLM to answer questions about your SaaS product. Your product updated three times since GPT-4o’s training data. The model hallucinates features that don’t exist and misses new ones.
Prompt engineering won’t help — the model literally doesn’t know. Fine-tuning is overkill for something that changes every month. RAG is the answer: embed your latest docs, retrieve relevant sections, inject them into the prompt.
Example RAG setup in Python:
from anthropic import Anthropic
import json
client = Anthropic()
# Your docs as a simple knowledge base
KNOWLEDGE_BASE = {
"pricing": "Standard: $99/mo. Pro: $299/mo. Enterprise: custom",
"onboarding": "New users get 30-day trial access to all features",
"api_limit": "10,000 API calls per month on Standard plan"
}
def retrieve_context(query):
"""Simple keyword matching. Use embedding search in production."""
relevant = []
for key, value in KNOWLEDGE_BASE.items():
if any(word in query.lower() for word in key.split()):
relevant.append(value)
return "\n".join(relevant) if relevant else "No relevant docs found"
def answer_with_rag(user_question):
context = retrieve_context(user_question)
message = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=500,
messages=[
{
"role": "user",
"content": f"Answer based on this info:\n{context}\n\nQuestion: {user_question}"
}
]
)
return message.content[0].text
# Test it
print(answer_with_rag("What does the Standard plan cost?"))
That’s RAG in 30 lines. In production, you’d use embedding-based retrieval (OpenAI embeddings, Cohere, or Sentence Transformers) and a vector store (Pinecone, Weaviate, Chroma). The principle stays the same: retrieve + inject + answer.
Cost: infrastructure for embeddings and retrieval, ongoing maintenance as docs change.
When Fine-Tuning Is Actually Worth It
Fine-tuning is the most expensive approach. Use it only when the first two fail.
Fine-tune when:
- You have 100+ training examples of the exact task (usually needed for real improvement)
- The model needs to internalize patterns or style, not just access information
- You’re running inference at scale and token costs matter more than training cost
Real example: You manage customer support tickets. You need the model to adopt your team’s specific tone, categorization scheme, and response structure. Prompt engineering handles the structure. RAG handles missing knowledge. But the model still sounds wrong — too formal, or it misses your specific categorization nuances.
Fine-tune on 200 real support conversations (tickets + ideal model responses). After fine-tuning on Llama 3 8B or Mistral 7B (local inference), the model internalizes your exact style and categorization patterns.
Cost: $5–50 for API fine-tuning (OpenAI, Anthropic). Hours of data prep. Days of iteration to see if it helped.
The risk: Fine-tuning can degrade general performance. Test on a validation set before shipping to production.
Decision Tree: What to Try First
Start at the top. Move down only if the previous step fails.
- Does the model already know the answer? Yes → Try prompt engineering. No → Move to 2.
- Is the information in your control (docs, database, API)? Yes → Build RAG. No → Move to 3.
- Do you have 100+ labeled examples of the exact task? Yes → Fine-tune. No → Stay with RAG + better prompting.
Most real systems don’t need fine-tuning. They need better prompts and better retrieval. Fine-tuning is a last resort, not a first instinct.
Your Next Move: Audit Your Current Setup
Pick one LLM task you’re currently unhappy with. Measure the current failure rate. Then run this sequence:
- Spend 2 hours iterating on the prompt (specify output format, constraints, examples). Measure the new failure rate.
- If it’s still above acceptable, grab 5 relevant documents from your knowledge base and test RAG injection. Measure again.
- Only if both fail, consider fine-tuning — and only if you have the training data.
This costs almost nothing and clarifies which approach actually solves your problem. Most teams skip step 1 entirely and jump to step 3. That’s expensive and usually wrong.