
Wrong Format, Wasted GPU Hours: How Chat Templates Determine What Your Fine-Tuned Model Actually Learns
Chris Harper
3 min read
Jul 10, 2026 · 20:03 UTC
TL;DR: The dataset format you choose — Alpaca, ShareGPT, or ChatML — determines which special tokens the tokenizer injects around each conversation turn; use the wrong one and you train on structured noise, not signal.
What you'll be able to do after this:
- Understand which of the three dominant fine-tuning formats to use and why format affects what the model actually learns
- Convert a ShareGPT dataset to ChatML in two lines with Unsloth's
standardize_sharegpt - Verify your formatted examples before burning a single GPU minute
Every fine-tuning tutorial says "format your dataset correctly" without explaining why it matters. Here's why: the tokenizer wraps each conversation turn in special tokens that signal role boundaries. Pick the wrong format and the model sees those boundaries scrambled — it trains on noise rather than the instruction-response pattern you intended.
The three formats
Alpaca — single-turn, simple
{
"instruction": "Summarize this article in one sentence.",
"input": "<article text>",
"output": "The article describes..."
}
Best for: classification, extraction, single-shot Q&A. Many older community datasets use this. Base (non-instruct) models prefer this format.
ShareGPT — multi-turn, community standard
{
"conversations": [
{"from": "human", "value": "What is LoRA?"},
{"from": "gpt", "value": "LoRA stands for Low-Rank Adaptation..."}
]
}
Best for: multi-turn chat datasets from HuggingFace Hub. Crucial difference: keys are from/value, not role/content. Many HuggingFace conversation datasets ship in this format.
ChatML — modern, recommended for new datasets
[
{"role": "system", "content": "You are a coding assistant."},
{"role": "user", "content": "What is LoRA?"},
{"role": "assistant", "content": "LoRA stands for..."}
]
Best for: new datasets targeting OpenAI-compatible or modern open models. Uses <|im_start|> / <|im_end|> special tokens. The role/content keys map directly to the OpenAI messages format.
Applying a template in Unsloth
from unsloth import FastLanguageModel
from unsloth.chat_templates import get_chat_template, standardize_sharegpt
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/llama-3-8b-instruct",
max_seq_length=2048,
load_in_4bit=True,
)
# Step 1: if your dataset is ShareGPT format, normalize it to role/content
dataset = standardize_sharegpt(dataset) # converts from/value → role/content
# Step 2: apply ChatML template — patches the tokenizer with correct special tokens
tokenizer = get_chat_template(tokenizer, chat_template="chatml")
# Step 3: format each sample into a single string with special tokens applied
def format_prompts(examples):
texts = tokenizer.apply_chat_template(
examples["conversations"],
tokenize=False,
)
return {"text": texts}
dataset = dataset.map(format_prompts, batched=True)
# Step 4: ALWAYS inspect before training
print(dataset[0]["text"])
Expected output for ChatML:
<|im_start|>system
You are a coding assistant.<|im_end|>
<|im_start|>user
What is LoRA?<|im_end|>
<|im_start|>assistant
LoRA stands for Low-Rank Adaptation...<|im_end|>
What to check before starting a training run
Print two or three formatted samples and verify:
- Special tokens appear at every role boundary (
<|im_start|>/<|im_end|>for ChatML;### Human:/### Assistant:for Alpaca) - The assistant's turn ends with the model's EOS token — not mid-sentence, not missing
- System prompt (if any) is the first turn and is correctly labeled
If you see raw JSON or missing role markers, you applied the wrong template or forgot standardize_sharegpt. Fix this before training — not after eight GPU hours.
Sources: Chat Templates — Unsloth Docs · Datasets Guide — Unsloth Docs · Fine-Tune Llama 3.1 with Unsloth — Towards Data Science