# Nanbeige4.3-33B: a teacher first, and a cache you pay for

> Satyajit Ghana — Head of Engineering @ Inkers Technology
> canonical: https://ai.thesatyajit.com/articles/nanbeige-4-3-33b
> date: 2026-10-26
> tags: agents, agentic-coding, distillation, kv-cache, on-device, benchmarks, small-models

On 25 October the Nanbeige LLM Lab (Boss Zhipin, Kanzhun) [posted](https://x.com/nanbeige/status/2114328933181333798)
Nanbeige4.3-33B: "SOTA agentic performance among open models at ~30B parameters", reached by "building a
powerful teacher first". The 33B is meant to teach smaller models, "starting with Nanbeige4.3-3B". The
post has no thread. Its replies add community quantizations, a lot of requests for a mixture-of-experts
version, and a few people asking whether anyone has verified the numbers. The two links in the post are
the model repository and its Base. There is no technical report, which the [4.2-3B](/articles/nanbeige-4-2-3b)
had.

So this article does what a model card allows. I read the safetensors headers by range request, the
config, the tokenizer and the chat template, and I ran the template and tokenizer on a CPU. The
weights themselves I did not download, and I did not run the model. Every number below is tagged
**measured** (I computed it from a file), **reported** (the publisher or a community poster said it) or
**reasoned** (my arithmetic on the other two).

<ModelCard repo="Nanbeige/Nanbeige4.3-33B" />

<ModelCard repo="Nanbeige/Nanbeige4.3-33B-Base" />

## What is in the files

The architecture is `LlamaForCausalLM`, the plainest thing a 2026 model can be. The header sum is
**33,118,977,024** parameters, all bfloat16, in 14 shards of about 66.2 GB (**measured**; the 471 tensors are
52 layers times 9, plus the embedding, the head and the final norm). Rebuilding that number from the
config closes it to the digit (**measured**):

| piece | count |
|---|---|
| attention per layer: q 7,168², o 7,168², k and v 1,024 × 7,168 each | 117,440,512 |
| feed-forward per layer: three matrices of 7,168 × 22,016 | 473,432,064 |
| 52 layers with norms | 30,726,119,424 |
| input embedding, 166,912 × 7,168 | 1,196,425,216 |
| output head, untied, same shape | 1,196,425,216 |

Two things follow. The feed-forward layer holds 80% of each layer's weights, the usual dense profile.
And "33B" counts both embedding tables. Without them it is 30.7B, which is what "~30B class" means in the
post (**reasoned**). The Hugging Face tags show a text model, and the tensor list agrees: no vision tower. One
replier said so within the hour.

Nothing here loops. The 4.2-3B was a two-pass looped transformer, and its depth came from running the
same layers twice (see [the looped-transformer explainer](/architectures/looped-transformer)). The 33B has
52 distinct layers and a `model_type` of `llama`, so a loop would need custom code the repository does
not ship. Whatever carried over from 4.2, it is not the loop.

### The cache is the bill

Attention uses 56 query heads over 8 key-value heads, so seven queries share each cached head. That is
grouped-query attention, 7:1. The cache per token is

$$2 \times 52 \times 8 \times 128 = 106{,}496 \text{ values}$$

which is **212,992 bytes, 208 KiB, at f16** (**reasoned** from the config). At the 128K positions the
Base config allows that is 26 GiB. At the 512K the chat model's config allows it is 104 GiB. Full
multi-head attention would be seven times worse.

Every one of the 52 layers keeps a cache; no layer is sliding-window or linear. [Qwen3.8-27B](/articles/qwen3-8-27b-on-12gb),
the card's main comparator, is a hybrid that caches only 16 of its layers, at 64 KiB a token by that article's
arithmetic (**reasoned**). So Nanbeige's cache is 3.25 times Qwen's per token. [Muse Glimmer](/articles/muse-glimmer)
and [Gemma 4](/articles/gemma-4) are both built the other way, spending architecture to shrink the cache.
The 33B spends nothing on it. That is a legitimate choice, and it is what the "cost-efficient inference"
line has to be weighed against.

This widget does the arithmetic for any file, cache type, context and chip. The file sizes are the real
ones from the Hugging Face listings; the chip bandwidths are spec-sheet numbers I typed in, not measured.

<MemoryLedger />

Three readings of it (all **reasoned**). A Q4_K_M file is 20.79 GB. On a 24 GB card that leaves about 3.2 GB,
which is roughly 15,000 tokens of f16 cache before the runtime takes its share. IQ4_XS is 18.64 GB and
leaves 5.4 GB, about 25,000 tokens, or about 47,000 with a `q8_0` cache. And at 128K, a Q4_K_M file with an f16
cache is 48.7 GB of memory, with `q4_0` cache 28.6 GB.

## The tokenizer is Nanbeige's own, unchanged

The `tokenizer.model` in the 33B has the same SHA-256 as the one in Nanbeige4.2-3B and in Nanbeige4-3B-Base
(`fb41d047…`), and the chat model's `tokenizer.json` is byte-identical to the 4.2-3B's (**measured**). It is a
SentencePiece BPE with 166,100 pieces plus seven chat tokens, padded to a 166,912-row embedding. So the whole
family shares one vocabulary, and the 3B student can share the teacher's tokens, which matters for
logit-level distillation (**reasoned**; the lab has not said what kind it uses).

Is it a copy of someone else's? I compared the piece strings, mapping SentencePiece's `▁` to a space and
byte-level tokens to text. Of its 166,100 pieces, 58% also appear in DeepSeek-V3's vocabulary (76% of
DeepSeek's), 51% in Qwen3's and 39% in Llama 3.1's (**measured**). That is overlap from common words, not
lineage: a byte-for-byte copy would be near 100%. The tokenizer has its own merges. On three short samples it
used 25 tokens on an English line like every comparison tokenizer, 22 on a Chinese line against Qwen3's 24,
and 31 on a Python snippet against 25 to 27 (**measured**, tiny sample). Roughly: good on Chinese, a little
heavier on code.

## Base to chat: what changed in the weights

I fetched small slices of both repositories to see what post-training touched (**measured**, range requests).

- **The context window moved on paper.** Base: `rope_theta` 1e7 and 131,072 positions. Chat: `rope_theta`
  1.2e8, `rope_scaling` null, 524,288 positions. The chat model re-based its RoPE and says 512K, in the
  config and the card. No long-context evaluation is published, so 512K is a configured limit, not a result.
  See [the RoPE explainer](/architectures/rope) for what the base does.
- **The new chat tokens were learned.** The seven tokens from `<|im_start|>` to `</tool_call>` have near-zero
  rows in Base (RMS 0.0001 to 0.002) and ordinary-size rows in the chat model (about 0.006 to 0.008).
  Ordinary token rows moved about 28% (mean absolute difference over the Base row's mean).
- **Norms barely moved at the end.** The final norm differs by 0.4%, layer 0's post-attention norm by 5%.

That is a model whose post-training changed a lot, not a light fine-tune. How much compute, on what data, is
not disclosed.

## What "teacher first" says, and does not

The strategy in the card is one sentence: build "a high-capacity teacher agent first, which will
subsequently anchor the distillation of advanced agentic capabilities into smaller models." Click through
what is on the record at each stage.

<TeacherMap />

The unknowns are the point. The card names no pretraining token count, no data mix, no RL method, no
agent environments and no distillation recipe. The 4.2-3B report described a synthesized-environment SFT
pipeline and agentic RL with process rewards, and it is tempting to assume 4.3 inherits it. I would not
write that down as fact: the 4.3 pages say none of it. Replies on the post ask the right questions. Does
the student see tool failures and recoveries, or only clean trajectories? Does distillation copy the next
token, which says little about long-horizon behaviour? No answer yet (**reported** as questions, **unknown** as
answers).

One more check. A Hugging Face search for "Nanbeige4.3" on 26 October lists no 3B repository (**measured**).
The student is announced, not released.

## The benchmark claim

All four models were "evaluated at their highest thinking effort," with "the same inference
hyperparameters and harness across models" on each benchmark (**reported**). The comparators are
Qwen3.8-27B, Muse-Glimmer-30B and Gemma4-31B. Reading the card's table, Nanbeige is first on 17 of 20
rows (**measured** by counting the table). It is behind on three: SWE-Bench Pro (60.3 against Qwen's 61.7),
GDPval (84.8 against 86.4) and GPQA Diamond (89.5 against Gemma's 91.3).

<Figure
  src="https://media.thesatyajit.com/ai/articles/nanbeige-4-3-33b/fig1.png?v=a588b672ab75eb00"
  alt="Eight bar charts: Terminal-Bench 2.1, Terminal-Bench 4.0, DeepSWE, SWE-Atlas-QnA, NL2Repo, Automation, JobBench and Toolathlon-Verified. Each compares Gemma4-31B, Muse-Glimmer-30B, Qwen3.8-27B and Nanbeige4.3-33B, and Nanbeige is the tallest bar in every panel."
  caption="The card's headline chart: Nanbeige4.3-33B (teal) against three ~30B models on eight agentic benchmarks (Nanbeige4.3-33B model card, benchmark figure)."
/>

The margins are uneven, and that is the useful part. The big wins are on the newest, hardest agent suites:
Terminal-Bench 4.0 is 23.8 against Qwen's 6.3, DeepSWE 65.5 against 42.5, Automation Bench 54.2 against 38.3.
The small ones are where the benchmark is saturated or noisy: Tau3-Bench is 48.8 against 48.5,
EnterpriseOps-Gym 41.0 against 40.2, AIME 2026 95.2 against 94.5, Toolathlon-Verified 70.4 against 68.5
(all **reported**; gaps **reasoned**). A 0.3 gap on one run is not a lead.

The footnotes tell you where each score came from, and they differ by row. Terminal-Bench 2.1 uses Terminus 2.
Terminal-Bench 4.0, DeepSWE and SWE-Atlas-QnA use `mini-swe-agent` v2.4.6. NL2Repo uses Claude Code, and
JobBench uses Claude Code with a search tool. DeepPlanning, EnterpriseOps-Gym and Tau3-Bench use their
official repositories. So "mainstream agent harnesses" means these. Two caveats. Nanbeige is scored with
`preserve_thinking=true`; the card does not say whether the others got an equivalent setting. And GDPval
uses "revised rubrics" and SWE-Atlas-QnA a GPT-6 judge, so the rows are not on public leaderboard terms
(**reported**).

<Figure
  src="https://media.thesatyajit.com/ai/articles/nanbeige-4-3-33b/fig2.png?v=534504db161ab8a4"
  alt="A heatmap table of JobBench scores for 35 occupations in eight groups, with columns for Nanbeige4.3-33B, Qwen3.8-27B and Muse-Glimmer-30B. Overall scores are 44.80, 34.51 and 16.60. Nanbeige is bold in most rows."
  caption="JobBench by occupation, 35 occupations (Nanbeige4.3-33B model card, occupation figure)."
/>

I counted the occupation figure against Qwen: Nanbeige is ahead in 26 occupations, behind in 8 and tied in one
(**measured** from the image). The losses cluster in healthcare managers, secretaries, customer service and data
entry, and the wins in technical writing, web administration and online merchants. It is the most informative
view the card gives. It still reads one benchmark, with three models.

Two small inconsistencies, both **measured** against the card itself: the chart prints 18.3 for Muse-Glimmer on JobBench
where the table and the occupation figure say 16.6, and 33.7 for Gemma on NL2Repo where the table says 33.8.
Neither changes a conclusion. They do say the chart was not generated from the table.

### The cost claim has no number behind it

The post says the model "tackles real-world tasks with cost-efficient inference" in mainstream harnesses. The
card gives no tokens per task, no dollars per task and no latency. It does give the recommended settings:
temperature 1.0, top-p 0.95 and 65,536 new tokens for agentic work. "Cost" in the post can only mean
per-token price on a 33B dense model, or fewer tokens per task than peers. The first is arithmetic about size.
The second is unmeasured. The cache section above is why I would not assume the first: a long agentic
session pays for 208 KiB per token held. A cost claim needs tokens per solved task next to the benchmark
score, which is exactly what [the Qwen3.8-27B variants article](/articles/qwen3-8-27b-variants) does for
that model. I could not verify this one.

## How it calls a tool

The chat template is where agent behaviour becomes concrete. I rendered it with a sandboxed Jinja
environment and the model's own tokenizer, with one tool, one tool call, its result and a follow-up. This is
the real output from the first user message on, with `preserve_thinking=true` (**measured**). Above it the
template writes a Chinese tool-use preamble and the tool schema, 274 tokens in this case, and the preamble runs
directly into `# Tools` with no line break:

```text
<|im_start|>user
Fix the failing test in src/.<|im_end|>
<|im_start|>assistant
<think>
I should run the tests first.
</think>

<tool_call>
<function=run_tests>
<parameter=path>
src/
</parameter>
</function>
</tool_call><|im_end|>
<|im_start|>user
<tool_response>
1 failed: test_parse
</tool_response><|im_end|>
<|im_start|>assistant
<think>
The parser drops a trailing newline.
</think>

Patched parse().<|im_end|>
<|im_start|>user
Now run them again.<|im_end|>
<|im_start|>assistant
<think>
```

Four facts from it. `<tool_call>` and `<think>` are single added tokens (ids 166105 and 166103), while
`<function=` and `<parameter=` are three ordinary tokens each. The format is the XML shape that vLLM and SGLang
call `qwen3_coder`, which is the parser the card tells you to launch. So compatibility with existing harnesses
comes from reusing a parser, not from a new one (**reported** flags, **measured** format). Tool results come
back as a `user` turn wrapped in `<tool_response>`. And the default system prompt for tool use is in Chinese,
which would be a surprise to someone who only reads the English card.

The flag with a real cost is `preserve_thinking`. I expected it to drop reasoning from every earlier
turn, including the tool loop. It does not. The template drops reasoning only from assistant messages
before the **latest user message**; inside one task's tool loop it is always kept (**measured**: I rendered a
two-step loop with the flag off and both thoughts survived). So the flag matters across follow-up
requests in one session. With it on, the old reasoning stays in the prompt. With it off, each earlier
assistant message carries an empty `<think>` wrapper of 6 tokens. The card recommends on for tool use, and
scores the model that way. The slider shows the price.

<ThinkingTape />

At 800 reasoning tokens a step, six steps a request and eight requests, request 8 starts at 35,218 prompt tokens
with the flag on and 1,870 with it off (**reasoned**). That is cheap to state and expensive to run. The card
reports no ablation of the flag, or of XML against JSON calls, so what each is worth is unknown.

## Running it locally

The community moved fast, because the architecture is stock Llama. Within a day a search finds dozens of
quantized repositories. File sizes come from the Hugging Face listings (**measured**):

| format | size | bits per weight |
|---|---|---|
| BF16 safetensors (official) | 66.2 GB | 16 |
| Q8_0 GGUF (bartowski) | 35.2 GB | 8.50 |
| Q6_K | 29.0 GB | 7.01 |
| Q5_K_M | 25.1 GB | 6.06 |
| Q4_K_M | 20.8 GB | 5.02 |
| IQ4_XS | 18.6 GB | 4.50 |
| MLX 4-bit (pratikgx) | 18.6 GB | 4.50 |
| Q3_K_M | 15.9 GB | 3.85 |
| IQ2_M | 12.2 GB | 2.94 |

Bits per weight is file size over the 33.1B header count, so it includes the embeddings and any higher-bit
tensors (**reasoned**).

Decoding a dense model is bandwidth-bound: each token reads every weight, plus the cache so far. The ceiling is
bandwidth over bytes read (**reasoned**). The community gives me four measurements to test that against
(**reported**, M5 Pro 64 GB Mac mini, MLX 4-bit): 14.4 tok/s at 512 tokens of context, 13.9 at 4K, 11.7 at 16K and
9.9 at 32K, with peak memory 22.8 GB at 16K and 26.4 GB at 32K. Multiply each speed by the bytes read per
token (18.63 GB of weights plus 208 KiB times the context) and you get 270, 271, 259 and 254 GB/s. That
is close to flat, which is what a bandwidth-bound decoder should do, and it shows the cache is what slows
it at 32K (**reasoned**). The memory peaks also match: 18.63 GB plus 6.98 GB of f16 cache at 32K is 25.6 GB,
and the reported peak is 26.4 (**reasoned**). A second report, 13.7 tok/s for a 17 GB 4-bit build on an M4 Pro,
is 85% of the 273 GB/s spec-sheet ceiling of about 16 tok/s (**reasoned**; the bandwidth is the vendor's).

A 12 GB RTX 3060 owner tried it and reported 24K of context and "definitely not usable for agentic
work" (**reported**; no quant or speed given). That matches the ledger: even IQ2_M is 12.2 GB before any cache.

## Licence

The card metadata says Apache-2.0 on both repositories, and there is no separate `LICENSE` file in either file
listing (**measured**). That is a permissive licence for weights. The training data and the evaluation harness are
not released.

## The take

Nanbeige4.3-33B is a competent-looking dense agent model whose strongest claims are on benchmarks the lab ran
itself, against three rivals, on rows where some margins are under a point. The files back the parts they
can: a plain 52-layer Llama, a tokenizer inherited unchanged from the 3B line, a re-based 512K context and a
template that reuses the Qwen tool format. The files cannot back the part in the headline. "Teacher first"
is a plan. The recipe, the distillation and the cost-per-task claim are unpublished, and the 3B student does
not exist yet.

What you can use today is a 33B you can run on a 24 GB card at modest context, with a cache that is more
expensive than its peers'. What to wait for is the technical report and an independent run of Terminal-Bench 4.0
and DeepSWE. If the student arrives and holds up, the strategy is proved. Until then the interesting number
is not a score. It is 208 KiB.

---

*Sources: the [Nanbeige4.3-33B](https://huggingface.co/Nanbeige/Nanbeige4.3-33B) and
[Base](https://huggingface.co/Nanbeige/Nanbeige4.3-33B-Base) repositories (card, config, tokenizer, safetensors
headers, file listings), the [announcement post](https://x.com/nanbeige/status/2114328933181333798) and its
replies, and the community repositories named above. Figures are the lab's; the interactives are mine. Not
verified: any benchmark score, the tokens-per-task claim, the 512K context, and the distillation plan. I ran
the tokenizer and chat template on a shared 4-core CPU, and never loaded the weights.*
