DEV Community

Cover image for Don't Fine-Tune. Unless You Can Answer These Three Questions.
Chidozie Uzoegwu for AWS Community Builders

Posted on Originally published at builder.aws.com

Don't Fine-Tune. Unless You Can Answer These Three Questions.

Twice now I have gone looking for a retrain and found the problem somewhere else.

The first time, a third of my output had collapsed into one template. Before spending anything I counted the pattern in my training data. 5 occurrences in 1,610 examples. Then I counted it in the output. 36%. The cause was a single example I had hardcoded into my own prompt months earlier, and the model was copying it.

The second time, quality had gone flat across the board. The system prompt had grown to 224,833 characters, roughly 56,000 tokens on every call, and ninety percent of it was accumulated rules about how the output should sound. The model was doing exactly what I had asked it to do, which was avoid things.

Neither needed new weights.

That is the pattern I would put in front of anyone about to fine-tune. It is the most expensive way to discover you had a prompt bug. About $30 and a five-hour job per run on a 70B model, and the compute is the small part. The real cost is that you now have two variables moving and no clean way to tell which one broke.

So, three questions.

1. Is this a knowledge problem or an identity problem?

Fine-tuning does not teach a model facts. It shifts a distribution.

If the model needs to know things it currently does not, your product details, your documentation, anything that was true last week and false today, that is retrieval. Training knowledge into weights means retraining every time the knowledge changes, which is a subscription you did not mean to sign.

Fine-tuning is for behaviour that stays put. How it writes. What register it falls back to. What it does when the input is ambiguous.

The test I use: if the right answer changes when the underlying data changes, it belongs in retrieval.

2. Have you stripped the prompt back first?

Most requests to fine-tune are prompt bloat wearing a disguise.

Prompts accrete. Something goes wrong, you add a rule, it improves, and nothing ever gets removed, because removing a rule feels like inviting the bug back. Six months later two hundred lines of prohibitions are competing with two lines describing the actual job, and the model attends across all of it.

Before you price a training run, cut the prompt to the smallest thing that states the task, and measure again. If the output improves, you never had a weights problem.

This is uncomfortable, because it means deleting work you were proud of. Do it anyway. You cannot diagnose a system you have only ever added to.

3. Can you actually produce the data?

This is the question that stops people, and it is where most of the effort goes.

Everyone has data. Almost nobody has a thousand or more curated examples of the exact behaviour they want, cleaned, and is prepared to keep cleaning them.

My last build started from 1,418 labelled examples and kept 884 after cleaning. The final training set reached 1,610 rows once other curated sources were added. Here is what got dropped from that base pool, and none of it was optional.

Rhetorical tics I did not want the model to learn: 107 examples dropped for one construction alone, plus smaller counts for two others. If a pattern sits in your training data at any volume, you are teaching it.

Length and register discipline: 302 dropped for being the wrong length for their category. A model trained on mixed lengths produces mixed lengths.

Opener variety: 45 dropped because more than two examples shared the same opening three words. Without that cap the model finds one opening it likes and reuses it everywhere.

Then there was the part I did not plan for.

83 examples were being deleted on every build

The build had a decontamination step. It removed hand-approved examples from one source file, on the assumption they had already been copied into a curated file elsewhere.

Nothing had ever copied them.

83 examples were dropped silently at build time, on every run, for months. They were disproportionately the best ones, the examples carrying concrete specifics rather than general statements, because those were exactly the ones I had approved by hand in the first place.

A row that never arrives leaves no trace. Nothing in a training run tells you what it did not receive.

So there was no error. The row counts looked plausible. The model trained, the evaluation ran, and the result was slightly worse than it should have been in a way no single test could isolate.

I found it by reading the builder line by line.

That is not really a lesson about checking your pipeline. A training pipeline fails quietly by design. Code that drops rows produces a smaller number, and a smaller number still looks like a number. So print what you dropped and why, broken down by reason, on every single build, and then read it.

The bar

Answer all three and fine-tuning is a reasonable thing to do, and it works. Voice in particular is something you can instruct a model toward but cannot make native to it, and that gap is real.

You will also need an evaluation set that can fail, held out and genuinely separate from anything you trained on, and a rollback path that restores the previous model together with its system prompt. Those are their own articles, and they are the difference between shipping a fine-tune and gambling on one.

But answer the three questions first. Two of them cost nothing except honesty.

Top comments (2)

Collapse
 
max_quimby profile image
Max Quimby

"The most expensive way to discover you had a prompt bug" is going straight into my notes. The two war stories land because they're the common case, not the exotic one — a hardcoded example poisoning a third of your outputs, and a 56K-token system prompt of accumulated "avoid this" rules. Both look like model deficiencies right up until you count.

The knowledge-vs-identity test is the cleanest phrasing of it I've seen: if the right answer changes when the underlying data changes, it's retrieval, not weights. Teams conflate these constantly because both feel like "the model doesn't know our stuff."

The one I'd add as a fourth question: can you evaluate the fine-tune once you have it? The failure I see after a retrain is that people now have two moving variables (weights + prompt) and no frozen baseline to attribute regressions to — so they can't tell whether the new weights helped or the prompt change they made alongside it did. Fine-tuning without a locked eval set just moves the mystery, it doesn't remove it. And your 83-silently-discarded-training-examples bug is the perfect argument for why the data pipeline is the real project, not the training run.

Collapse
 
chidozie profile image
Chidozie Uzoegwu AWS Community Builders

That fourth question is the right one, and I did not have it solved at the time.

Two things I would add, both from getting them wrong.

The first is your two-variables point, one level down. Weights and system prompt are not independent variables. A fine-tune is trained against a specific prompt, so swapping one without the other degrades the output with no error anywhere and nothing in the logs to attribute it to. I now treat them as a pair in config, and rollback swaps both together. Before that I spent two days debugging a model that was fine.

The second is that a locked eval set is necessary but not sufficient. If your training data and your held-out battery draw on the same source material, a pass is memorisation rather than capability, and it looks exactly like success. I once found 19 of 25 battery items overlapping my training sources. The model was scoring well and the score meant nothing. Disjoint sources is the property that matters, not just held out.

Agreed on the data pipeline being the real project. The training run is the cheap part, and it is the part everyone photographs.