Архитектура

Модели

Как Cradle управляет локальными GGUF-моделями — каталог, скачивание, совместимость с железом, жизненный цикл runner и бюджет памяти.

Cradle запускает модели локально через node-llama-cpp (llama.cpp). После скачивания модели inference происходит целиком на хосте — никакого облачного endpoint, никакого Python-рантайма в основном процессе.

Роли моделей

Каждая запись каталога имеет role, который определяет, как runner используется:

РольИспользуется
classifierКлассификатор рисков уровня 2 (структурированный JSON-выход)
generalАгенты с ролью general, business, marketing, seo, other
codingАгенты с ролью coding
embeddingRAG ingest и retrieval

Runner-провайдер выбирает модель автоматически:

  • acquireClassifier — сначала classifier, затем самая маленькая не-embedding модель, если классификатор не настроен.
  • acquireForAgent(id) — конкретный modelId, сохранённый в агенте.
  • acquireEmbedder — только embedding-модели.

Встроенный каталог

Cradle поставляется с assets/models-catalog.json, покрывающим chat, coding и embedding. Несколько характерных записей:

IDРольРазмерПример RAMКонтекст
qwen3-0.6b-q4classifier430 MB2 GB4K
qwen3-1.7b-q4general1.1 GB3 GB8K
qwen3-8b-q4general4.9 GB10 GB16K
qwen3-14b-q4general8.4 GB16 GB16K
qwen3-coder-7b-q4coding4.7 GB10 GB16K
qwen3-embedding-0.6b-q8embedding680 MB2 GB8K
bge-m3-q4embedding580 MB2 GB8K

Источники следуют HuggingFace GGUF-конвенциям (unsloth/…-GGUF, bartowski/…-GGUF, Qwen/…-GGUF, CompendiumLabs/bge-m3-gguf).

Совместимость с железом

Перед скачиванием Cradle проверяет, поместится ли модель на хост. Вердикт виден на странице Models и в cradle models list:

cradle models list
# ● fits comfortably  qwen3-8b-q4  needs ~10.0 GB; 18 GB total
# ● tight             qwen3-14b-q4 needs ~16.0 GB; 18 GB total
# ● won't run         llama-3.3-70b-q4 needs ~48 GB; 18 GB total

cradle models check <catalogId> выводит полный расчёт (weights + KV cache + headroom). Проверка находится в src/core/models/hardware-checker.ts.

Скачивание и докачка

Файлы моделей сохраняются в директорию пользовательских данных:

  • Desktop app: ~/Library/Application Support/Cradle/models/<id>.gguf
  • Сервер: ~/.cradle/models/<id>.gguf

Загрузки поддерживают докачку через .part-файлы и заголовок Range: bytes=X-, отмену через AbortController, опциональную проверку SHA-256, а также broadcast прогресса каждые 300 мс.

Интерфейс runner

type RunnerConfig = {
  contextSize?: number
  gpuLayers?: number | 'auto'
  mode?: 'chat' | 'embedding'
}

interface ModelRunner {
  load(modelPath, modelId, config): Promise<void>
  generate(prompt, opts?): AsyncIterable<string>
  generateStructured<T>(prompt, schema, opts?): Promise<T>
  embed(texts: string[]): Promise<number[][]>
  unload(): Promise<void>
  status(): RunnerStatus
}

Первая реализация — LlamaCppRunner. Он оборачивает node-llama-cpp v3 с prebuilt-бинарями для Metal, CUDA и Vulkan. Модель загружается строго в одном режиме за раз — переключение chat/embedding выгружает и перезагружает.

Управление памятью

Реестр моделей хранит загруженные runner в Map по id строки модели:

  • Бюджет по умолчанию — 60 % от общего RAM.
  • LRU-эвикция выгружает least-recently-used runner при превышении бюджета.
  • last_used_at обновляется на каждый acquire().
  • shutdownRegistry() корректно dispose все runner при выходе.

Маленькие модели (классификатор + embedder) дёшево держать загруженными одновременно. Большие агентские модели загружаются лениво по первому запросу.

Кастомные модели

Можно добавить кастомную модель через страницу Models или отредактировав userData/models-catalog-custom.json:

[{
  "id": "my-domain-slug",
  "name": "My domain model",
  "role": "general",
  "sizeMb": 3000,
  "url": "https://huggingface.co/.../model-Q4_K_M.gguf",
  "sha256": null,
  "recommendedRamGb": 6,
  "contextSize": 8192,
  "description": "..."
}]

Кастомные записи мержатся с встроенным каталогом. Совпадающий id переопределяет встроенную запись.

Рекомендуемые модели

cradle models list --recommended показывает обновляемый раз в неделю топ-25 OpenLLM Leaderboard, каждая с тем же вердиктом совместимости. Это оператор-управляемая функция: список загружается и кешируется, но не скачивается автоматически.