TL;DR — I built a customer-support assistant three ways, holding the base model constant, and measured each. Naive retrieval-augmented generation (RAG) actually scored below the ungrounded baseline on answer quality. A tiny fine-tuned intent router — 0.14% of the model’s parameters, trained on a free Colab T4 — fixed it and topped every quality metric. The lesson: retrieval and fine-tuning fix different problems, and “just add RAG” is not a strategy.


At a glance

MetricBaselineNaive RAGHybrid RAG
ROUGE-10.1370.122 ↓0.148
BLEU0.00440.00640.0149 (3.4×)
Hallucination36%26%26%
Router format adherence100%

Same base model (Qwen2.5-1.5B-Instruct) across all three systems — only the architecture around it changed.


The problem nobody demos

Customer-support LLMs fail in three expensive ways:

  1. Hallucination — inventing policies that don’t exist (a refund window, a shipping carrier, a fee).
  2. Intent misread — confidently answering the wrong question.
  3. Policy drift — replies that quietly ignore the company’s actual standard operating procedures (SOPs).

The usual fix you hear is “ground it with RAG.” Retrieve the relevant policy document, stuff it into the prompt, and the model will stop making things up. It sounds airtight. So I decided to actually measure it — not with vibes, but with a controlled experiment.

The experiment: change one thing at a time

The trap in most “RAG vs. fine-tuning” debates is that people change the model, the data, and the pipeline all at once, then attribute the result to whatever they were rooting for. To isolate cause and effect, I held the generation model constantQwen2.5-1.5B-Instruct — across all three systems and changed only the architecture around it:

SystemWhat it is
A — BaselineRaw LLM. No company policies. Answers from parametric memory alone.
B — Naive RAGSemantic retrieval over corporate SOPs → context → same LLM.
C — Hybrid RAGA fine-tuned intent router classifies the query first, then retrieval targets the right policy, then the same LLM answers.

Everything else was locked for fairness and reproducibility:

  • Deterministic decoding (do_sample=False) so results are repeatable.
  • Leakage-free splits — stratified 80/10/10 with programmatic set-intersection checks between train/validation/test.
  • A six-metric scorecard: Format Adherence, Intent Accuracy, ROUGE-1/L, BLEU, Consistency, and Hallucination Frequency.
  • The knowledge base was a set of real corporate policy documents (refunds, returns, billing, shipping, account recovery), chunked by Markdown header.

The surprise: retrieval made it worse

Here’s the result I did not expect.

Naive RAG scored below the ungrounded baseline on answer quality — ROUGE-1 of 0.122 vs. 0.137. Adding retrieval hurt.

When I dug into the transcripts, the cause was clear and a little embarrassing for the “just add RAG” crowd. The retriever kept pulling the right document but the wrong section. Ask “when do I get my refund?” and it would surface the agent-workflow steps rather than the refund-timing rule. The model, dutifully grounded in that passage, would answer:

Answer it produced
Naive RAG“Please share your order ID.”
What the SOP actually says“Refunds are processed in 3–7 business days.”

The correct rule was sitting one section away in the same file.

Retrieval alone had made the bot safe and useless. It stopped hallucinating numbers, but it also stopped answering the question. Grounding is only as good as what you ground on.

The fix: a tiny fine-tuned intent router

The failure wasn’t retrieval itself — it was unguided retrieval. So instead of letting a raw, messy query drive the vector search, I put a small classifier in front of it whose only job is to decide what the user actually wants and emit a strict JSON intent that the retriever can target.

I trained that router with QLoRA.

What LoRA / QLoRA actually is

LoRA (Low-Rank Adaptation) is a parameter-efficient fine-tuning technique. Instead of updating all of a model’s billions of weights, you freeze them and inject small trainable “adapter” matrices into a few layers. A weight update ΔW is approximated by the product of two much smaller matrices:

W′ = W + ΔW = W + B·A

where W is frozen and A, B have a small rank r (I used r = 16). You end up training a tiny fraction of the parameters. QLoRA adds 4-bit quantization of the frozen base model, so the whole thing fits on a modest GPU.

In this project the numbers were striking:

  • 2.18M of 1.55B parameters trained — just 0.14%.
  • Adapters applied only to the attention projections (q_proj, v_proj).
  • 4-bit NF4 base, r=16, alpha=32, on a free Colab T4.
  • Training converged cleanly (train loss 2.29 → 0.41; no overfitting).

QLoRA intent-router training curves — loss falling from 2.29 to 0.41 with no overfitting.

Because the base weights stay frozen, the model keeps its general language ability and only specializes at the one thing I need: query → intent JSON.

How Hybrid RAG works

The pipeline is “route first, then retrieve”:

Raw query  →  Intent router (QLoRA → JSON)  →  Targeted retrieval  →  Grounded answer
"when's my       {"intent":                     right SOP + right       generated by the
 money back?"     "get_refund"}                  section                 same base LLM

The router removes the guesswork before retrieval, so the vector search lands on the correct passage instead of the plausible-but-wrong one that sank Naive RAG.

Hybrid RAG architecture: raw query flows through a QLoRA intent router to targeted retrieval and a grounded answer from the base LLM.

The results

Evaluated on a held-out set of 50 stratified queries:

SystemROUGE-1ROUGE-LBLEUHallucination
Baseline0.1370.0880.004436%
Naive RAG0.1220.0850.006426%
Hybrid RAG0.1480.1090.014926%

Plus, the router itself hit 100% valid JSON (format adherence) and 88% intent accuracy. On the flagship refund category, Hybrid RAG’s ROUGE-1 climbed to 0.222.

Comparative results across all three systems on ROUGE-1, ROUGE-L, BLEU, and hallucination frequency.

Read across the row for Hybrid RAG and it wins on every generation quality metric — BLEU is 3.4× the baseline and 2.3× Naive RAG.

The one insight worth keeping

Decompose the numbers and a clean story falls out:

  • Retrieval reduced hallucination — 36% → 26%. Grounding is what stops the model inventing facts.
  • Fine-tuning drove quality — the router is what lifted ROUGE, BLEU, and actual helpfulness, by making sure retrieval grounded on the right thing.

They fix different problems. Retrieval is about not being wrong. Fine-tuning (here, routing) is about knowing what to be right about. Naive RAG gave you the first without the second — which is exactly why it went safe and evasive. You usually need both.

Being honest about limits

This is a deliberately scoped study, and it would be dishonest to oversell it:

  • Small held-out set (50 queries) and a single support domain.
  • Reference-based metrics (ROUGE/BLEU) are proxies, not ground truth for “helpfulness.”
  • Hallucination is measured as unsupported numbers relative to retrieved context — a useful proxy, not a full factuality audit.
  • A 1.5B model on a T4 is a constraint, not a recommendation for production scale.

None of that changes the direction of the finding, which is the point of a controlled comparison: the only variable that moved was the architecture.

Takeaways for anyone building LLM support

  1. Measure before you believe. RAG can regress quality if retrieval targets the wrong passage. Ship an eval harness before you ship the bot.
  2. Route, then retrieve. A cheap intent classifier in front of your vector store can matter more than a bigger model behind it.
  3. PEFT is genuinely accessible. Fine-tuning 0.14% of a model on a free GPU is well within reach — you don’t need a cluster to get a useful specialist.
  4. “Just add RAG” is not a strategy. Retrieval and fine-tuning are complementary, not interchangeable.

References & tooling

Methods:

Tooling:


Built end-to-end on Google Colab (T4) with Qwen2.5-1.5B-Instruct, all-MiniLM-L6-v2 embeddings, ChromaDB, and QLoRA — as part of the IIITB GenAI capstone on controlled customer-support generation.