Running a dense 33B agent model on one 24 GB GPU
- Authors

- Name
- Nino
- Occupation
- Senior Tech Editor
Deploying a dense LLM on consumer-grade hardware presents unique engineering challenges, especially when working with models like Nanbeige4.3-33B, the Apache-2.0 agent coding model released by the BOSS Zhipin team. Unlike Mixture of Experts (MoE) architectures where only a fraction of parameters activate per token, dense models require every single parameter to participate in every forward pass. This article details our hands-on deployment using llama.cpp on a single NVIDIA RTX 4090, addressing critical bottlenecks such as VRAM bandwidth limits, the offloading trap, KV cache scaling, and the infamous empty reply bug caused by reasoning blocks.
Understanding the Dense Model Constraint
When evaluating models that fit within a 24 GB VRAM budget, many developers assume standard quantization rules apply universally. For MoE models, a 35 billion parameter count might only load 3 billion active parameters per token, making offloading or aggressive quantization more forgiving. Nanbeige4.3-33B, however, is fully dense.
Every token generated forces the GPU to stream the entire model file out of its onboard VRAM. Your generation speed is strictly bound by VRAM memory bandwidth. If you park even a fraction of the weights in slower system RAM, your performance collapses. Furthermore, using an API aggregator like n1n.ai can often bypass local hardware limitations, but for local inference and self-hosted agents, hardware tuning remains paramount.
The Offloading Trap
When VRAM capacity is tight, the instinctive reaction is to offload layers to the CPU. With a dense model, this is disastrous.
During our tests on the RTX 4090 using bartowski's 4-bit GGUF file (totaling roughly 20.8 GB), we managed to stay under the 16 GB usage mark by offloading 16 out of the 52 total layers to the CPU. While the semantic correctness of the outputs remained intact, generation speed plummeted to an unusable 1.6 tokens per second.
To achieve acceptable speeds without CPU bottlenecks, you must select a quantization level that fits entirely within your VRAM budget.
Quantization Performance Comparison
| Quantization File | VRAM Footprint (RTX 4090) | Speed (RTX 4090) | Speed (RTX 2000 Ada 16GB) | Output Quality Notes |
|---|---|---|---|---|
| 4-bit (Q4_K_M) | ~20.8 GB | 42 - 44 tps | Out of VRAM (requires offload) | Excellent code and reasoning |
| 3-bit (IQ3_XXS) | ~14,730 MiB | 56.5 tps | 13.6 - 14.4 tps | Passed all checks, stable code |
| 2-bit | < 12 GB | Untracked | Untracked | Hallucinated basic math rules |
Switching to the 3-bit file (IQ3_XXS) allowed the entire model to reside in VRAM, jumping performance to 56.5 tokens per second on the RTX 4090 and maintaining a stable 13.6 to 14.4 tokens per second on a restrictive 16 GB RTX 2000 Ada running at 70 watts.
Handling Long Context and KV Cache Squeezing
Context window scaling is vital for agentic workflows that parse large repositories. On the RTX 4090, we successfully tested a 64K-token prompt. The model accurately retrieved a hidden secret word planted at token index 61,428.
Achieving a 64K context window requires managing the KV cache size, which holds the working notes for the prompt:
- 16-bit Cache: Supports up to 16K context.
- 8-bit Cache: Supports up to 32K context.
- 4-bit Cache: Supports up to 64K context, leaving less than 1 GB of headroom on a 24 GB card.
As prompt length scales to 64K tokens, generation speed drops to roughly 16 tokens per second because each new token must attend to over 61,000 historical tokens in memory. When building production environments or scaling multiple concurrent agent tasks, offloading heavy prompt processing to scalable endpoints via n1n.ai ensures zero degradation in response latency.
Fixing the Empty Reply Issue in Thinking Mode
By default, advanced agent models utilize a "thinking mode" where internal reasoning tokens are generated before the final output. When running Nanbeige4.3-33B via llama.cpp, we encountered a recurring issue: replies came back with an empty content field, while the entire response was nested inside reasoning_content.
This occurs because the model's chat template concludes the prompt by opening a thinking block:
<|im_start|>assistant
<think>
If the client or server configuration fails to parse this block correctly, the output gets trapped.
Implementation Fixes
- Server-Side Flag: Pass the following configuration to disable native thinking blocks or adjust template parsing:
--chat-template-kwargs '{"enable_thinking":false} - Client-Side Fallback: Program your SDK wrapper to check for empty content fields and fallback automatically to the reasoning payload:
response = client.chat.completions.create(...) message = response.choices[0].message final_output = message.content if message.content else message.reasoning_content print(final_output)
For enterprise teams seeking reliable API orchestration without managing raw model flags and compilation bottlenecks, exploring managed alternatives on n1n.ai provides immediate production readiness.
Get a free API key at n1n.ai