Report

One box dirty, one box clean: the two-node home AI lab that keeps its numbers honest

Our two identical Strix Halo units live opposite lives: one carries the whole containerized service stack, the other serves a single model and stays otherwise empty. The split is not tidiness — the benchmark harness invalidates any run that finds a GPU neighbor on the host.

lab_single_run internal research August 21, 2026 · Funding: Self-funded internal research

The short version: this lab’s two Strix Halo boxes are commercially identical and deliberately opposite. One carries the entire containerized service stack and is allowed to be messy. The other serves one model through one runtime and is otherwise kept empty. The split is not housekeeping — it is a precondition our benchmark harness physically checks. The Habr original, in Russian, tells the operational half of the story; this page adds the half that only makes sense next to our measurement rules.

Both machines are Beelink GTR9 Pro units: Ryzen AI Max+ 395, 128 GB of unified memory, an integrated GPU that shares that memory with everything else on the host. The last property decides the architecture. On a workstation with a discrete card, a stray background service steals some CPU and leaves your VRAM alone. On unified memory there is no “alone”: every neighbor lives on the same bandwidth your inference decodes through.

What runs on which box?

The service node — the dirty one — carries the platform. Dify with its API, worker and web pieces. RAGFlow with the MySQL, Elasticsearch and MinIO retinue it brings along. A Milvus vector store. Small llama.cpp servers doing embeddings and reranking on the integrated GPU, because those calls are short, frequent and tolerant enough to share a busy host. Prometheus, Grafana and Loki watching everything; Traefik, Authelia, n8n and Open WebUI at the edge. The count stood at 34 containers when the Habr article was written.

What the dirty box does not do is heavy generation. Large-model answers arrive over the LAN from other hardware; this box is a platform, not an engine.

The clean node runs a llama.cpp server on the Vulkan backend with one Qwen3.6 MoE model loaded, and that is the complete inventory. No databases, no proxy, no dashboards. Between measurements it sits close to idle, on purpose.

Why does a measurement need an empty host?

Because our harness refuses to take anyone’s word for it, including ours. Every benchmark run starts by recording a host inventory: the full list of containers alive on the machine at that moment. When the run ends, the inventory is taken again. Both snapshots go into the run manifest as evidence, and if either one contains a GPU-capable neighbor — anything that looks like another inference server or GPU runtime — the cell is invalidated outright. A neighbor that appears mid-run kills the measurement as surely as one that was there at the start.

This is the same posture as the rest of our benchmarking method: a condition that would invalidate a number must be machine-checked, not promised in prose. And once “nothing else runs here” is a hard gate, the cheapest way to pass it every day is a second machine where everything else runs. The dirty box exists so the clean box can stay empty. That sentence is the whole architecture.

What operating the dirty box taught us

Pin the stack and write the pins down. On this GPU family the working combination of kernel, firmware and driver versions is exactly that — a combination. Upgrading one member because it looked harmless has produced regressions before. A stack that works is recorded as a set and changed as a set.

Stock monitoring fails by omission. The vendor GPU tool answers N/A for key sensors on this silicon, so temperature and power are read from the kernel’s hwmon files by a small collector feeding node-exporter. Readers of our DGX Spark monitoring report will recognize the disease: different vendor, same green-and-empty dashboard, same boring cure.

GPU offload can vanish without an error. A misnamed Vulkan ICD manifest silently disables the GPU; generation continues on the CPU, slower and quieter. The only confirmation worth trusting is the runtime’s own log line reporting every model layer offloaded — which is why the harness also treats a detected CPU fallback as an invalidation, not a footnote.

One more habit that earned its keep: restart counters as the primary health signal. Nearly every container on the dirty box has never restarted; the one that keeps a nonzero counter is named in the Habr piece and watched. A counter that only moves when something actually died says more than a wall of green panels.

Scope

This page describes two specific units, one container stack and one runtime choice, as they stood at the time of the Habr write-up. It is an operational account, not a comparative study: we do not claim this split is optimal, only that it is what lets every published number carry proof the host was quiet. The configurations, the memory tuning and the measured figures live in the primary source on Habr, in Russian.

Cite this report

AGmind Systems Lab (2026-08-21). One box dirty, one box clean: the two-node home AI lab that keeps its numbers honest. Evidence level: lab_single_run. https://agmind.ai/reports/two-node-home-ai-lab/
← Reports