Что это решает
Локальный ИИ-агент нужен, когда данные нельзя отправлять наружу, а работа всё равно должна делаться моделью: медицинские выписки, переписка с клиентами, внутренние документы, коммерческая тайна. Второй мотив — независимость: ни лимитов провайдера, ни смены поведения модели после обновления на чужой стороне, ни отвалившегося интернета. Третий — расход: железо покупается один раз, дальше счётчик не крутится, и массовая рутина вроде разметки десятков тысяч записей перестаёт упираться в бюджет. Взамен приходится самому решать вопросы, которые в облаке решены за вас: сколько памяти, какое квантование, почему модель перестала возвращать вызовы инструментов.
Как устроено
Конструкция трёхслойная: движок инференса → файл весов → агентная обвязка.
Движок
- llama.cpp — базовый движок и сервер
llama-server, работает на CPU и на GPU, ест формат GGUF. - Ollama — обёртка над ним с каталогом моделей и менеджментом загрузки, самый короткий путь к первому запуску.
- LM Studio — то же самое с графическим интерфейсом, удобно для примерки моделей.
- vLLM — сервер под GPU и параллельные запросы, берёт веса в формате safetensors, окупается, когда пользователей больше одного.
- MLX — путь для Apple Silicon с использованием общей памяти.
Веса и квантование
Модель на диске — это матрицы чисел. В исходном виде каждый параметр занимает два байта, при квантовании его ужимают до восьми, шести, пяти или четырёх бит с потерей точности. Механика прикидки простая: память под веса ≈ число параметров × бит на параметр / 8. К этому добавляется KV-кэш — хранилище состояния внимания по всем обработанным токенам. Кэш растёт с длиной контекста, числом слоёв и размерностью внимания, и на длинных диалогах способен занять больше, чем сами веса. Плюс накладные расходы движка.
Ключевой порог: пока всё это помещается в видеопамять, скорость определяется GPU. Как только часть слоёв уходит в системную память, генерация резко замедляется, потому что каждый токен тащит данные через шину. Именно этот порог, а не название модели, определяет, будет ли агент пригоден к работе.
Скорость и почему агент дороже чата
Генерация делится на две фазы: prefill (обработка всего входа) и decode (выдача токенов по одному). Агент на каждом шаге цикла отправляет заново всю накопленную историю, поэтому именно prefill становится узким местом: пятый шаг цикла обрабатывает вход, выросший на все предыдущие результаты инструментов. Локально это чувствуется сильнее, чем в облаке, где префикс кэшируется на стороне провайдера.
Обвязка
Почти все движки отдают OpenAI-совместимый эндпоинт /v1/chat/completions. Любой агентный код подключается сменой base_url и фиктивного ключа — переписывать цикл не нужно.
Отдельная проверка — вызов инструментов. Поддержка tools зависит от модели и от её шаблона чата: часть моделей возвращает вызов текстом внутри ответа вместо структурированного tool_calls, часть путается при нескольких инструментах сразу. Это проверяется на своих схемах до всякой интеграции.
Правило: сначала измерить, влезает ли модель вместе с рабочим контекстом в видеопамять, и только потом обсуждать её качество.
Как подключить
Шаг 1. Посмотреть железо. На NVIDIA — nvidia-smi, колонка Memory-Usage покажет общий объём и занятое. На Mac — system_profiler SPDisplaysDataType и общий объём RAM, который делится с графикой. Заодно проверить свободное место на диске: файлы весов крупные.
Шаг 2. Поставить движок.
brew install ollama # или установщик с сайта
ollama serve # адрес и порт печатаются в выводе
Шаг 3. Скачать модель. В каталоге у каждого тега указан размер и квантование — начинать разумно с варианта, который заведомо меньше доступной памяти.
ollama pull <модель>:<тег>
ollama list
Шаг 4. Проверить эндпоинт тем же запросом, каким пойдёт агент. Адрес брать из вывода ollama serve, не из памяти.
curl http://127.0.0.1:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"<модель>","messages":[{"role":"user","content":"скажи ok"}]}'
Шаг 5. Убедиться, что модель в GPU. ollama ps показывает, какая часть ушла на процессор. Любая доля на CPU — сигнал брать более сжатый вариант или уменьшать контекст.
Шаг 6. Подключить агента. В клиенте выставить base_url на локальный адрес и произвольный ключ. Остальной код цикла не меняется.
Шаг 7. Проверить инструменты. Отправить запрос с массивом tools и посмотреть на ответ: пришёл ли tool_calls со списком аргументов, валиден ли JSON, не оказался ли вызов пересказан прозой.
Шаг 8. Настроить контекст. В Ollama — параметр num_ctx, в llama-server — --ctx-size. Значение подбирается под самый длинный реальный запрос, а не с запасом: каждый лишний токен окна занимает память под кэш даже вхолостую.
Шаг 9. Автозапуск. На Mac — launchd-агент в ~/Library/LaunchAgents, на Linux — unit в systemd. Проверить, что после перезагрузки сервер поднимается сам.
Шаг 10. Закрыть доступ. Сервер слушает на 127.0.0.1, наружу — только через туннель с авторизацией. Открытый в сеть эндпоинт без ключа отдаст вычисления кому угодно.
Полезные сценарии
- Разбор документов с персональными данными без выхода за периметр компании.
- Массовая классификация и разметка, где важен объём, а не тонкость рассуждений.
- Офлайн-помощник на ноутбуке: работа в самолёте, в поле, за закрытым контуром.
- Локальный поиск по базе знаний: индекс и генерация ответа на одной машине.
- Предварительный фильтр перед облачной моделью: локально отсеять шум, наверх отправить остаток.
- Черновая обработка кода и текстов, где цена ошибки низкая, а частота обращений высокая.
Ограничения
Качество на длинных цепочках рассуждений и на многошаговых вызовах инструментов уступает сильнейшим облачным моделям. Агент, который у облака проходит десять шагов, локально начинает терять нить и повторять вызовы.
Длинный контекст платится памятью. Модель, комфортно живущая на коротких запросах, перестаёт помещаться, как только окно расширили под большой документ.
Параллельные пользователи требуют другого движка: Ollama и llama.cpp рассчитаны на одного-двух, при нескольких одновременных запросах очередь растёт. Под нагрузку берут vLLM.
Обслуживание ложится на вас: обновление движка, совместимость шаблонов чата, новые форматы весов, регресс поведения после смены версии. Автоматических улучшений «само по себе» не происходит.
Физика тоже присылает счёт: шум, нагрев, электричество, простой дорогого железа между задачами.
Время инженера — крупнейшая статья на старте. Если задача разовая, аренда GPU по часам закроет её быстрее покупки.
Как проверить результат
ollama psили логllama-server— вся ли модель в GPU. Это первая проверка, остальные без неё бессмысленны.- Скорость на своём типичном запросе, а не на «привет»: сервер печатает в лог время prefill и токены в секунду. Замерить отдельно короткий вход и вход, равный худшему рабочему случаю.
- Золотой набор из нескольких десятков своих задач: прогнать локально и на облачной модели с одинаковыми промптами, сравнить долю правильных исходов. Решение принимается по этой таблице.
- Доля валидных
tool_callsот общего числа шагов агента. Низкая — менять модель или переходить на строгий формат ответа со схемой. - Поведение под памятью: во время прогона смотреть на
nvidia-smiили монитор памяти, ловить момент вытеснения в своп — там скорость падает без всяких сообщений об ошибке. - Изоляция: отключить сеть и прогнать набор целиком. Если всё отработало, а
lsof -iне показал исходящих соединений, контур действительно закрыт.
