Локальная модель без Ollama: digit local
До этой команды «локальный» путь первого запуска упирался в чужой установщик:
мастер искал ollama в PATH и, не найдя, печатал ссылку на ollama.com и
выходил. Человек, который хотел просто запустить агента, получал домашнее
задание — и получал его ровно в том месте, ради которого мастер и запускали.
digit local доводит дело до конца силами самого Digit: скачивает
llama-server, скачивает веса, поднимает OpenAI-совместимый сервер на
127.0.0.1:8127 и печатает готовую секцию для config.yaml.
digit local start | stop | status
Почему llama.cpp, а не Ollama
Ollama — отдельный демон со своим форматом хранения. GGUF в него надо
импортировать через Modelfile, а для этого Ollama уже должна быть
установлена: чтобы решить проблему «нет модели», сначала нужно решить проблему
«нет Ollama».
llama.cpp публикует готовые бинарники под каждую платформу (лицензия MIT),
читает GGUF с диска как есть и поднимает ровно тот OpenAI-совместимый
эндпоинт, с которым Digit и так работает через провайдер custom. Не хватало
только того, кто его поднимет.
Если Ollama в системе уже стоит, мастер первого запуска возьмёт её и качать ничего не станет. Это не предпочтение, а вежливость: поднимать рядом второй сервер и качать вторые веса — расточительство.
Что происходит при digit local start
Четыре шага, и каждый пропускается, если его результат уже на месте.
- Бинарник. Скачивается ассет релиза llama.cpp под текущую платформу,
сверяется sha256, архив распаковывается в
$DIGIT_HOME/bin/llama.cpp-<тег>/целиком — не одним файлом. - Веса. GGUF качается в
$DIGIT_HOME/models/во временный файл рядом и переименовывается только целиком. - Сервер. Запускается
llama-server, и команда ждёт не появления процесса, а ответа200на/health. - Конфиг. Печатается готовая секция
model:— Digit её не подставляет молча, а показывает.
Проверено запуском на этой машине (Linux x86_64, 8 ядер, сборка без ускорителей):
· Скачиваю llama.cpp b10295 (llama-b10295-bin-ubuntu-x64.tar.gz)
установлено за 0.86 с -> …/bin/llama.cpp-b10295/llama-server
version: 10295 (3db4ff877)
Замер разработчика на 16-ядерном хосте, с основными весами: установка
llama-server — 1,2 с, загрузка весов (2,3 ГиБ) — 75 с, подъём сервера —
9,1 с, 8,9 ГиБ RSS при окне 64 000 с KV-кэшем в q8_0. Числа зависят от канала
и процессора: на этой машине те же 424 МиБ вспомогательных весов качались
179,6 с, а сервер поднялся за 13,2 с.
Куда всё кладётся
| Что | Где | Сколько |
|---|---|---|
llama-server и его библиотеки |
$DIGIT_HOME/bin/llama.cpp-<тег>/ |
40 МиБ распакованными |
| Веса основной модели | $DIGIT_HOME/models/Qwen3-4B-Instruct-2507-Q4_K_M.gguf |
2,3 ГиБ |
| PID и лог сервера | $DIGIT_HOME/models/llama-server-<порт>.{pid,log} |
байты |
$DIGIT_HOME по умолчанию — ~/.digit. Наружу при этом уходят ровно две
загрузки: релиз llama.cpp с GitHub и файл весов с Hugging Face.
Что видно без запуска: digit local status
Команда отвечает и тогда, когда ничего ещё не скачано, — и это её основная работа. Живой прогон на машине, где локальная модель не поднималась:
$ digit local status
llama-server не запущен (порт 8127)
бинарник: не установлен — поставится при `digit local start`
веса qwen3-4b-instruct-2507: не скачаны (2.3 ГиБ, окно 262144)
веса digit-router-0.6b: не скачаны (0.4 ГиБ, окно 40960)
Отдельно различается случай «на порту что-то отвечает, но запущено не через
digit local»: чужой сервер на 8127 не будет ни перезапущен, ни остановлен.
Тег llama.cpp прибит гвоздями вместе с хешами
Версия берётся не из /releases/latest, и причина не теоретическая:
2026-08-06 в 13:42 UTC у свежего тега в релизе висел один ассет из
двадцати пяти — CI ещё догружал остальные. «Latest» у llama.cpp не атомарен,
и автоустановка, которая ему доверяет, ломается в случайные минуты дня.
Контрольные суммы взять неоткуда: апстрим файла с ними не публикует. Поэтому
sha256 каждого ассета снят руками при закреплении тега и лежит в коде
(digit_cli/local_model.py). Без него любой, кто может подменить ответ на пути
к серверу раздачи, кладёт исполняемый файл в $DIGIT_HOME/bin. Не сошёлся хеш
— архив не распаковывается вовсе.
Обновление тега — отдельное осознанное действие вместе с пересчётом хешей, а не побочный эффект запуска.
Какие платформы поддержаны, а какие нет
Готовых сборок шесть: Linux x86_64 и aarch64, macOS arm64 и x86_64,
Windows x64 и ARM64. Этого достаточно для обычных машин и не покрывает
FreeBSD, musl-дистрибутивы вроде Alpine, 32-битные системы и Termux (ассет
android-arm64 в релизе есть, но собран не под Termux и нами не проверялся —
поэтому мы его не обещаем).
На неподдержанной платформе команда не притворяется, что справилась, а
печатает три выхода: собрать llama.cpp самому и указать путь через
DIGIT_LLAMA_SERVER, поставить пакетом (brew install llama.cpp) или
подключить любой другой OpenAI-совместимый эндпоинт через digit model.
DIGIT_LLAMA_SERVER проверяется первым и на поддержанных платформах тоже:
у кого собрана своя сборка с CUDA или Metal, тот не должен получить нашу
процессорную вместо неё.
Чем сервер запускается и почему именно так
Флаги не подобраны на глаз, у каждого есть цена, которую он покупает.
--jinja— без негоllama-serverне применяет шаблон чата модели и не собираетtool_calls. Для агента, который весь состоит из вызовов инструментов, это разница между «работает» и «просто болтает».--cache-type-k q8_0,--cache-type-v q8_0— KV-кэш квантованный. На окне 64 000 у модели 4B это 4,8 ГиБ против 9,7 ГиБ: разница между «влезло в ноутбук» и «не влезло». Квантованный V-кэш llama.cpp принимает только вместе с--flash-attn, поэтому она включена.--parallel 1— один слот. Агент ходит по одному запросу за раз, а KV-кэш делится между слотами: при двух слотах каждому досталась бы половина окна.--cors-origins localhost— по умолчаниюllama-serverотдаётAccess-Control-Allow-Origin: *и сам предупреждает об этом в логе. Слушаем мы только127.0.0.1, но этого мало: страница в браузере ходит на localhost беспрепятственно и с открытым CORS может и гонять модель, и прочитать из/propsпуть к файлу весов.--alias <имя файла>— без него сервер отдаёт в/v1/modelsполный путь к файлу, иmodel.defaultв конфиге с ним не совпадает.
Почему окно 64 000 и почему модель именно эта
Требование жёсткое и задано не выбором модели: Digit отвергает окно меньше 64 000 токенов на старте, потому что схемы инструментов и системный промпт занимают большой фиксированный префикс. Замер: системный промпт с одним тулсетом — 7,4 тыс. токенов, со стандартным набором — 18,6 тыс.
Это отсекает почти все «маленькие» модели: Qwen3-1.7B и Qwen3-4B обучены на
32 768, наш собственный роутер — на 40 960. Просить у сервера больше
бессмысленно: llama-server обрезает окно слота по обучающему и пишет об этом
в лог («the slot context exceeds the training context of the model —
capping»), а отключить обрезку нечем.
Qwen3-4B-Instruct-2507 обучена на 262 144 и вызывает инструменты — отсюда и выбор, а не из соображений «поменьше скачивать».
Свой роутер основной моделью быть не может
digit local start --model router
Скачает digit-router-0.6b (424 МиБ) и поднимет его на том же порту, но
предупредит о себе при запуске, и предупреждение стоит читать. Роутер
обучен на окне 40 960 — меньше требуемых 64 000, и Digit отвергнет такую
конфигурацию на старте с явной ошибкой.
Его место вспомогательное: выбрать инструмент и фрагмент корпуса, а не отвечать. Содержание ответа в проверяемом режиме приходит из утилиты, дословной цитаты или сертификата FTS — поставить роутер источником фактов значит потерять ровно то, ради чего он обучался. Разбор устройства — на странице «Как устроена проверяемость».
Живой прогон вспомогательных весов на этой машине: 424 МиБ скачаны за 179,6 с,
сервер поднялся за 13,2 с, RSS 2,8 ГиБ при окне 40 960, /v1/models вернул
router-0.6b-v3-Q5_K_M.gguf.
Сервер — процесс, а не служба
После перезагрузки llama-server сам не вернётся. Поэтому при обычном запуске
digit поднимет его сам — но только если выполнены оба условия: конфиг
указывает именно на наш порт и наши веса, и веса с бинарником уже лежат на
диске. Ничего не докачивается молча: тихая загрузка на гигабайты при обычном
запуске digit — не то, чего от него ждут.
digit local stop останавливает только тот сервер, который запускали мы:
PID берётся из своего файла, а не из поиска по процессам.
Чего это стоит
2,3 ГиБ на диске под веса, 40 МиБ под сервер и около 9 ГиБ оперативной памяти
при окне 64 000. Без квантованного KV-кэша — почти вдвое больше. Модель на 4B в
Q4 на процессоре отвечает приемлемо; кому нужна видеокарта, тот ставит свою
сборку и указывает её через DIGIT_LLAMA_SERVER.
Скрипт scripts/local-router.sh остался в репозитории обёрткой над этой же
командой — своей логики у него больше нет.
Границы
Качество ответов этой модели на задачах агента мы не измеряли. При подготовке
страницы прогонялись установка бинарника, загрузка весов, подъём сервера,
/health, /v1/models и остановка. Сквозной прогон агента с вызовом
инструмента (read_file) снят разработчиком, не нами, — как и числа на
основных весах.
Числа выше сняты на процессорной сборке без ускорителей; на других машинах они другие. Замера на macOS и Windows у нас нет: код собирает ту же команду, но проверялся он на Linux.
Справочник по командам целиком — в английской
документации; digit local
там пока не описана, эта страница — единственное её описание.