C.W.K.
Stream
Lesson 06 of 06 · published

End-to-End Walkthrough — Fine-Tune, Merge, Serve

~20 min · walkthrough, end-to-end, deployment

Level 0Curious
0 XP0/51 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

The whole pipeline in one place

Five lessons of pieces; one lesson putting them together. We're going to fine-tune a 7B instruct base on a tiny domain dataset, merge the adapter into a deployable model, serve it through mlx-lm's HTTP server, and call it from openai-python. End to end on a single 32 GB Mac, no GPU rental required.

The full sequence

  1. Pick a base. mlx-community/Mistral-7B-Instruct-v0.3-4bit — 7B Q4, fits in ~5 GB of unified memory, decent instruction following baseline.
  2. Prepare data. Build a small train.jsonl + valid.jsonl in the chat format (lesson 2). 100–300 examples is plenty for the demo.
  3. Train. Run mlx_lm lora --train with sane defaults from lesson 3. Watch val loss; stop when it plateaus.
  4. Merge. Run mlx_lm fuse to fold the adapter into the base, producing a new model directory.
  5. Serve. Start mlx_lm server --model ./my-fused in one terminal.
  6. Use. Hit the server from openai-python in another terminal — the fine-tuned model now answers in your domain's voice.

What this exercise should leave you with

Three things. First, a working artifact you can refer back to — a file layout, a YAML config, a training command, a fuse command, a server command. Second, the muscle memory that this whole pipeline is one person on one Mac in an afternoon, not a team-and-cloud project. Third, a baseline you can iterate on — your next fine-tune is a variation of this walkthrough, not a rebuild from scratch.

The artifacts the walkthrough produces

  • ./my-data/{train,valid}.jsonl — your curated dataset.
  • ./my-lora.yaml — the training config (one source of truth).
  • ./my-adapter/ — the trained LoRA adapter (small file, the actual learned correction).
  • ./my-fused/ — the merged deployable model directory.
  • An HTTP endpoint at http://localhost:8080/v1 serving your fine-tune to anything OpenAI-compatible.

Where to go from here

Push the fused model to your own mlx-community-style HF repo with --upload-repo if you want others to pull it. Or keep iterating — train a second adapter on a different slice of your domain and compare them at inference. Or jump to prod.lesson1 to wrap your fine-tune in a real FastAPI service with worker management, when the built-in server hits its limits.

Code

Step 1-2 — Pick the base, prepare a tiny dataset·bash
mkdir -p my-data
# Hand-write at least 50 chat-format examples in train.jsonl
# and ~10 in valid.jsonl (lesson 2 has the format).
# You can also use a public dataset like mlx-community/wikisql for the demo.
Step 3 — Train the LoRA adapter·bash
# my-lora.yaml from lesson 3 contains all the flags as one source of truth.
python -m mlx_lm lora -c my-lora.yaml

# Or inline:
python -m mlx_lm lora \
  --model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
  --train --data ./my-data \
  --fine-tune-type lora --num-layers 16 \
  --batch-size 4 --iters 200 --learning-rate 5e-5 \
  --max-seq-length 2048 \
  --steps-per-eval 25 --save-every 100 \
  --adapter-path ./my-adapter
Step 4 — Fuse the adapter; Step 5 — Serve·bash
# Fuse
python -m mlx_lm fuse \
  --model mlx-community/Mistral-7B-Instruct-v0.3-4bit \
  --adapter-path ./my-adapter \
  --save-path ./my-fused

# Serve (in one terminal — keeps running)
python -m mlx_lm server --model ./my-fused
Step 6 — Hit the fine-tune from a client·python
# In a separate terminal:
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="x")

resp = client.chat.completions.create(
    model="./my-fused",
    messages=[
        {"role": "system", "content": "You are an expert in <your domain>."},
        {"role": "user",   "content": "<a question your fine-tune should answer well>"},
    ],
    max_tokens=120,
    temperature=0.7,
)
print(resp.choices[0].message.content)

External links

Exercise

Run the entire walkthrough end-to-end on a domain you care about. Spend 70% of your time on the data (lesson 2), 20% running the training and watching loss, 10% on the fuse + serve + test loop. Save the YAML config so you can re-run the whole thing with one command later. The exercise is to feel that the pipeline is repeatable — your second domain fine-tune should take half the time of the first.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.