Справочник

Дообучение под домен

Обучите LoRA-адаптер на своих документах, чтобы модель говорила словарём и рассуждала в стиле вашей узкой области.

RAG даёт Cradle факты (прайсы, спецификации, пункты договоров). Дообучение даёт стиль и паттерны рассуждений узкой области — юриспруденция, медицина, строительство, бухгалтерия и т.д. Две функции работают вместе.

Python нужен только для шагов LoRA. Основной рантайм Cradle остаётся без Python.

Что можно доучить на MacBook Pro M3 Pro 18 GB

БазаLoRA-trainInferenceВремя обучения (500 примеров, 3 эпохи)
Qwen2.5-1.5B-Instructкомфортнонорм~15 мин
Qwen2.5-3B-Instructкомфортно (~8 GB RAM)норм~40 мин
Qwen2.5-7B-Instructborderline (rank ≤ 8, grad checkpoint)норм~2 ч

С 36 GB RAM и больше можно использовать Qwen2.5-7B с rank 16.

Шаг 1 — собрать датасет

Соберите исходники в одну папку:

~/corpus/legal/
├── snippets/
│   ├── contract-terms.md
│   └── court-practice.pdf
├── gost/
│   └── civil-code-sections.pdf
└── examples/
    └── faq-operator.md

Запустите сборщик датасета:

pnpm build-dataset \
  --files ~/corpus/legal \
  --out "~/Library/Application Support/cradle/finetune-datasets/legal-v1" \
  --mode qa \
  --model "~/Library/Application Support/cradle/models/qwen3-8b-q4.gguf" \
  --qa-per-chunk 2 \
  --language ru
  • --mode qa — синтезирует Q&A-пары из каждого chunk'а локальной моделью. Медленно, но даёт instruction-tuning dataset.
  • --mode raw — быстро, отдаёт { "text": "<chunk>" } для continued pretraining.
  • --model — путь к скачанному chat-GGUF, используется для Q&A-синтеза. Рекомендуется Qwen3 8B.

Результат:

legal-v1/
├── train.jsonl
├── valid.jsonl
└── meta.json

Проверьте 5–10 пар вручную: вопросы должны звучать естественно, ответы не содержать выдуманных цифр. Если синтезатор галлюцинирует — попробуйте модель побольше или --mode raw.

Шаг 2 — установка MLX

Python нужен один раз на training-машине. Используйте uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

uv venv cradle-finetune --python 3.11
source cradle-finetune/bin/activate
uv pip install -r /path/to/cradle/tools/finetune/requirements.txt

python -c "import mlx_lm; print(mlx_lm.__version__)"
# ожидайте ≥ 0.31.0

Шаг 3 — обучение LoRA

Скопируйте пример конфига и отредактируйте пути:

cp tools/finetune/lora_config.example.yaml ~/lora-legal.yaml
# отредактируйте: data, adapter_path, base model

Запустите обучение:

python -m mlx_lm.lora --config ~/lora-legal.yaml

В логе вы увидите:

Loading pretrained model
Loading training data
Training
Iter 1:   Val loss 2.134, Val took 4.2s
Iter 10:  Train loss 1.987, It/sec 0.85, Tokens/sec 420
...
Iter 750: Train loss 1.234, Val loss 1.456
Saved final adapter weights to adapters-raw/legal-v1/adapters.safetensors

На что смотреть:

  • Val loss должен падать. Если застрял или растёт — перетренировка, сократите iters.
  • It/sec 0.5–2 на M3 Pro — норма. Если меньше 0.2 — RAM забита, уменьшите batch_size или включите grad_checkpoint.
  • OOM на середине — уменьшите num_layers с 16 до 8, rank с 16 до 8.

Шаг 4 — экспорт в GGUF

Нужен clone llama.cpp для convert_hf_to_gguf.py и llama-quantize:

git clone https://github.com/ggml-org/llama.cpp ~/repos/llama.cpp
cd ~/repos/llama.cpp
cmake -B build && cmake --build build --config Release -j

Дальше один скрипт сливает LoRA в базу и квантует:

cd /path/to/cradle
BASE_MODEL=Qwen/Qwen2.5-3B-Instruct \
ADAPTER_PATH="~/Library/Application Support/cradle/adapters-raw/legal-v1" \
OUT_DIR=/tmp/legal-v1-gguf \
LLAMA_CPP=~/repos/llama.cpp \
QUANT=Q4_K_M \
./tools/finetune/export_gguf.sh

Результат: /tmp/legal-v1-gguf/model-Q4_K_M.gguf (~1.9 GB для 3B базы).

Шаг 5 — импорт в Cradle

Вариант А (простой) — как новую модель

  1. Переместите GGUF в ~/Library/Application Support/cradle/models/legal-v1.gguf.
  2. В Cradle: Models → Add Custom URL.
  3. URL: file:///Users/aki/Library/Application%20Support/cradle/models/legal-v1.gguf
  4. Role: general, Context: 16384 (или как у базовой модели).
  5. Сохраните → модель появится в списке установленных.

Теперь в Agents → Edit у нужного агента выберите эту модель вместо базовой.

Вариант Б (экспериментальный) — runtime LoRA-адаптер

Если у вас отдельный GGUF-адаптер:

  1. В Cradle перейдите в Adapters.
  2. Import adapter → выберите GGUF.
  3. Укажите базовую модель по catalogId.
  4. Scale: 1.0.

В Agents → Edit → "Domain adapter" выберите новый адаптер. База остаётся прежней.

⚠️ Проверено ограниченно: node-llama-cpp v3.4 поддерживает LoRA-адаптеры через createContext({ lora: ... }), но формат адаптера должен быть совместим с llama.cpp. MLX-LM напрямую GGUF-адаптеры не выгружает — используйте Вариант А, пока не понадобится независимо надевать несколько адаптеров.

Troubleshooting

  • OOM на iter 1 — база слишком большая. Для 18 GB max: 3B с rank=16 или 7B с rank=8 + grad_checkpoint.
  • Val loss не падает — мало данных (less than 100 примеров) или неверный формат. Откройте train.jsonl, убедитесь, что каждая строка — валидный JSON с полем messages.
  • GGUF после fuse выходит 16 GB — забыли квантовать. Проверьте, что llama-quantize прошёл без ошибок и OUT_DIR содержит model-Q4_K_M.gguf, а не только model-f16.gguf.
  • Агент с адаптером всё равно отвечает как базовая модель — scale слишком мал, попробуйте scale=1.5. Или адаптер доучился слабо: увеличьте iters.

Что дальше

  • После обкатки RAG и Finetune должны работать вместе: адаптер формирует "язык", RAG подсовывает актуальные факты.