花 200 英镑把一块数据中心 GPU 塞进了我的游戏 PC
2026-05-30
Oscar Molnar
13 分钟阅读(2710 字)
#
家庭实验室
#
GPU
#
NixOS
#
本地大语言模型
#
硬件
#
调试
我原本已经有一块 RTX 4080。16GB 的显存。打游戏够用,但跑我想在本地运行的模型就不够了。在 GPU 领域,下一步要么花大价钱买一块显存更大的显卡,要么另寻他路。
我找到了另一条路。
我买了一块连标准 PCIe 接口都没有的数据中心 GPU,用转接卡把它塞进了我的游戏 PC。现在,我拥有两块 GPU 共 32GB 显存,能以每秒 32 个模型 token 的速度运行一个 270 亿参数的模型。整件事只花了我 200 英镑。
这块 GPU
这是一块 Tesla V100 SXM2 16GB。它专为 NVIDIA 的 DGX 服务器和超大规模服务器机架设计。SXM2 形态意味着它没有 PCIe 插槽,没有显示输出接口,也没有普通的电源接口。它插在服务器机架内一块专用板上,通过 NVLink 通信。
你不能直接把它插到主板上。没有辅助手段不行。
但关键在于:这是一块 Volta 架构的 GPU,拥有 16GB HBM2 内存、5120 个 CUDA 核心,我在 eBay 上花大约 150 英镑淘到的。它的算力依然真实可用,显存也是实打实的。而它的内存带宽才真正令人惊讶。
HBM2 是不同级别的内存。V100 拥有 4096 位内存总线,提供 900 GB/s 的带宽。做个对比,我那块搭载 fancy GDDR6X 显存的 RTX 4080 只能达到 736 GB/s。这块 2017 年的 V100,内存带宽比 2022 年发布的 GPU 还要高出 22%。
而且输掉的不仅仅是 NVIDIA 的消费级显卡。Apple 的 M3 Max 是 400 GB/s,M4 Max 是 546 GB/s。全新的 M5 Max,买一台搭载它的笔记本要花掉你超过 3000 英镑,带宽也只有 614 GB/s。一块 2017 年的 GPU 击败了市面上所有 Mac。
与我的 4080 最接近的 AMD 竞品是 RX 7900 XTX,它在 24GB GDDR6 显存上能达到 960 GB/s。从技术上讲,这略胜 V100,但 7900 XTX 售价 700 英镑以上,而且 ROCm 对 LLM 推理的支持与 CUDA 相比仍然粗糙。V100 以不到四分之一的价格提供了该带宽的 94%,并且它能直接与 llama.cpp 配合使用。
唯一能轻松胜过它的消费级 GPU 是 RTX 5090,带宽达到 1792 GB/s,而那张卡售价超过 2000 英镑。对于大语言模型推理而言,内存带宽是决定每秒 token 数的瓶颈,这一点比几乎其他任何因素都更重要。
唯一的问题在于接口。
转接卡#
结果发现,有人制造了 SXM2 转 PCIe 的转接卡。它并非英伟达生产,也不受任何官方支持。它只是一块裸露的 PCB,一侧是 SXM2 插槽,另一侧是 PCIe 金手指接口。我花了大约 50 英镑买下它。其中一半可能只是铜的成本。
所以总共花了大约 200 英镑,我就得到了一块 16GB 显存的 GPU,可以插在我的主板上,与我的 RTX 4080 并肩工作。总显存达到 32GB。而一块 32GB 显存的单张 RTX 5090 售价超过 2000 英镑。我并不是说体验相同,我只是说显存容量一样。
地狱级风扇#
在我能用 V100 做任何有用的事情之前,必须先解决风扇问题。
V100 SXM2 原本设计安装在配备工业级散热的 2U 服务器内部。转接卡上的风扇毫不含蓄,绝不安静,绝不是你想放在自己睡觉的房间里那种东西。
我用 Apple Watch 测量了一下:
82 分贝。这介于垃圾处理器和割草机之间,远远超过“电脑很吵”的程度,进入了“我在自己家里是不是该戴耳塞”的范畴。
最糟糕的是:你无法控制它。我试过 nvidia-smi,试过在 Linux 上扫描它,甚至在 Windows 上试过 Afterburner(稍后会详述,这套配置在 Windows 上几乎无法正常工作)。全都没用。这块转接卡上的风扇设计初衷就不是被控制的。它被设计成永远以 100% 转速运行,待在没人需要听到它的服务器机架里。
这是我试图弄清风扇引脚定义的场景。我猜测它可能是一个怪异接口上的标准机箱风扇引脚定义,于是我把两根跳线插到 VCC 和接地端,然后用一块 9V 电池去碰触它们。风扇转了起来。而且比它通常得到的 12V 供电时安静得多:
这证实了引脚定义,也让我看到了驯服这个风扇的希望。
让风扇听从理智#
9V电池测试告诉我,引脚排列属于标准机箱风扇范畴,只是接口比较特殊。接下来的问题是,如果我把测速线和PWM引脚接到主板上,风扇是否真的会对PWM控制做出响应。
于是我把几根杜邦线塞进接口,另一端插到一个空闲的风扇插针上(请调高音量):
成功了。主板能读取转速,风扇也对PWM有响应。我把它保持在10%转速。即使满载运行,温度也从未超过50摄氏度,而且我几乎听不到它的声音。
现在我只缺一根像样的线缆,而不是靠运气固定的杜邦线。
转接卡上的风扇接口是一个四针的小型JST PH2.0插头。主板风扇插针采用标准的0.1英寸(2.54mm)间距。GPU风扇使用的是2.0mm间距的JST PH接口。针脚更密集,插头也更小。
解决方案是一根2.54mm公头转PH2.0母头的杜邦线。PH2.0母头端插入风扇的测速线和PWM针脚,2.54mm公头端则插入主板上一个空闲的风扇插针:
噪音从82分贝的耳朵损伤级别,降到了我实际能忍受的程度。
廉价翻倍显存#
风扇问题解决后,V100就顺理成章地插在了我的4080旁边:
- RTX 4080:16GB显存,Ada架构
- Tesla V100:16GB显存,Volta架构
- 总计:两块GPU共32GB显存
llama.cpp可以通过张量切分将模型分配到两块GPU上。它通过PCIe总线对层进行流水线处理,让4080处理部分层,V100处理其余部分。这不如单块32GB显存的GPU快,但能用,而且成本大约只有32GB显存GPU的10%。值得一提的是,我见过V100的最高功耗大约在150W左右。这不算低,但对于运行本地大语言模型推理的GPU来说,也不算离谱。
等等,还能更大#
V100还有32GB显存的版本。价格比我买的贵一倍以上,但单卡32GB HBM2显存,我们谈的仍然只是几百英镑。在今天的市场上,买两块这样的卡,就能获得64GB显存,成本大约只有RTX 5090价格的20%。
你还可以将它们组成集群。SXM2 格式原生支持 NVLink,这意味着如果你正在搭建一个合适的多 GPU 系统,这些显卡可以以非常高的带宽相互通信。即使通过 PCIe 适配器,张量拆分性能也相当不错。
软件方面#
这部分出奇地顺利,这要归功于 NixOS。V100 是一款 Volta 芯片。英伟达从驱动程序分支 560 开始停止了对 Volta 的支持。最后一个同时支持我的 RTX 4080(Ada)和 V100(Volta)的驱动程序是分支 550.x,在 NixOS 上对应的是 nvidiaPackages.legacy_535。
那个驱动程序只支持最高 CUDA 12.2。当前的 nixpkgs 最低只提供 CUDA 12.6。所以我不得不从 nixpkgs 24.05 中提取 CUDA 12.2。
另外,该驱动程序需要内核 6.6。较新的内核不受旧版驱动程序支持。
还有一个奇怪的地方:尽管这是一个无头推理服务器,但必须设置 services.xserver.enable = true。没有它,英伟达内核模块就无法加载。
NixOS 让这部分工作变得非常简单。以下是让驱动程序和内核正确运行的关键配置:
boot.kernelPackages = pkgs.linuxPackages_6_6;
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_535;
services.xserver.enable = true;
services.xserver.videoDrivers = [ "nvidia" ];
以及从较旧的 nixpkgs 加载 CUDA 12.2 的方法,因为当前的 nixpkgs 只提供 12.6 及以上版本:
nixpkgs.overlays = [
(final: prev: {
cudaPackages_12_2 = nixpkgs-cuda.legacyPackages.${prev.system}.cudaPackages_12_2;
})
];
重要的是:它运行起来了。两块 GPU 都能识别,CUDA 功能正常,NixOS 优雅地处理了整个过程。如果你想复现这个配置,完整的机器定义在我的 dotfiles 仓库的这个提交中,包括 llama.cpp 服务定义和锁定到正确版本的自定义构建。
运行模型#
我正在运行量化到 Q5_K_M 的 Qwen3.6-27B-MTP 模型,大小约为 19GB。使用两块 GPU,整个模型可以放入显存,并且还有上下文空间:
| 设置项 | 值 |
|---|---|
| 模型 | Qwen3.6-27B-MTP Q5_K_M(19GB) |
| 上下文大小 | 128k 模型 token |
| GPU 层数 | 99(全部卸载到 GPU) |
| 张量拆分 | -ts 1.0,1.0(在两块 GPU 之间均匀分配) |
性能表现:
| 指标 | 值 |
|---|---|
| 推理速度 | 约 32 tok/s |
| 提示词处理 | 约 133-160 tok/s |
每秒 32 个 token 的速度对于交互式使用来说足够快了。考虑到网络延迟,这比大多数云端 API 端点都要快。而且这还是通过 PCIe 连接的两个不同 GPU 架构之间进行张量拆分的结果。
这个模型实际上很不错#
我想把话说清楚。这并非“对于本地模型而言表现不错”,也不是“降低预期后尚可接受”。Qwen3.6-27B 在 Artificial Analysis 的智能体指数上与 Claude Sonnet 4.6 打成平手,在 MMMU-Pro 和 Terminal-Bench 2.0 上甚至超越了 Sonnet 4.6。一个运行在二手硬件上的 270 亿参数模型,确实能与 Anthropic 最新的云端模型一较高下。
没错,Sonnet 4.6 在 GPQA 和 SWE-Bench Verified 上略胜一筹。这也在情理之中,毕竟它是一个庞大的专有模型。同样,如果你追求极致性能,还有 Opus 4.8 可选。但重度使用 20 分钟的费用,比我买这块 GPU 和整套转接设备的总花费还高。然而,差距已经小得惊人。我们已经到了这样一个节点:你在卧室里跑起来的模型,已经能和那些按 token 收费的模型相提并论了。
多 Token 预测#
模型名称中的 MTP 代表多 Token 预测。常规的大语言模型推理一次只预测一个 token:预测一个 token,接受它,再预测下一个 token,如此循环。MTP 改变了这一点,它让模型一次性预测多个未来 token,然后验证哪些是正确的。被接受的 token 基本算是免费获得的,错误的预测则回退到常规路径。
结果是生成速度大约提升 1.5 到 2 倍,且精度毫无损失。在我的设备上,这意味着当 MTP 发挥最佳性能时,推理速度能从大约 32 tok/s 提升到 50-60 tok/s,尤其是在处理代码这类可预测的输出时。
问题在于 llama.cpp 对 MTP 的支持还很新。nixpkgs 中的版本不支持 Qwen3.6 的 MTP 架构,所以我不得不从添加了该支持的特定提交版本开始,从源码构建 llama.cpp。在 NixOS 上,这很简单。我创建了一个指向正确提交的自定义派生包,整个过程是可复现的。当我想更新模型或更改 llama.cpp 版本时,只需修改配置文件中的一行,运行 nixos-rebuild switch 即可。没有依赖地狱,无需手动重装,也不用担心是否针对正确的 CUDA 版本进行了构建。
视觉能力:模型如何理解图像#
Qwen3.6-27B 模型通过一个独立的多模态投影文件(mmproj)支持图像输入。这个文件大约 928MB,其功能令人着迷。
其工作原理是:一个视觉编码器(类似于 ChatGPT 和 Claude 所使用的)将图像像素转换到大语言模型的 token 嵌入向量空间。该模型并不会像人类那样“看见”图像。相反,视觉编码器将图像压缩成一系列向量,这些向量与文本 token 处于同一个数学空间中。然后,大语言模型将这些向量当作另一串 token 序列来处理。
这在实践中意味着:你可以将图像 URL 连同文本提示词一起发送给模型,模型就能描述、分析并推理它所看到的内容。整个视觉能力大约给模型增加了 1GB 的大小。仅此而已。增加一个 GB,你的本地大语言模型就能读取图像了。
在 llama.cpp 中,相关的标志参数很直接:
--mmproj /mnt/nas/llamacpp/mmproj-F16.gguf --mmproj-offload
`--mmproj-offload` 标志会将视觉编码器与模型一同加载到 GPU 上,这样即使处理图像,你依然能获得快速的推理速度。
通过 OpenCode 运行
我将这套设置与 OpenCode 配合使用,这是一个能够对接本地模型的 AI 编程助手。大语言模型服务器运行在我的台式机上,但我并不在那台机器上使用它。我通过局域网在家中任何其他机器上使用它,或者通过 Tailscale 从外部访问(不过这属于另一篇博客文章的内容了)。将 OpenCode 指向 llama.cpp 服务器,只需设置 API URL 即可。模型在本地运行,响应速度快,且没有任何数据离开我的网络。
NAS 与 USB 驱动器
所有模型都存放在我的 TrueNAS 服务器上,通过 NFS 挂载:
fileSystems."/mnt/nas" = {
device = "truenas-nfs.tymscar.com:/mnt/oasis/services";
fsType = "nfs";
options = [ "nfsvers=4" "_netdev" "auto" "nofail" ];
};
llama.cpp 服务依赖于 `mnt-nas.mount`,因此在 NAS 可用之前它不会启动。这意味着我可以存储数 TB 的模型,而无需担心本地磁盘空间。
整个操作系统运行在一个 DockCase USB-C NVMe 硬盘盒中的 Corsair MP600 MINI 固态硬盘上。无需修改内部驱动器。当我想玩游戏时,拔掉这个硬盘盒,重启进入我的主 Windows 系统,就能在 4080 显卡上正常游戏。当我想做大语言模型相关工作时,插回硬盘盒,重启进入 NixOS,两块 GPU 就都可用了。
这不如双系统启动菜单那么优雅,但它简单且有效。没有 GRUB,没有引导加载器冲突,没有分区管理。只是一个物理开关。
唯一烦人的一件事
在热重启(操作系统重启但主板保持通电)后,V100 有时会从 lspci 和 nvidia-smi 中消失。这似乎是 PCIe 插槽的 ACPI 枚举问题。冷重启(物理断电,等待几秒,再重新通电)总能恢复它。
当 V100 缺失时,llama.cpp 无法启动,因为它无法将模型放入单块 16GB GPU 中。服务会陷入崩溃循环,直到 GPU 恢复。实际上这问题不大,因为我通常在重启时就在旁边,但值得了解。这让我想起臭名昭著的 AMD GPU 重置 bug——将 AMD GPU 直通给虚拟机然后关闭后,GPU 会进入一种只有完全切断宿主机电源再重启才能修复的状态。
我最终得到了什么#
花 200 英镑,我得到了:
- 一块 16GB 数据中心 GPU,与我的游戏 GPU 一起运行
- 总共 32GB 显存,用于本地大语言模型推理
- 在 27B 参数模型上达到每秒 32 个 token
- 128k token 上下文窗口
- 支持图像输入的视觉功能
- 一个完全本地运行的模型,无需云端,无按 token 计费
唯一的实际代价是噪音,而我用价值 2 英镑的跳线和一点接头探索解决了这个问题。V100 并非最快的推理 GPU,且跨两种不同架构的张量拆分不如单块 GPU 那样干净。但就这个价格而言,它的性价比高得离谱。
如果你想在本地运行像样的模型,可以看看二手服务器 GPU 市场。你甚至不需要已有 GPU。我碰巧在游戏 PC 里有一块 4080,但单块 V100 放在廉价服务器机箱里就能给你 16GB 显存和一个完全可用的本地大语言模型,花费极少。V100 SXM2 并非唯一选择。P40 以类似价格提供 24GB 显存,不过速度更慢且没有 Tensor Core。V100 32GB 版本价格更高,但仍比任何拥有同等显存的消费级 GPU 便宜。
只是要做好应对风扇的准备。
I Put a Datacenter GPU in My Gaming PC for £200
2026-05-30
Oscar Molnar
13 min read (2710 words)
#
homelab
#
gpu
#
nixos
#
local-llm
#
hardware
#
debugging
I already had an RTX 4080. 16GB of VRAM. Good enough for gaming, not good enough for the models I wanted to run locally. The next step up in GPU land is either spend a fortune on a card with more VRAM, or find another way.
I found another way.
I bought a datacenter GPU that doesn’t even have a normal PCIe connector, stuck it in my gaming PC with an adapter, and now I have 32GB of VRAM across two GPUs running a 27 billion parameter model at 32 tokens per second. The whole thing cost me £200.
The GPU#
This is a Tesla V100 SXM2 16GB. It was designed for NVIDIA’s DGX servers and hyperscaler racks. The SXM2 form factor means it does not have a PCIe slot. It does not have display outputs. It does not have a normal power connector. It sits on a proprietary board inside a server rack and communicates over NVLink.
You cannot plug this into a motherboard. Not without help.
But here is the thing: this is a Volta GPU with 16GB of HBM2 memory, 5120 CUDA cores, and I picked it up for about £150 on eBay. The compute is still real. The VRAM is still real. And the memory bandwidth is where it gets genuinely surprising.
HBM2 is a different class of memory. The V100 has a 4096-bit memory bus delivering 900 GB/s of bandwidth. To put that in perspective, my RTX 4080 with its fancy GDDR6X manages 736 GB/s. The V100 from 2017 has 22% more memory bandwidth than a GPU that launched in 2022.
And it is not just NVIDIA’s consumer cards that lose. Apple’s M3 Max does 400 GB/s. The M4 Max does 546 GB/s. The brand new M5 Max, which will set you back over £3,000 for a laptop, manages 614 GB/s. A GPU from 2017 beats every Mac on the market.
The closest AMD competition to my 4080 is the RX 7900 XTX, which does 960 GB/s on its 24GB of GDDR6. Technically that edges out the V100, but the 7900 XTX costs £700+ and ROCm support for LLM inference is still rough compared to CUDA. The V100 gives you 94% of that bandwidth for less than a quarter of the price, and it just works with llama.cpp.
The only consumer GPU that comfortably beats it is the RTX 5090 at 1,792 GB/s, and that card costs over £2,000. For LLM inference, where memory bandwidth is the bottleneck that determines your tokens per second, this matters more than almost anything else.
The only problem is the connector.
The adapter#
Turns out, someone makes an SXM2-to-PCIe adapter. It is not made by NVIDIA. It is not officially supported by anyone. It is a bare PCB with the SXM2 socket on one side and a PCIe edge connector on the other. I paid about £50 for it. Half of that might just be the copper.
So for about £200 total, I had a 16GB VRAM GPU that could slot into my motherboard alongside my RTX 4080. That is 32GB of total VRAM. A single RTX 5090 with 32GB costs over £2,000. I am not saying this is the same experience. I am saying the VRAM is the same.
The fan from hell#
Before I could do anything useful with the V100, I had to deal with the fan.
The V100 SXM2 was designed to live inside a 2U server with industrial cooling. The fan on the adapter is not subtle. It is not quiet. It is not something you want in a room you also sleep in.
I measured it with my Apple Watch:
82 decibels. That is somewhere between a garbage disposal and a lawnmower, well past “loud PC” and into “should I be wearing earplugs in my own house” territory.
And the worst part: you cannot control it. I tried nvidia-smi, I tried scanning for it on Linux, I even tried Afterburner on Windows (more on that later, the whole setup barely works on Windows). Nothing. The fan on this adapter is not designed to be controlled. It is designed to run at 100%, forever, inside a server rack where nobody has to hear it.
Here is me trying to figure out the fan pinout. I guessed it might be a standard case fan pinout on a weird connector, so I jammed two jumper wires into VCC and ground and prodded a 9V battery against them. It spun. And it was so much quieter than the 12V it normally gets:
That confirmed the pinout and gave me hope that the fan could actually be tamed.
Making the fan listen to reason#
The 9V battery test told me the pinout was standard case fan territory, just with a weird connector. The next question was whether the fan would actually respond to PWM control if I wired the tachometer and PWM pins to my motherboard.
So I shoved some jumper wires into the connector and jammed the other ends into a spare fan header (turn your volume up):
It works. The motherboard can read the RPM and the fan responds to PWM. I keep it at 10%. It never goes above 50C even at full load, and I cannot really hear it.
Now I just needed a proper cable instead of jumper wires held in by hope.
The fan connector on the adapter is a small JST PH2.0 plug with four pins. Motherboard fan headers use a standard 0.1 inch (2.54mm) pitch. The GPU fan uses a 2.0mm JST PH connector. The pins are closer together and the plug is smaller.
The solution was a 2.54mm male to PH2.0 female jumper cable. The female PH2.0 end plugs into the fan’s tachometer and PWM pins, and the male 2.54mm end goes into a spare fan header on the motherboard:
That went from 82dB ear damage to something I can actually live with.
Doubling VRAM for cheap#
With the fan situation handled, the V100 slotted right in alongside my 4080:
- RTX 4080: 16GB VRAM, Ada architecture
- Tesla V100: 16GB VRAM, Volta architecture
- Total: 32GB VRAM across two GPUs
llama.cpp can split the model across both GPUs using tensor splitting. It pipelines the layers across the PCIe bus so the 4080 handles some layers and the V100 handles the rest. It is not as fast as having a single GPU with 32GB, but it works, and it cost me roughly 10% of what a 32GB GPU would cost. For what it is worth, the most I have ever seen the V100 pull is around 150W. That is not nothing, but it is not out of this world for a GPU running local LLM inference.
But wait, you can go bigger#
The V100 also comes in a 32GB variant. It costs more than double what I paid, but we are still talking about a few hundred pounds for 32GB of HBM2 memory on a single card. Two of those would give you 64GB of VRAM for roughly 20% of what an RTX 5090 costs in today’s market.
You can also cluster them. The SXM2 format supports NVLink natively, which means if you are building a proper multi-GPU setup, these cards can talk to each other at very high bandwidth. Even through the PCIe adapter, the tensor split performance is solid.
The software side#
This part was surprisingly smooth thanks to NixOS. The V100 is a Volta chip. NVIDIA dropped Volta support starting with driver branch 560. The last driver that supports both my RTX 4080 (Ada) and the V100 (Volta) is branch 550.x, which maps to nvidiaPackages.legacy_535 on NixOS.
That driver only supports CUDA up to 12.2. Current nixpkgs ships CUDA 12.6 minimum. So I had to pull CUDA 12.2 from nixpkgs 24.05.
Also, the driver requires kernel 6.6. Newer kernels are not supported with the legacy driver.
And here is a weird one: even though this is a headless inference server, services.xserver.enable = true is required. Without it, the NVIDIA kernel modules do not load.
NixOS made most of this straightforward. Here is the key configuration for getting the driver and kernel right:
boot.kernelPackages = pkgs.linuxPackages_6_6;
hardware.nvidia.package = config.boot.kernelPackages.nvidiaPackages.legacy_535;
services.xserver.enable = true;
services.xserver.videoDrivers = [ "nvidia" ];
And for loading CUDA 12.2 from an older nixpkgs since the current one only ships 12.6+:
nixpkgs.overlays = [
(final: prev: {
cudaPackages_12_2 = nixpkgs-cuda.legacyPackages.${prev.system}.cudaPackages_12_2;
})
];
The important thing is: it works. Both GPUs show up, CUDA is functional, and NixOS handled the whole thing elegantly. If you want to replicate this, the entire machine definition is in this commit on my dotfiles repo, including the llama.cpp service definition and the custom build pinned to the right version.
Running the model#
I am running Qwen3.6-27B-MTP quantized at Q5_K_M, which comes in at about 19GB. With both GPUs, the entire model fits in VRAM with room for context:
| Setting | Value |
|---|---|
| Model | Qwen3.6-27B-MTP Q5_K_M (19GB) |
| Context size | 128k tokens |
| GPU layers | 99 (all offloaded) |
| Tensor split | -ts 1.0,1.0 (even across both GPUs) |
And the performance:
| Metric | Value |
|---|---|
| Inference speed | ~32 tok/s |
| Prompt processing | ~133-160 tok/s |
32 tokens per second is fast enough for interactive use. It is faster than most cloud API endpoints when you factor in network latency. And this is with tensor splitting across two different GPU architectures connected by PCIe.
This model is actually good#
I want to be clear about something. This is not “good for a local model.” This is not “acceptable if you lower your expectations.” Qwen3.6-27B ties with Claude Sonnet 4.6 on Artificial Analysis’s Agentic Index. It beats Sonnet 4.6 on MMMU-Pro and Terminal-Bench 2.0. A 27 billion parameter model running on secondhand hardware is genuinely competitive with the latest cloud models from Anthropic.
Yes, Sonnet 4.6 edges it out on GPQA and SWE-Bench Verified. It should, it is a massive proprietary model. And yes, if you want the absolute best, Opus 4.8 exists. It also costs more per 20 minutes of heavy use than I paid for this entire GPU and adapter setup combined. But the gap is shockingly small. We have reached the point where the model you run in your bedroom is in the same conversation as the ones that charge you per token.
Multi-Token Prediction#
The MTP in the model name stands for Multi-Token Prediction. Normal LLM inference predicts one token at a time. Predict one token, accept it, predict the next token, repeat. MTP changes this by having the model predict several future tokens at once, then verifying which ones were correct. Accepted tokens are essentially free. Wrong predictions fall back to the normal path.
The result is roughly 1.5-2x faster generation with no accuracy loss. On my setup that means inference goes from around 32 tok/s to potentially 50-60 tok/s when MTP hits its stride, especially on predictable output like code.
The catch is that MTP support in llama.cpp is new. The version in nixpkgs does not support the Qwen3.6 MTP architecture, so I had to build llama.cpp from source at a specific commit that added support. On NixOS this is painless. I have a custom derivation pinned to the right commit, and the whole thing is reproducible. When I want to update the model or change the llama.cpp version, I change one line in my config, run nixos-rebuild switch, and I am done. No dependency hell, no reinstalling by hand, no wondering whether I built against the right CUDA version.
Vision: how the model sees images#
The Qwen3.6-27B model supports image input through a separate multimodal projector file (mmproj). This is about 928MB extra, and it is fascinating.
The way it works is that a vision encoder (similar to what ChatGPT and Claude use) takes image pixels and translates them into the LLM’s token embedding space. The model does not “see” the image the way a human does. Instead, the vision encoder compresses the image into a sequence of vectors that live in the same mathematical space as text tokens. The LLM then processes those vectors as if they were just another sequence of tokens.
What this means in practice: you send the model an image URL alongside your text prompt, and it can describe, analyze, and reason about what it sees. The entire vision capability adds about 1GB to the model size. That is it. One gigabyte and your local LLM can read images.
In llama.cpp, the flags are straightforward:
--mmproj /mnt/nas/llamacpp/mmproj-F16.gguf --mmproj-offload
The --mmproj-offload flag loads the vision encoder onto GPU alongside the model, so you still get fast inference even with images.
Running it through OpenCode#
I use this setup with OpenCode, which is an AI coding assistant that can run against local models. The LLM server runs on my desktop, but I do not use it from that machine. I use it from any other machine in my house over the network, or from outside over Tailscale (but that is a blog post for another time). Pointing OpenCode at the llama.cpp server is as simple as setting the API URL. The model runs locally, the responses are fast, and nothing leaves my network.
The NAS and the USB drive#
All the models live on my TrueNAS server, mounted via NFS:
fileSystems."/mnt/nas" = {
device = "truenas-nfs.tymscar.com:/mnt/oasis/services";
fsType = "nfs";
options = [ "nfsvers=4" "_netdev" "auto" "nofail" ];
};
The llama.cpp service depends on mnt-nas.mount, so it does not start until the NAS is available. This means I can store terabytes of models without worrying about local disk space.
The entire OS runs from a Corsair MP600 MINI in a DockCase USB-C NVMe enclosure. No internal drive modification needed. When I want to game, I unplug the drive and reboot into my main Windows install, and game normally on the 4080. When I want to do LLM stuff, I plug the drive back in, reboot into NixOS, and both GPUs are available.
This is not as elegant as a dual-boot menu, but it is simple and it works. No GRUB, no bootloader conflicts, no partition management. Just a physical switch.
The one annoying thing#
The V100 occasionally disappears from lspci and nvidia-smi after a warm reboot (where the OS restarts but the motherboard stays powered). This seems to be an ACPI enumeration issue with the PCIe slot. A cold reboot (physically power off, wait a few seconds, power back on) always restores it.
When the V100 is absent, llama.cpp fails to start because it cannot fit the model on a single 16GB GPU. The service crash-loops until the GPU comes back. This is not a big deal in practice since I am usually around when I reboot, but it is worth knowing about. It gives me the same vibes as the infamous AMD GPU reset bug, where passing through an AMD GPU to a VM and then shutting it down leaves the GPU in a state that only a full host power cycle can fix.
What I ended up with#
For £200, I got:
- A 16GB datacenter GPU running alongside my gaming GPU
- 32GB total VRAM for local LLM inference
- 32 tokens per second on a 27B parameter model
- 128k token context window
- Vision support for image input
- A model that runs completely locally, no cloud, no per-token costs
The only real cost was the noise, and I solved that with £2 worth of jumper cables and a bit of connector spelunking. The V100 is not the fastest GPU for inference, and the tensor split across two different architectures is not as clean as a single GPU. But for the price, it is absurdly good value.
If you want to run proper models locally, look at the secondhand server GPU market. You do not even need an existing GPU. I happen to have a 4080 in my gaming PC, but a single V100 in a cheap server box would give you 16GB of VRAM and a perfectly usable local LLM for very little money. The V100 SXM2 is not the only option. The P40 gives you 24GB for similar money, though it is slower and has no Tensor Cores. The V100 32GB variant costs more but still undercuts any consumer GPU with that much VRAM.
Just be ready for the fan.