Konwersja dostrojonego modelu do GGUF dla Ollama

Autor: Jakub Rusinowski · Ostatnia aktualizacja: 12 lipca 2026

Aby uruchomić dostrojony model w Ollama albo llama.cpp, scalasz adapter LoRA z modelem bazowym, konwertujesz wynik do GGUF skryptem konwersji z llama.cpp, kwantyzujesz go i opakowujesz w plik Modelfil

W tym przewodniku

Aby uruchomić dostrojony model w Ollama albo llama.cpp, scalasz adapter LoRA z modelem bazowym, konwertujesz wynik do GGUF skryptem konwersji z llama.cpp, kwantyzujesz go i opakowujesz w plik Modelfile. Cały potok to cztery polecenia, a ten poradnik omawia każde z nich — łącznie z krokiem szablonu czatu, który za pierwszym razem wszyscy robią źle.

Ostatnia aktualizacja: lipiec 2026

Potok w skrócie

adapter LoRA + model bazowy → scalenie → folder HF → convert_hf_to_gguf.py
    → model-f16.gguf → llama-quantize → model-Q4_K_M.gguf → Modelfile → ollama create

Skończyłeś fine-tuning swojego pierwszego LLM-a i masz folder z wagami adaptera. Frameworki treningowe zapisują *adapter LoRA* — kilkaset megabajtów różnic wag, a nie gotowy do uruchomienia model. Ollama oczekuje pojedynczego pliku GGUF. Ten poradnik służy właśnie do przerzucenia mostu nad tą przepaścią.

Krok 0 — Wymagania wstępne

Na Macu z Apple Silicon zanim zaczniesz, upewnij się, że masz natywnego Pythona arm64 — interpreter x86 pod Rosettą to powód, dla którego MLX i część zależności konwersji odmawiają instalacji.

git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
pip install -r requirements.txt     # dla skryptów konwersji
cmake -B build && cmake --build build --config Release -t llama-quantize

Potrzebujesz zapasu miejsca na dysku: potok dla modelu 8B przez chwilę przechowuje scalony model FP16 (~16 GB), plik GGUF F16 (~16 GB) i kwant (~5 GB). Jeśli miejsca jest mało, usuwaj pliki pośrednie na bieżąco.

Krok 1 — Scal adapter LoRA z modelem bazowym

from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import torch

base = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B-Instruct",   # musi być DOKŁADNIE ta baza, na której trenowałeś
    torch_dtype=torch.float16, device_map="cpu")
model = PeftModel.from_pretrained(base, "./my-lora-adapter")
merged = model.merge_and_unload()          # wtapia różnice w wagi

merged.save_pretrained("./merged-model", safe_serialization=True)
AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B-Instruct").save_pretrained("./merged-model")

Dwie pułapki: nazwa modelu bazowego musi *dokładnie* odpowiadać temu, na czym prowadziłeś fine-tuning (adapter wytrenowany na wariancie Instruct i scalony z wariantem bazowym daje subtelnie zepsuty model), i nie zapomnij zapisać tokenizera — bez niego konwersja się nie powiedzie. device_map="cpu" pozwala uruchomić to na maszynach bez zapasu VRAM; scalanie potrzebuje RAM-u systemowego, nie GPU.

(Skrót: jeśli trenowałeś w Unsloth, model.save_pretrained_gguf(...) wykonuje kroki 1–3 jednym wywołaniem — ten poradnik opisuje standardową ścieżkę dla wszystkich pozostałych oraz dla sytuacji, gdy potrzebujesz kontroli nad każdym etapem).

Krok 2 — Konwersja HF → GGUF

python convert_hf_to_gguf.py ./merged-model \
  --outfile my-model-f16.gguf --outtype f16

Konwertuj do F16, a kwantyzuj w osobnym kroku — kwantyzowanie prosto z konwertera skazuje Cię na powtarzanie konwersji przy każdym poziomie kwantyzacji, który zechcesz sprawdzić.

Jeśli skrypt zgłosi błąd Model architecture not supported, Twój model bazowy jest nowszy niż Twoja kopia llama.cpp — wykonaj git pull i spróbuj ponownie; wsparcie dla nowych architektur trafia tam w ciągu kilku dni od ważnych premier.

Krok 3 — Kwantyzacja

./build/bin/llama-quantize my-model-f16.gguf my-model-Q4_K_M.gguf Q4_K_M

Q4_K_M to właściwy domyślny wybór (najlepsza jakość na gigabajt; ~4,9 GB dla modelu 8B). Sięgnij po Q5_K_M albo Q8_0, jeśli VRAM masz pod dostatkiem, a po Q3_K_M tylko pod prawdziwą presją — pełną tabelę decyzyjną znajdziesz w poradniku wyboru kwantyzacji. Warto przygotować dwa poziomy kwantyzacji i porównać je w teście A/B na *swoim* zadaniu: dostrojone zachowania (zwłaszcza sztywne formaty wyjścia) bywają bardziej wrażliwe na kwantyzację niż zwykła rozmowa.

Krok 4 — Modelfile (miejsce, gdzie umierają fine-tuningi)

FROM ./my-model-Q4_K_M.gguf

# Llama 3.1 chat template - MUST match what you trained with
TEMPLATE """<|start_header_id|>system<|end_header_id|>

{{ .System }}<|eot_id|><|start_header_id|>user<|end_header_id|>

{{ .Prompt }}<|eot_id|><|start_header_id|>assistant<|end_header_id|>

"""
PARAMETER stop <|eot_id|>
SYSTEM You are a helpful assistant.
ollama create my-finetune -f Modelfile
ollama run my-finetune "A test prompt from your training distribution"

Kluczowa jest linia TEMPLATE. Twój fine-tuning nauczył się oczekiwać dokładnie tego formatu promptu, na którym był trenowany (powyżej nagłówki Llama 3.1; modele z rodziny Qwen/ChatML używają zamiast tego znaczników <|im_start|> — skopiuj poprawny szablon z modelu z tej samej rodziny poleceniem ollama show llama3.1 --template). Niedopasowany szablon to przyczyna numer jeden tego, że świeżo skonwertowany model wypisuje bzdury, ignoruje swój trening albo nigdy nie przestaje generować — spektakularnie wyglądające awarie, a wszystko przez jeden zły ciąg znaków. Jeśli Twój pierwszy test wygląda na zepsuty, zobacz bełkot na wyjściu: zły szablon promptu.

Walidacja wyniku

Najczęściej zadawane pytania

Czy Ollama może użyć adaptera LoRA bezpośrednio, bez scalania?

llama.cpp obsługuje adaptery skonwertowane do GGUF w czasie działania (convert_lora_to_gguf.py + --lora), ale to ścieżka ze scalaniem jest tym, czego oczekuje Ollama i co powinieneś dystrybuować: jeden artefakt, brak rozjazdu wersji adaptera i bazy, nieznacznie szybsze wnioskowanie.

Czy muszę powtarzać ten potok po każdym ponownym treningu?

Kroki 1–4 tak — ale to czynności mechaniczne; napisz do nich skrypt raz. Plik Modelfile zmienia się tylko wtedy, gdy zmienia się szablon albo parametry, więc kolejne iteracje treningu sprowadzają się do: scal → konwertuj → kwantyzuj → ollama create.

Dlaczego mój skonwertowany model działa gorzej niż podczas ewaluacji treningowej?

W kolejności prawdopodobieństwa: zły szablon czatu w pliku Modelfile (naprawiane w kilka minut), scalenie z innym wariantem bazy niż ten, na którym trenowałeś, albo kwantyzacja przy zadaniu wrażliwym na kwantyzację — przetestuj plik GGUF w F16, żeby ustalić, która z tych przyczyn zadziałała.

Ile miejsca na dysku potrzebuje konwersja modelu 8B?

W szczycie ~37 GB: scalony FP16 (~16 GB) + GGUF F16 (~16 GB) + kwant Q4 (~5 GB). Po walidacji usuń pliki pośrednie, a zostanie Ci tylko kwant o wielkości ~5 GB. Potok dla modelu 70B osiąga szczyt w okolicach 300 GB — zaplanuj to albo przeprowadź konwersję na wynajętej maszynie (poradnik o GPU w chmurze).

Powiązane poradniki

← Wszystkie przewodniki | Sprawdź zgodność GPU