Every fine-tuning framework accepts a handful of conversation formats and converts them into one tokenised string before training. Understanding that conversion is the difference between a fine-tune that behaves and one that rambles.
Alpaca: single turn, three fields
The Alpaca format came out of Stanford's 2023 instruction-tuning work and is the simplest of the three. One JSON object per example, with instruction, an optional input, and output.
It suits single-turn tasks exactly and multi-turn conversation not at all. If your data is 'given this document, produce this summary' or 'classify this ticket', Alpaca is a clean fit and the lack of structure is an advantage. The input field exists so that the instruction can stay constant across many examples while the content varies — useful, and frequently ignored in favour of concatenating everything into instruction.
[
{
"instruction": "Summarise the clinical note in two sentences.",
"input": "Patient presented with a three-day history of ...",
"output": "A 54-year-old patient reported three days of ..."
},
{
"instruction": "List the three risk factors mentioned.",
"input": "...",
"output": "1. Hypertension\n2. Family history\n3. Smoking"
}
]
ChatML is a template, not a storage format
This is the distinction that clears up most of the confusion. Alpaca and ShareGPT describe how conversations sit in a file. ChatML describes how they are rendered into the single token sequence the model sees.
A chat template wraps each turn in special tokens that mark role boundaries. The widely used ChatML convention uses <|im_start|>role and <|im_end|>, but it is not universal: many model families have their own — Llama, Mistral and Gemma each differ — and using the wrong one is one of the most common causes of a fine-tune that echoes role markers as text or never stops talking.
You almost never want to write these tokens by hand. The tokenizer that ships with a model carries its own template, and applying it is one call. Let the tokenizer do it and the boundaries are correct by construction.
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("<model-id>")
msgs = [
{"role": "system", "content": "You are a careful assistant."},
{"role": "user", "content": "Summarise this note: ..."},
{"role": "assistant", "content": "A 54-year-old patient ..."},
]
# training: render the full conversation including the final answer
text = tok.apply_chat_template(msgs, tokenize=False)
# inference: stop after the assistant header so the model continues it
prompt = tok.apply_chat_template(
msgs[:-1], tokenize=False, add_generation_prompt=True)
print(repr(text[-120:])) # inspect the actual boundary tokens onceThe decision that actually matters: loss masking
Having rendered the conversation, you must decide which tokens contribute to the loss. Train on every token and the model learns to produce user turns as well as assistant turns — it will happily continue your conversation on both sides. Train only on assistant tokens and it learns to respond.
For most instruction tuning, masking everything except assistant responses is what you want, and it is what the response-only and assistant-only loss options in the major frameworks do — Unsloth's train_on_responses_only, for example. The exception is continued pretraining, where you genuinely do want loss on all tokens because you are teaching the model a domain rather than a behaviour.
In a multi-turn ShareGPT example this means masking every human turn and computing loss on every gpt turn — not just the last one. Getting that wrong wastes most of a multi-turn dataset's signal, and it fails silently: the loss curve looks fine.
Which to choose
If your data is single-turn and task-shaped, Alpaca is the least ceremony. If it has system prompts, multiple turns, or you expect it to grow into those, use a messages list — ShareGPT's from/value or the role/content variant, whichever your framework prefers. Store conversations in whichever one you pick, and let the tokenizer apply the model's own template at training time.
The one combination to avoid is baking rendered special tokens into your stored dataset. It welds your data to one model family, and the next time you fine-tune something else you will be stripping template tokens out with regular expressions.
Questions people ask
Can I convert Alpaca data to ShareGPT?
Yes, and it is lossless in that direction. Each example becomes a two-turn conversation: the instruction and input joined into a human turn, the output as the gpt turn. Going the other way loses anything beyond the first exchange, so multi-turn data cannot be flattened into Alpaca without discarding most of it.
Do I need a system prompt in my training data?
Only if you want the model to condition on one at inference. If every training example carries the same system prompt, the model partly folds it into its weights and behaves that way without it. If you want robustness to varied system prompts, vary them in training — including leaving them out of some examples.
What happens if I use the wrong chat template?
Typically the model trains without error and then behaves oddly: it may not stop generating, may echo role markers as literal text, or may ignore the system prompt. Because there is no error, this is usually diagnosed late. Rendering one example and reading it is the cheap preventative.
Is there a standard for tool and function calls?
Not a single one. Tool calls are generally stored as an extra turn with a structured payload, and each model family's template serialises them differently. If you are fine-tuning for tool use, follow the target model's documented format exactly rather than inventing a shape — this is the area where templates diverge most.