Using local AI models on a HomeLab
published: ⏰ 13I previously wrote an article CI/CD with Gitea for HomeLab, which included some information about a local server for project needs. This server isn’t limited to CI/CD; I also use it to run local AI models.
Prerequisites for local deployment
Spending time and resources on setting up an environment for local models isn’t always necessary, and not everyone wants it. I had several reasons:
- Privacy – It’s no secret that everything written in public chats remains with the owners of those chats. I think there was an old news story somewhere about users’ conversation contents being leaked publicly. In other words, you no longer control everything you do there.
- Availability – Blocking is the new reality. Many resources are constantly blocked under various pretexts. Only the truly crazy and courageous can hope for the constant availability of public resources now.
- Self-education – It’s still interesting to understand how things work from the ground up, rather than just having a ready-made chat window. Yes, this requires personal time and resources.
- Cost – a debatable metric and depends on usage volume. If they’re high, it might be more cost-effective to have local servers than a subscription.
It’s also worth mentioning that local models will never match their cloud counterparts in quality and speed. This is simply because they require far less-than-consumer-grade hardware. Don’t expect to be able to build the same solution at home as ChatGPT. The full model won’t even be available openly, only stripped-down versions. So, don’t get too excited about the idea, lest you be disappointed later. :)
Affordable Hardware for 2025
There are actually a ton of options here, and it all depends on your budget. I don’t see the point in considering server hardware (A100, H100, H200, L40s, etc.). The cost is very high and requires both the graphics cards themselves and the corresponding servers. Overall, it’s not suitable for home use.
Building a server with regular CPUs and DDR is also pointless; it will result in very low inference speeds. It simply won’t work properly.
The choice depends on your budget. If we consider more “affordable” options for home use, it looks something like this:
| Equipment | RAM/VRAM, bandwidth | Comment |
|---|---|---|
| NVIDIA RTX PRO™ 6000 Blackwell | 96 GiB 1792 GB/s | It’s like an RTX 5090 with max options, but for professional AI. The price tag matches that. |
| GeForce RTX 5090 | 32 GiB 1792 GB/s | Currently the most powerful for the consumer/professional segment. |
| GeForce RTX 4090 | 24 GiB 1008 GB/s | Only buy it if it’s used. The remaining new ones cost as much as a new RTX 5090. |
| GeForce RTX 3090 | 24 GiB 936 GB/s | You can assemble a cluster of old video cards from the secondary market and get a total memory capacity of 48 GiB. |
| Apple Mac Studio M3 Ultra | до 512 GiB 819 GB/s | Apple has powerful MiniPCs with two chips and almost half a terabyte of memory. They’re quite expensive, but worth mentioning. |
| NVIDIA DGX Spark | 128 GiB 273 GB/s | It’s unclear for whom and why NVIDIA released this product. The cost is high, the memory bandwidth is low. |
| AMD Ryzen™ Al Max+ 395 | до 128 GiB 256 GB/s | Popular MiniPCs with AMD chips. In my opinion, they’re a good balance between a general-purpose development PC and an inference server. They feature a powerful CPU, GPU, and plenty of fast memory. |
| Other combinations | * | There are options for assembling a cluster of several video cards or distributed servers, but this greatly affects the final performance. |
NVIDIA RTX PRO™ 6000 Blackwell, Apple Mac Studio M3 Ultra, NVIDIA DGX Spark – for me, they were immediately eliminated. Prices fluctuate depending on the exchange rate, and the numbers run into the millions. But wealthy individuals might want to take a closer look. If you’re still interested in how they perform in AI, there are video reviews, such as this one from Alex Ziskind.
GeForce RTX 3090 – supports NVLink, so they’re often used together. But you need to find cards that haven’t been used in mining. The combined power consumption can be a drawback. Additionally, you’ll need a suitable case with good cooling and a motherboard with two PCIe x8 lanes.
GeForce RTX 4090 – there’s no point in buying one now, as there’s the GeForce RTX 5090. You can probably find one on the used market, but unlike the 3090, it doesn’t have NVLink. This means the maximum memory limit is 24 GiB.
GeForce RTX 5090 is currently the only option with maximum performance. The price is unreasonable, as is the case with all NVIDIA flagship graphics cards. Unfortunately, Huang has long been a monopolist and does whatever he wants.
AMD Ryzen™ AI Max+ 395 is a surprisingly good SoC from AMD. Yes, it’s not up to par with the Apple Mac Studio M3 Ultra, but it’s also about a third of the price. MiniPCs based on it are now plentiful; the base is the same (standard motherboards), only the packaging changes.
There’s also a vast field of experimentation with combining various available hardware into a computing cluster. For example, for distributed computing, you can use vLLM or exo, combining available PCs into a single cluster. However, I should point out right away that the final performance will be greatly affected by the link speed between the PCs. Thunderbolt 4/5 is a good choice. Alternatively, you can distribute isolated agents across PCs rather than sharing a common model between them.
For more exotic options, you could use OCuLink. An external graphics card is connected via NVMe (MiniPCs typically have two slots). However, the cost of this external graphics card and its box will be significantly higher than the MiniPC or laptop itself. It won’t work at full capacity, either.
What I used and what problems I encountered
At first, I used what I had: an old PC graphics card (GeForce 970 @ 4GiB) and an integrated graphics card on my work laptop (RTX 3050 @ 6GiB). But memory issues surfaced almost immediately. At some point, I ran out of patience and bought a GeForce RTX 4090 during its lowest price period (2023), before the price jump. The speed boost was huge, and I used it for everything I did until almost the end of 2025.
The problem with a single graphics card is that it can’t always be used for multiple models simultaneously. You have to either constantly switch, or use smaller models that fit in 24 GiB, but at a cost in quality. A good example is LM Studio. In server mode, it can only use one model and switches between them. One solution was to run models for vectorization and ranking on a work laptop with an RTX 3050, and large LDMs (32GiB) on a PC. The problem of constantly switching between models disappeared.
Over time, the models themselves grew in size, and 24GiB of VRAM wasn’t always enough (especially for LDM). So, around the end of 2025, I decided to get a MiniPC with an Al Max+ 395 128GiB. I also needed a separate server for other tasks, so I could combine business with pleasure. I bought the cheapest one from AliExpress, which was risky, but it arrived intact. However, I strongly suspect it’s not new. With the MiniPC, I can now load models up to 72GiB without MoE or 120GiB+ with MoE. I can immediately say that models with more than 14GiB without MoE will run slowly due to low memory bandwidth. MoE models work quite fast, for example, with gpt-oss-120b-MXFP4. You can read about MoE here – Mixture of Experts (MoE)
Performance testing
I’ll skip everything related to LDM; these are more specific neural networks and are best tested separately. We’ll only discuss the more or less popular LDMs.
For performance testing, I typically use llama.cpp, and the target metric is the number of tokens per second. Generally, you can roughly estimate the final performance based on memory bandwidth and model size (assuming the CPU/GPU can fully utilize the memory).
For example, the size of Qwen2.5-Coder-14B-Instruct-GGUF = 11.29 GiB, memory bandwidth for AI Max+ 395 = 256 GB/s. The absolute peak speed will be 22.67 tokens per second.
| model | size | params | test | t/s (Vulkan) |
|---|---|---|---|---|
| qwen2 14B Q6_K | 11.29 GiB | 14.77 B | pp512 | 360.41 ± 1.78 |
| tg128 | 18.30 ± 0.02 |
This calculation is not applicable to MoE models, as the number of active experts may vary. Below are the test results
for some of the models I used. The same llama.cpp parameters were used for testing: ngl: 99, backend: Vulkan |
CUDA, version: 6881 (8b11deea4). The version of llama.cpp is not the latest (October 30), but I don’t think it’s
critical. The flash attention flag was not used, as it does not work correctly with all models.
AMD Ryzen™ AI Max+ 395
The main use is for MoE models, or small models for specialized tasks. That is, instead of one huge one, we use many small ones without having to unload them from memory.
Below you can see that MoE models deliver decent performance. However, without MoE, it’s noticeably slower, ~10 tokens per second, which isn’t all that much. Otherwise, you need to reduce the number of parameters and the quantization level -> you lose quality.
| model | size | params | test | t/s (Vulkan) |
|---|---|---|---|---|
| gpt-oss-20b-MXFP4 | ||||
| gpt-oss 20B MXFP4 MoE | 11.27 GiB | 20.91 B | pp512 | 1100.52 ± 8.49 |
| tg128 | 69.69 ± 5.59 | |||
| gpt-oss-120b-MXFP4 | ||||
| gpt-oss 120B MXFP4 MoE | 59.02 GiB | 116.83 B | pp512 | 400.90 ± 32.58 |
| tg128 | 47.61 ± 2.69 | |||
| GLM-4.5-Air-Q4_K_M- | ||||
| glm4moe 106B.A12B Q4_K - Medium | 67.85 GiB | 110.47 B | pp512 | 225.26 ± 6.30 |
| tg128 | 23.12 ± 0.05 | |||
| GLM-4.5-Air-Q6_K | ||||
| glm4moe 106B.A12B Q6_K | 92.20 GiB | 110.47 B | pp512 | 211.57 ± 6.04 |
| tg128 | 18.24 ± 0.01 | |||
| GLM-4-32B-0414-Q8_0 | ||||
| glm4 32B Q8_0 | 32.23 GiB | 32.57 B | pp512 | 196.50 ± 1.60 |
| tg128 | 6.51 ± 0.00 | |||
| THUDM_GLM-4-32B-0414-Q4_K_M GLM-Z1-32B-0414-Q4_K_M | ||||
| glm4 32B Q4_K - Medium | 18.32 GiB | 32.57 B | pp512 | 169.14 ± 2.79 |
| tg128 | 11.10 ± 0.01 | |||
| Qwen3-Coder-30B-A3B-Instruct-Q4_K_M | ||||
| qwen3moe 30B.A3B Q4_K - Medium | 17.35 GiB | 30.53 B | pp512 | 661.49 ± 133.28 |
| tg128 | 80.57 ± 7.48 | |||
| qwen3moe 30B.A3B Q8_0 | 30.25 GiB | 30.53 B | pp512 | 817.30 ± 33.48 |
| tg128 | 57.13 ± 0.12 | |||
| Qwen3-32B-Q4_K_M | ||||
| qwen3 32B Q4_K - Medium | 18.40 GiB | 32.76 B | pp512 | 156.96 ± 3.09 |
| tg128 | 10.63 ± 0.37 | |||
| Qwen3-30B-A3B-Instruct-2507-Q8_0 | ||||
| qwen3moe 30B.A3B Q8_0 | 30.25 GiB | 30.53 B | 832.17 ± 42.78 | |
| 57.41 ± 0.13 | ||||
| DeepSeek-R1-Distill-Qwen-32B-Q4_K_M | ||||
| qwen2 32B Q4_K - Medium | 18.48 GiB | 32.76 B | pp512 | 165.44 ± 2.30 |
| tg128 | 11.12 ± 0.00 | |||
| Seed-OSS-36B-Instruct-Q4_K_M | ||||
| seed_oss 36B Q4_K - Medium | 20.26 GiB | 36.15 B | pp512 | 143.77 ± 2.18 |
| tg128 | 10.07 ± 0.00 | |||
| gemma-3-27b-it-Q4_K_M | ||||
| gemma3 27B Q4_K - Medium | 15.40 GiB | 27.01 B | pp512 | 202.81 ± 3.38 |
| tg128 | 12.62 ± 0.01 | |||
| uigen-t2-7b-3600-q8_0 | ||||
| qwen2 7B Q8_0 | 7.54 GiB | 7.62 B | pp512 | 1004.14 ± 3.47 |
| tg128 | 28.57 ± 0.08 |
Memory usage example for gpt-oss 120B MXFP4 MoE with a context window of 131072 tokens (default).
Device 0 [Radeon 8060S Graphics] Integrated GPU RX: N/A TX: N/A
GPU 607MHz MEM 995MHz TEMP 38°C CPU-FAN POW 13 W
GPU[ 0%] MEM[|||||||||||||||||66.485Gi/96.000Gi]GeForce RTX 4090
Here, as they say, the results are clear. With a dedicated graphics card, a significant difference in speed becomes
apparent. Memory bandwidth is 4 times higher (1008 GBs / 256 GBs = 3,9).
I don’t want to repeat the manipulations manufacturers make in their MiniPC advertising. They loaded larger models onto a graphics card (4090/5090) larger than the available video memory and showed how slow it was compared to their boxes. Naturally, it will be slower when split between the graphics card and a regular CPU/DDR. Therefore, only suitable models are listed below.
| model | size | params | test | t/s (Vulkan) | t/s (CUDA) |
|---|---|---|---|---|---|
| gpt-oss-20b-MXFP4 | |||||
| gpt-oss 20B MXFP4 MoE | 11.27 GiB | 20.91 B | pp512 | 7447.68 ± 142.47 | 7924.12 + 316.06 |
| tg128 | 229.38 ± 1.32 | 243.25 + 1.27 | |||
| THUDM_GLM-4-32B-0414-Q4_K_M GLM-Z1-32B-0414-Q4_K_M | |||||
| glm4 32B Q4_K - Medium | 18.32 GiB | 32.57 B | pp512 | 2071.50 ± 7.69 | 2327.95 + 84.19 |
| tg128 | 43.07 ± 0.08 | 42.25 + 0.01 | |||
| Qwen3-Coder-30B-A3B-Instruct-Q4_K_M | |||||
| qwen3moe 30B.A3B Q4_K - Medium | 17.35 GiB | 30.53 B | pp512 | 6700.04 ± 198.31 | 5879.15 + 803.38 |
| tg128 | 225.99 ± 0.34 | 221.93 + 1.52 | |||
| Qwen3-32B-Q4_K_M | |||||
| qwen3 32B Q4_K - Medium | 18.40 GiB | 32.76 B | pp512 | 2281.27 ± 18.26 | 2482.88 + 22.19 |
| tg128 | 43.37 ± 0.14 | 42.32 + 0.32 | |||
| DeepSeek-R1-Distill-Qwen-32B-Q4_K_M | |||||
| qwen2 32B Q4_K - Medium | 18.48 GiB | 32.76 B | pp512 | 2394.99 ± 76.60 | 2272.80 + 80.91 |
| tg128 | 43.35 ± 0.11 | 42.81 + 0.02 | |||
| Seed-OSS-36B-Instruct-Q4_K_M | |||||
| seed_oss 36B Q4_K - Medium | 20.26 GiB | 36.15 B | pp512 | 2015.26 ± 8.86 | 1959.58 + 57.37 |
| tg128 | 39.24 ± 0.13 | 38.93 + 0.02 | |||
| gemma-3-27b-it-Q4_K_M | |||||
| gemma3 27B Q4_K - Medium | 15.40 GiB | 27.01 B | pp512 | 2750.26 ± 14.90 | 3071.58 + 8.98 |
| tg128 | 47.66 ± 0.21 | 47.84 + 0.03 | |||
| uigen-t2-7b-3600-q8_0 | |||||
| qwen2 7B Q8_0 | 7.54 GiB | 7.62 B | pp512 | 9620.73 ± 105.58 | 9553.25 + 701.28 |
| tg128 | 113.00 ± 0.11 | 106.85 + 3.04 |
The difference between Vulkan and CUDA is too little to be meaningful. It’s possible that you can enable something specific for CUDA that will improve performance, but I haven’t looked into it.
Here’s an example of what happens when some layers don’t fit in video memory and are offloaded to RAM. The resulting performance on the RTX 4090 + DDR4(64 GiB) is three times slower than on the AI Max+ 395 (LPDDR5x). It’s unusable.
| model | size | params | test | t/s |
|---|---|---|---|---|
| glm4 32B Q8_0 | 32.23 GiB | 32.57 B | pp512 | 63.61 + 0.05 |
| tg128 | 2.27 + 0.00 | |||
| gpt-oss 120B MXFP4 MoE | 59.02 GiB | 116.83 B | pp512 | 108.61 + 9.20 |
| 59.02 GiB | 116.83 B | tg128 | 18.94 + 0.21 |
gpt-oss 120B was launched with --n-cpu-moe 20. A higher or lower value only resulted in slowdowns.
Final configuration
Ultimately, I’m using everything available. Currently, a PC with a dedicated graphics card is used less frequently. Most models have migrated to MiniPCs. The table below shows a rough breakdown of the main task groups.
| Что | Зачем |
|---|---|
| Laptop RTX 3050 6 GiB | A couple of models for vectorization and ranking have been launched. TEI – HuggingFace has high-performance solutions, but they don’t work with AMD. |
| MiniPC AI Max+ 395 128 GiB | Models with MoE for chats, autocompletion, text analysis (llama.cpp). RAM allocation: 32 GiB for applications and OS, 96 GiB for models. |
| Desktop GeForce RTX 4090 24 GiB | Models without MoE (LM Studio), 2D/3D generation (ComfyUI, Automatic1111, custom projects), speech recognition (vibe, Scriberr with diarization). |
I also plan to install and configure Open WebUI to unite all of this together, but I haven’t gotten around to it yet.
It’s important to note that AMD has issues with ROCm support on Linux. It’s only available in Ubuntu 20.24 and, judging by the reviews, it’s not working properly. I hope AMD will finally bring a stable alternative to Nvidia’s CUDA monopoly to a stable state. In the meantime, the Vulkan backend implementation is currently the most stable.
I’ve also experimented with additional services, but I rarely use them right now:
- n8n – a pioneer, so to speak, a convenient tool for organizing processes.
- RAGFlow – RAG, working with documents and the knowledge base.
- OpenHands – a VSCode-based webIDE with an agent.
- Ollama – I don’t understand why it’s so popular, but I tried using it.
A couple of examples for llama.cpp
And here’s an example of running llama.cpp as an OpenAI compatible server, if anyone’s interested.
GPT-OSS-120b
#!/usr/bin/env bash
MODEL=gpt-oss-120b-MXFP4-00001-of-00002.gguf
llama-server --host 0.0.0.0 --port 1234 \
-c 0 \
--batch-size 2048 --ubatch-size 2048 \
--temp 1 --top-p 1 --top-k 0 \
--flash-attn on --no-warmup --jinja \
--alias "gpt-oss" -m ${MODEL}Qwen3-Coder-30B-A3B-Instruct
#!/usr/bin/env bash
MODEL=Qwen3-Coder-30B-A3B-Instruct-Q8_0.gguf
llama-server --host 0.0.0.0 --port 1234 \
-c 65536 \
--batch-size 1024 --ubatch-size 256 \
--n-predict 2048 \
--temp 0.7 --top-p 0.8 --top-k 20 \
--repeat-penalty 1.05 \
-ctk q8_0 -ctv q8_0 \
--flash-attn on --no-warmup --jinja \
--alias "qwen-coder" -m ${MODEL}Is it worth it?
Let me say right away that I started experimenting with generative models back in 2022. That’s when the need for hardware that could run all this locally arose. Cloud services weren’t as widespread as they are now. The total budget for all this was a GeForce RTX 4090 graphics card (2023) and a MiniPC AMD Ryzen™ AI Max+ 395 (2025).
Was it worth it? Considering how much time was spent experimenting with LLM/LDM, it’s more likely yes than no. I suspect subscriptions, token purchases, and paid accounts would have eaten up more money over three years. Besides, this hardware is and will be used for other purposes, not just AI.
And looking at the bigger picture, I’m sure prices for public services will increase in the future. Currently, many AI services are essentially unprofitable, and this race against price gouging will end sooner or later. Investments will need to be recouped, and the ones being “cheated” will be regular users and corporate clients, who will no longer be able to function properly without their familiar tools.
Conclusion
Using local AI models ultimately depends on your immediate needs and interests. In my case, it was justified–at first, I was simply interested and needed it for my projects, then for my main job.
If everything is limited to work-related tasks, and on top of that, it’s free and paid for by the employer, then it’s clearly not worth it.