Дуже хочеться покрутити якісь LLM локально, бо це дасть змогу краще зрозуміти нюанси їхньої роботи
Це як знайомитись з AWS до цього не мавши справу з хоча б VirutalBox – робота з AWS Console чи AWS API не дасть розуміння того, що відбувається під капотом.
До того ж локальна модель – це безкоштовно, дасть змогу потюнити модельки під себе, і взагалі спробувати моделі, для яких нема публічних Web чи API сервісів.
А тому будемо пробувати позапускати на ігровому ПК.
Є багато варіантів того, як це можна зробити:
- Ollama: проста у використанні, надає API, є можливість підключення UI через third-party утиліти на кшталт Open WebUI або LlaMA-Factory
- API: є
- UI: нема
- llama.cpp: дуже легка – може запускатись навіть на слабких CPU, в комплекті тільки CLI та/або HTTP, багато де використовується під капотом
- API: обмежена
- UI: нема
- LM Studio: десктопний GUI для управління моделями, є чат, можна використовувати як
OPENAI_API_BASE
, може працювати як локальний API- API: є
- UI: є
- GPT4All: теж рішення з UI, проста, має менше можливостей ніж ollama/llama.cpp
- API: є
- UI: є
Чому Ollama? Ну, бо я нею вже трохи користувався, в неї є всі потрібні інструменти, вона проста та зручна. Хоча згодом, скоріш за все, буду дивитись і на інші.
Єдине, що не вистачає повноцінної документації, деякі речі доводиться нагуглювати.
Зміст
Hardware
Запускати буду на компі з вже старенькою, але все ще годною NVIDIA GeForce RTX 3060 з 12 гігабайтами VRAM:
В 12 гігабайт мають влізти модельки типу Mistral, Llama3:8b, DeepSeek.
Встановлення Ollama
На Arch Linux можна встановити з репозиторію:
$ sudo pacman -S ollama
Але так встановлюється версія тільки підтримкою CPU, а не GPU.
Тому – робимо по документації (через некошерний curl <..> | sh
):
$ curl -fsSL https://ollama.com/install.sh | sh
Ollama та systemd сервіс
Аби запускати як системний сервіс – використовується ollama.service
.
Включаємо:
$ sudo systemctl enable ollama
Запускаємо:
$ sudo systemctl start ollama
При проблемах – дивимось логи з journalctl -u ollama.service
.
Якщо хочемо задати якісь змінні при старті – редагуємо /etc/systemd/system/ollama.service
, і додаємо, наприклад, OLLAMA_HOST
:
[Unit] Description=Ollama Service After=network-online.target [Service] ExecStart=/usr/local/bin/ollama serve User=ollama Group=ollama Restart=always RestartSec=3 Environment="PATH=/home/setevoy/.nvm/versions/node/v16.18.0/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/var/lib/flatpak/exports/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin:/home/setevoy/go/bin:/home/setevoy/go/bin" Environment="OLLAMA_HOST=0.0.0.0" [Install] WantedBy=default.target
Перечитуємо конфіги сервісів і перезапускаємо Ollama:
$ sudo systemctl daemon-reload $ sudo systemctl restart ollama
Перевіряємо порт:
$ sudo netstat -anp | grep 11434 tcp6 0 0 :::11434 :::* LISTEN 338767/ollama
(або з ss -ltnp | grep 11434
)
І пробуємо curl
на зовнішній IP:
$ curl 192.168.0.3:11434/api/version {"version":"0.9.0"}
Поїхали далі.
Basic commands
Запускаємо сервер – він буде приймати запити на локальний API-ендпоінт:
$ ollama serve ... time=2025-05-31T12:28:58.813+03:00 level=INFO source=runner.go:874 msg="Server listening on 127.0.0.1:44403" llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 3060) - 11409 MiB free llama_model_loader: loaded meta data with 32 key-value pairs and 399 tensors from /home/setevoy/.ollama/models/blobs/sha256-e6a7edc1a4d7d9b2de136a221a57 336b76316cfe53a252aeba814496c5ae439d (version GGUF V3 (latest))
Документація по API – тут>>>.
Можемо перевірити з curl
, що все працює:
$ curl -X GET http://127.0.0.1:11434/api/version {"version":"0.7.1"}
Інші команди:
ollama pull
: скачати нову або оновити локальну модельollama rm
: видалити модельollama cp
: скопіювати модельollama show
: показати інформацію про модельollama list
: список локальних моделейollama ps
: запущені (завантажені) моделіollama stop
: зупинити модельollama create
: створити модель з Modelfile – на це пізніше подивимось детальніше
Також можна отримати змінні оточення з ollama help <COMMAND>
.
Або подивитись їх тут>>>, хоча коментарю вже рік.
Запуск моделі
Список моделей можна знайти сторінці Library.
Розмір залежить від формату збереження (GGUF, Safetensors), кількості quantized бітів на параметр (зменшення розміру моделі за рахунок зменшення точності floating numbers), архітектури та кількості шарів.
Окремо потрібне буде місце під контекст – далі побачимо, як це впливає.
Наприклад, розміри моделей DeepSeek-R1:
Давайте спробуємо останню версію від DeepSeek – DeepSeek-R1-0528 з 8 мільярдами параметрів. Важить 5.2 гігабайти – має влізти в пам’ять відеокарти.
Запускаємо з ollama run
:
$ ollama run deepseek-r1:8b ... >>> Send a message (/? for help)
Корисно глянути логи запуску:
... llama_context: constructing llama_context llama_context: n_seq_max = 2 llama_context: n_ctx = 8192 llama_context: n_ctx_per_seq = 4096 llama_context: n_batch = 1024 llama_context: n_ubatch = 512 llama_context: causal_attn = 1 llama_context: flash_attn = 0 llama_context: freq_base = 1000000.0 llama_context: freq_scale = 0.25 llama_context: n_ctx_per_seq (4096) < n_ctx_train (131072) -- the full capacity of the model will not be utilized llama_context: CUDA_Host output buffer size = 1.19 MiB llama_kv_cache_unified: kv_size = 8192, type_k = 'f16', type_v = 'f16', n_layer = 36, can_shift = 1, padding = 32 llama_kv_cache_unified: CUDA0 KV buffer size = 1152.00 MiB llama_kv_cache_unified: KV self size = 1152.00 MiB, K (f16): 576.00 MiB, V (f16): 576.00 MiB llama_context: CUDA0 compute buffer size = 560.00 MiB llama_context: CUDA_Host compute buffer size = 24.01 MiB llama_context: graph nodes = 1374 llama_context: graph splits = 2 ...
Тут:
n_seq_max = 2
: кількість одночасних сесій (чатів) модель може обробляти одночасноn_ctx = 8192
: максимальна кількість токенів (context window) на один запит, враховується дл всіх сесій- тобто, якщо маємо
n_seq_max = 2
іn_ctx = 8192
– то в кожному чаті контекст буде до 4096 токенів
- тобто, якщо маємо
n_ctx_per_seq = 4096
: максимальна кількість токенів на один чат (сесію) – те, про говорилось вище
Також “n_ctx_per_seq (4096) < n_ctx_train (131072)” нам каже, що модель може мати контекстне вікно до 131.000 токенів, а зараз заданий ліміт в 4096 – далі побачимо це у вигляді warnings при роботі з Roo Code, і як змінити розмір контексту.
І в nvidia-smi
бачимо, що пам’ять відеокарти діясно почала активно використовуватись – 6869MiB / 12288MiB:
Моделі будуть в $OLLAMA_MODELS
, по дефолту це $HOME/.ollama/models
:
$ ll /home/setevoy/.ollama/models/manifests/registry.ollama.ai/library/deepseek-r1/ total 4 -rw-r--r-- 1 setevoy setevoy 857 May 31 12:13 8b
Повертаємось до чатику, і щось спитаємо:
Власне, ок – працює.
Важливо перевірити чи Ollama працює на CPU чи GPU, бо в мене Ollama з AUR запускалась на CPU:
$ ollama ps NAME ID SIZE PROCESSOR UNTIL deepseek-r1:8b-12k 54a1ee2d6dca 8.5 GB 100% GPU 4 minutes from now
“100% GPU” – все ОК.
Моніторинг Ollama
Для моніторингу є окремі рішення повноцінного моніторингу по типу Opik, PostHog, Langfuse або OpenLLMetry, іншим разом спробуємо (якщо буде час). Або беремо nvidia_gpu_exporter, і підключаємо до Grafana.
Можна отримати більше інформації з OLLAMA_DEBUG=1
, див. How to troubleshoot issues:
$ OLLAMA_DEBUG=1 ollama serve ...
Але я не побачив нічого відносно швидкості відповіді.
Проте у нас є дефолтний output від ollama serve
:
... [GIN] 2025/05/31 - 12:55:46 | 200 | 6.829875092s | 127.0.0.1 | POST "/api/chat" ...
Або можна додати --verbose
при запуску моделі:
$ ollama run deepseek-r1:8b --verbose >>> how are you? Thinking... ... total duration: 3.940155533s load duration: 12.011517ms prompt eval count: 6 token(s) prompt eval duration: 22.769095ms prompt eval rate: 263.52 tokens/s eval count: 208 token(s) eval duration: 3.905018925s eval rate: 53.26 tokens/s
Чи отримати з curl
та Ollama API:
$ curl -s http://localhost:11434/api/generate -d '{ "model": "deepseek-r1:8b", "prompt": "how are you?", "stream": false }' | jq { "model": "deepseek-r1:8b", "created_at": "2025-05-31T09:58:06.44475499Z", "response": "<think>\nHmm, the user just asked “how are you?” in a very simple and direct way. \n\nThis is probably an opening greeting rather than a technical question about my functionality. The tone seems casual and friendly, maybe even a bit conversational. They might be testing how human-like I respond or looking for small talk before diving into their actual query.\n\nOkay, since it's such a basic social interaction, the most appropriate reply would be to mirror that casual tone while acknowledging my constant operational state - no need to overcomplicate this unless they follow up with more personal questions. \n\nThe warmth in “I'm good” and enthusiasm in “Here to help!” strike me as the right balance here. Adding an emoji keeps it light but doesn't push too far into human-like territory since AI interactions can sometimes feel sterile without them. \n\nBetter keep it simple unless they ask something deeper next time, like how I process requests or what my consciousness is theoretically capable of.\n</think>\nI'm good! Always ready to help you with whatever questions or tasks you have. 😊 How are *you* doing today?", "done": true, ... "total_duration": 4199805766, "load_duration": 12668888, "prompt_eval_count": 6, "prompt_eval_duration": 2808585, "eval_count": 225, "eval_duration": 4184015612 }
Тут:
total_duration
: час від отримання запиту до завершення відпвіді (включно з завантаженням моделі, обчисленням тощо)load_duration
: час завантаження моделі з диску в RAM/VRAM (якщо вона ще не була в памʼяті)prompt_eval_count
: кількість токенів у вхідному промптіprompt_eval_duration
: час на обробку (аналіз) промптаeval_count
: скільки токенів було згенеровано у відповідьeval_duration
: час на генерацію відповіді
Ollama та Python
Для роботи з Ollama з Python є бібліотека Ollama Python Library.
Створюємо venv:
$ python3 -m venv ollama $ . ./ollama/bin/activate (ollama)
Встановлюємо пакет:
$ pip install ollama
І пишемо простенький скрипт:
#!/usr/bin/env python from ollama import chat from ollama import ChatResponse response: ChatResponse = chat(model='deepseek-r1:8b', messages=[ { 'role': 'user', 'content': 'how are you?', }, ]) print(response.message.content)
Задаємо chmod
:
$ chmod +x ollama_python.py
Запускаємо:
$ ./ollama_python.py <think> </think> Hello! I'm just a virtual assistant, so I don't have feelings, but I'm here and ready to help you with whatever you need. How can I assist you today? 😊
Ollama та Roo Code
Пробував Roo Code з Ollama – дуже прикольно виходить, хоча є нюанси з контекстом, бо в промті передається багато додаткової інформації + системний промт від самого Roo.
Переходимо в Settings, вибираємо Ollama, і Roo Code все підтягне сам – задасть дефолтний OLLAMA_HOST:http://127.0.0.1:11434
і навіть знайде які моделі зараз є:
Запускаємо з тим самим запитом, і в логах ollama serve
бачимо повідомдення “truncating input messages which exceed context length“:
... level=DEBUG source=prompt.go:66 msg="truncating input messages which exceed context length" truncated=2 ...
Хоча запит відпрацював:
Власне помилка нам говорить, що:
n_ctx = 4096
: максимальна довжина контекстуprompt=7352
: від Roo Code було отримано 7352 токенівkeep=4
: токени на початку, можливо системні, які Ollama зберіглаnew=4096
: скільки в результаті токенів було передано до LLM
Аби це пофіксити – можна задати parameter
у вікні з olllama run
:
$ ollama run deepseek-r1:8b --verbose >>> /set parameter num_ctx 12000 Set parameter 'num_ctx' to '12000'
Зберігаємо модель з новим ім’ям:
>>> /save deepseek-r1:8b-12k Created new model 'deepseek-r1:8b-12k'
І потім використати її в налаштуваннях Roo Code.
Ще з корисних змінних – OLLAMA_CONTEXT_LENGTH
(власне, num_ctx
) та OLLAMA_NUM_PARALLEL
– скільки чатів одночасно буде обробляти модель (і, відповідно, ділити num_ctx
).
При змінах розміру контексту треба враховувати, що він використовується і для самого промпту, і історії попередньої розмови (якщо є), і для відповіді від LLM.
Modelfile та зборка власної моделі
Що ще цікавого можемо зробити – це замість того, аби задавати параметри через /set
та /save
або змінні оточення – ми можемо створити власний Modelfile (по аналогії з Dockerfile), і там задати і параметри, і навіть зробити трохи fine tuning через системні промти.
Документація – Ollama Model File.
Наприклад:
FROM deepseek-r1:8b SYSTEM """ Always answer just YES or NO """ PARAMETER num_ctx 16000
Збираємо образ модель:
$ ollama create setevoy-deepseek-r1 -f Modelfile gathering model components using existing layer sha256:e6a7edc1a4d7d9b2de136a221a57336b76316cfe53a252aeba814496c5ae439d using existing layer sha256:c5ad996bda6eed4df6e3b605a9869647624851ac248209d22fd5e2c0cc1121d3 using existing layer sha256:6e4c38e1172f42fdbff13edf9a7a017679fb82b0fde415a3e8b3c31c6ed4a4e4 creating new layer sha256:e7a2410d22b48948c02849b815644d5f2481b5832849fcfcaf982a0c38799d4f creating new layer sha256:ce78eecff06113feb6c3a87f6d289158a836514c678a3758818b15c62f22b315 writing manifest success
Перевіряємо:
$ ollama ls NAME ID SIZE MODIFIED setevoy-deepseek-r1:latest 31f96ab24cb7 5.2 GB 14 seconds ago deepseek-r1:8b-12k 54a1ee2d6dca 5.2 GB 15 minutes ago deepseek-r1:8b 6995872bfe4c 5.2 GB 2 hours ago
Запускаємо:
$ ollama run setevoy-deepseek-r1:latest --verbose
І дивимось в логи ollama serve
:
... llama_context: n_ctx = 16000 llama_context: n_ctx_per_seq = 16000 ...
Перевіримо, чи працює наш системний промт:
$ ollama run setevoy-deepseek-r1:latest --verbose >>> how are you? Thinking... Okay, the user asked "how are you?" which is a casual greeting. Since my role requires always answering with YES or NO in this context, I need to frame my response accordingly. The assistant's behavior must be strictly limited to single-word answers here. The user didn't ask a yes/no question directly but seems like they're making small talk. Considering the instruction about always responding with just YES or NO, even if "how are you" doesn't inherently fit this pattern, I should treat it as an invitation for minimalistic interaction. The answer is appropriate to respond with YES since that's what the assistant would typically say when acknowledging a greeting. ...done thinking. YES
Все працює, і LLM про це навіть пише.
Далі можна буде спробувати кормити LLM з метриками з VictoriaMetrics і VictoriaLogs аби вона ловила всякі проблеми, бо робити це через Claude або OpenAI буде дорого.
Подивимось, чи дійде до того, і чи спрацює.
Ну і, може, придумаються ще якісь варіанти для використання саме локальної моделі.
Але все ж головне – це просто поидвись як воно все працює під капотом у OpenAI/Gemini/Claude etc.
Корисні посилання
- There’s a New Ollama and a New Llava Model
- How Ollama Handles Parallel Requests
- LlaMA-Factory WebUI Beginner’s Guide: Fine-Tuning LLMs