DEV Community

Emily Thomas
Emily Thomas

Posted on

I Fine-Tuned a Small Language Model for Production — Here's the Full MLOps Pipeline

Big LLMs are impressive, but they're overkill (and expensive) for most real products. In 2026, more teams are shipping fine-tuned Small Language Models (SLMs) that run cheaper, faster, and fit exactly one job well. This article walks through the actual production pipeline — fine-tuning, evaluation, versioning, and deployment — not just a Colab notebook that dies after one run.


Overview: Why SLMs Instead of Giant LLMs

  • Lower cost — fraction of the inference cost of a large model
  • Faster inference — smaller models mean lower latency, easier to self-host
  • Focused performance — a 3B model fine-tuned on your exact task often beats a general-purpose 70B model for that specific task

The trade-off: fine-tuning and MLOps discipline matter a lot more, since you're not leaning on a giant pretrained model's general knowledge.

Before setting up your own pipeline, it's worth comparing what other teams are actually using in production. A software hub is a good place to check current MLOps platforms, fine-tuning frameworks, and hosting options before you commit to a stack.

Step 1: Prepare the Dataset

Fine-tuning quality depends almost entirely on data quality. Format matters — most SLM fine-tuning uses instruction-style JSONL.

{"instruction": "Summarize this support ticket", "input": "Customer says app crashes on login after update.", "output": "Login crash reported after recent app update."}
Enter fullscreen mode Exit fullscreen mode
import json

def load_dataset(path):
    data = []
    with open(path, "r") as f:
        for line in f:
            data.append(json.loads(line))
    return data

dataset = load_dataset("train.jsonl")
print(f"Loaded {len(dataset)} examples")
Enter fullscreen mode Exit fullscreen mode

Step 2: Fine-Tune With LoRA (Efficient, Not Full Fine-Tuning)

Full fine-tuning is expensive and often unnecessary. LoRA (Low-Rank Adaptation) trains a small set of extra parameters instead of the whole model — much cheaper, still effective.

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model

model_name = "microsoft/Phi-3-mini-4k-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
Enter fullscreen mode Exit fullscreen mode
training_args = TrainingArguments(
    output_dir="./slm-finetuned",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    num_train_epochs=3,
    learning_rate=2e-4,
    fp16=True,
    logging_steps=10,
    save_strategy="epoch"
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset
)

trainer.train()
Enter fullscreen mode Exit fullscreen mode

Step 3: Evaluate Before Shipping Anything

Never deploy a fine-tuned model based on vibes. Run it against a held-out test set and track real metrics.

from sklearn.metrics import accuracy_score

def evaluate(model, test_data):
    correct = 0
    for example in test_data:
        prediction = generate(model, example["input"])
        if prediction.strip() == example["output"].strip():
            correct += 1
    return correct / len(test_data)

accuracy = evaluate(model, test_dataset)
print(f"Eval accuracy: {accuracy:.2%}")
Enter fullscreen mode Exit fullscreen mode

For generative tasks, pair exact-match with something like ROUGE or an LLM-as-judge scoring pass — exact match alone is too strict for open-ended text.

Step 4: Version Everything (Model + Data + Config)

This is the part most tutorials skip and most production incidents trace back to. Every fine-tuned model needs to be traceable to the exact data and config that produced it.

import mlflow

with mlflow.start_run():
    mlflow.log_param("base_model", model_name)
    mlflow.log_param("lora_r", 16)
    mlflow.log_param("epochs", 3)
    mlflow.log_metric("eval_accuracy", accuracy)
    mlflow.pytorch.log_model(model, "slm-finetuned-v1")
Enter fullscreen mode Exit fullscreen mode

If a model regresses in production, you need to know exactly which dataset version and hyperparameters produced it — no exceptions.

Step 5: Deploy for Inference

Serve the fine-tuned model behind a lightweight API instead of loading it fresh on every request.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Query(BaseModel):
    prompt: str

@app.post("/generate")
def generate_text(query: Query):
    inputs = tokenizer(query.prompt, return_tensors="pt")
    outputs = model.generate(**inputs, max_new_tokens=200)
    return {"response": tokenizer.decode(outputs[0], skip_special_tokens=True)}
Enter fullscreen mode Exit fullscreen mode

Run it behind a proper inference server (vLLM or TGI) in production for batching and lower latency — raw generate() calls don't scale well under real traffic.

Keeping Costs Down Without Cutting Corners

Not every piece of your MLOps stack needs a paid license. Experiment tracking, dataset versioning, and even model registries all have solid free options. Check an alternative of free softwares list before paying for enterprise MLOps tooling you might not need yet — many free/open-source tools cover 90% of what small teams actually use.

Common Mistakes to Avoid

  • Skipping data cleaning — garbage instructions in, garbage outputs out.
  • No evaluation baseline — you can't tell if fine-tuning helped without a "before" score.
  • Ignoring catastrophic forgetting — fine-tuning too aggressively can wreck general capability. Keep LoRA rank and epochs conservative.
  • No rollback plan — always keep the previous model version deployable if the new one underperforms.

Final Thoughts

Fine-tuning an SLM isn't the hard part anymore — frameworks like LoRA and PEFT make that almost routine. The real skill is the MLOps discipline around it: clean data, honest evaluation, full versioning, and a deployment setup that doesn't fall over under load.

Frameworks and base models update constantly, so before your next fine-tuning run, check the updates software version website to make sure you're building on the latest stable model and library versions.

Top comments (0)