Kimi K3 is the largest set of open model weights anyone can download. Anyone can have the file. Almost nobody can run it — 2.8 trillion parameters, and even the most compressed complete version is around 870 GB. That is a datacentre number. It is not a number that fits under a desk.
A Mac Studio has 512 GB of memory, which is an absurd amount for one machine and still not close to enough. Normally that gap gets closed by quantisation — storing every weight more coarsely, 16 bits down to 8, down to 4. Here the maths runs out. Fitting K3 into 512 GB would mean 1.38 bits per weight, which is past the point where quantisation is a technique rather than a rounding error with ambitions.
Which raises the question that makes this class of model interesting in the first place. A mixture-of-experts model is not one brain, it is hundreds of small specialists with a router picking a handful per word. Nobody needs all of them. So could you take a frontier-scale model, keep only the specialists your own work actually depends on, delete the rest, and end up with something that runs on the machine already on your desk?
That is a real question with a real prize — a personal model, shaped to one person's use, running locally, on weights anyone can download. The version tested over a weekend was narrow: keep what handles Croatian, throw away the rest.
It fit. It ran. And it lost to a 19 GB model that would run on a laptop.
Pruning a mixture-of-experts model damages its ability to begin a response, not its ability to be right — and the corpus you calibrate on decides which languages keep the ability to begin.
Why deleting most of the model is even an option
For a normal model, cutting four-fifths of the weights is not a strategy, it is vandalism. Every weight participates in every token.
K3 is not that kind of model. It is a mixture-of-experts, and the architecture is worth a moment because everything downstream depends on it. Each of its 92 relevant layers holds 896 separate small networks — the experts. When a token comes through, a router picks 16 of those 896 and ignores the other 880. Different tokens wake different specialists. The model is not one large brain that must be present all at once. It is a warehouse, and any given moment of work opens sixteen doors in it.
Which makes an obvious thought hard to shake. If a model that only ever reads Croatian and writes Python opens the same few doors over and over, why is it carrying the rest of the building?
That thought rests on an assumption worth saying out loud, because it does a lot of work and it is only partly true. Experts are not labelled. Nobody has opened expert 417 and found the Japanese morphology inside it, and the popular image of one specialist per subject is not something this project or, as far as I know, anyone else has demonstrated. What can be measured is which experts a given kind of text selects. Across eight tagged sources the structure there is real and untidy at the same time: any two domains share on average 50.4% of their selected experts, which is 1.87 times what random selection would give. Routing is genuinely domain-sensitive. It is also nowhere near a clean partition — code and Chinese overlap least, at 23.8%, and even that is only a few points below chance.
There is even an established method for choosing what to cut. REAP scores each expert against a calibration corpus, measuring how much that expert actually contributes to output on that text, then deletes the ones that score low. Builds published this way already exist. Their calibration mix runs roughly 40% code, 30% English, 15% Chinese, and 15% spread across seven more languages.
Croatian appears nowhere in it. Which is the whole opening.
The corpus is the specification
That framing turns a config file into the most consequential decision in the build. The calibration corpus is not an input to the pruning. It is the specification of what the model is permitted to remain good at, because anything unrepresented in it is, by construction, a candidate for deletion.
So the corpus went 24.6% Croatian and 16.2% code, and 179 of the 896 experts per layer survived. Four-fifths of the model deleted, and the fifth that lived chosen specifically for one small European language.
The result is a 326 GB file that loads and runs at 5.4 tokens per second. Set against it were three deliberately unglamorous models — 65 GB, 19 GB and 13 GB — on 200 reading-comprehension passages per language and all 164 problems in a standard coding benchmark. Same prompts, same harness, greedy decoding, no retries.
Forty-five percent against ninety-three. Seventeen times the disk, six times the memory, five times slower, and forty-eight points worse at the one language the entire build was aimed at.
There is no generous reading of that chart, and nothing later in this post rescues it. As a way to get a usable Croatian model onto a desk, this failed completely.
But the shape of the failure did not match the shape of the surgery, and that is where it got interesting.
It isn't wrong. It's mute.
A benchmark score is one number covering two entirely different questions: did the model answer, and was the answer right. Those normally travel together closely enough that nobody separates them. Here they came apart.
The pruned model responded to 85.5% of Croatian prompts, 68.0% of English ones, and 49.4% of coding prompts. The three comparison models answered 98–100% of everything put in front of them. On the coding benchmark the split is almost surgical: 83 of 164 prompts produced zero tokens. Not a bad answer — no answer. The first token the model predicted was a stop token, so it emitted an empty string and scored zero by default. The remaining 81 produced real code, and that code passed 50.6% of its tests.
Twenty-five percent pass@1 reads as "this model cannot code". It codes at fifty-one percent and stays silent half the time. Those are different failures, and only one of them is about coding.
Roughly half the coding ability survived having four-fifths of the model deleted. What did not survive is whatever decides that a response should begin at all.
I can measure that failure and I cannot yet explain it. "Emits nothing" is an observation about output, and there are at least two different things underneath it — the model may be predicting a stop token at the very first position, or the response channel may never open because the chat template's control tokens route to experts that no longer exist. Different causes, different fixes. Reading the raw probabilities at position zero across a few hundred prompts would separate them in an afternoon, and that has not been done. Until it is, "pruning damages response initiation" describes a symptom, not a mechanism.
The Croatian result then reads differently, and not in the flattering direction. On identical passages the pruned model answers 17.5 points more often in Croatian than in English, and restates the passage instead of answering 14.5 points less often. Both effects are strong and hold up statistically. But the accuracy gap is 7.0 points and does not clear significance — and when it does answer, it is marginally better in English (55.9% against 52.6%).
So the Croatian corpus did not buy Croatian comprehension. It bought willingness to respond in Croatian. Which happens to be the exact axis the pruning damaged, so it protected the thing under threat — it just was never comprehension that was under threat.
The pushback: how do you know you didn't just break it?
It is the right question, and it does not get waved away, because twice during this project a configuration bug was completely indistinguishable from a destroyed model.
The first ran at 1.14 tokens per second. A quantisation profile had left the non-expert weights at full precision, so 114 GB was being re-read from memory on every single token. That reads exactly like a prune that wrecked the model. One flag took it to 5.19.
The second was more convincing, and worse. The tokenizer registered the chat control tokens as generic placeholders, so a marker like <|open|> encoded as five ordinary text tokens. The model was being shown its own chat markup as prose, and it did the only reasonable thing available to it — it continued the text. Echoing, repetition, degeneration. Textbook over-pruned behaviour, entirely a tokenizer bug, and it would have been very easy to write that up as a finding.
Against that, the artefact itself is verified without ever being loaded. Compared tensor by tensor against the source: 59 of 59 shards present, zero missing tensors, zero orphans, and 24 experts sampled across layers 8 to 86 dequantised and checked against the same experts in the original — all bit-exact, cosine similarity 1.00000, following the keep map exactly. That rules out the failure this result would otherwise most plausibly be: a router renumbering fault, where surviving experts get reindexed but the router still points at the old rows. That produces a model which loads cleanly, writes fluent grammatical text, and sends every token to the wrong specialist.
Then there is the harder version of the same question, which is whether the numbers themselves can be trusted. They could not, twice.
The first analysis said something far more flattering than anything above: Croatian 40.5%, English 24.5%, a 16-point advantage at p=0.00064. The targeting had worked. It fit the hypothesis, which in hindsight is the tell. It survived a four-hour benchmark sweep, eight fixed bugs and a written set of conclusions — and it lasted exactly as long as it took to write a script that could regenerate it from the raw per-item records.
The first error was that the comparison was never paired. The benchmark's entire methodological value is that it is parallel: the same 900 passages exist in every language, so comparing a model against itself across two of them isolates language ability from item difficulty. The harness drew 200 items per language using the same seed and got 48 in common. shuffle(seed) fixes the permutation, not the outcome — each language stores its rows in a different order, so position k after shuffling is a different passage in Croatian than in English. The one property that made the benchmark worth choosing had been thrown away by a line that looked obviously correct. Re-scoring English on the exact Croatian items took 53 minutes and moved the gap from 16.0 points to 7.0, and p from 0.00064 to 0.13.
The second error was a detector for responses that restated the passage instead of answering it. It flagged a response as an echo if its first 40 characters appeared anywhere in the prompt's first 200 — with no minimum length. The expected answer to one of these items is a single digit, and most passages contain that digit somewhere near the top. So a bare, correct 2 was classified as an echo, discarded as unparsed, and scored wrong. That touched 253 items, and for all three comparison models it accounted for 100% of their reported echoes. Those models had never restated a passage once. An echo rate around 10% looked entirely plausible across four models, which is exactly why it survived from the pilot run onwards.
Correcting the echo rule raised the comparison models by 8–11 points and the pruned model by only 3–6. The fix made the result being reported here worse. That is the one correction not worth double-checking, and it is the reason to trust the direction of the other three.
Two more of the same family turned up in that pass. The published throughput number averaged per-item rates, which counted 83 generations that produced zero tokens as running at zero tokens per second — the real sustained rate was 5.4, not 4.3. And the significance test printed p = 0 for what was actually 3e-42, because 1 − normal_cdf(z) cancels to exactly zero past |z| = 8. A p-value of zero is never a result. It is a rendering artefact that reads as stronger evidence than the truth.
None of the four were in the experiment. The measurement was fine the entire time. All of them lived in the layer that turns measurements into claims — the layer with no tests, no assertions and no second reader, and the only one anybody actually reads. Every one of them was a bimodal failure hiding inside an average that looked perfectly reasonable, which is the same shape as the finding itself.
Three limits remain that cannot be fixed by re-reading anything. There is no control arm: a published build at the same ratio and quantisation profile, differing only in calibration corpus, has not been through this harness, so "REAP is destructive at this ratio" cannot be cleanly separated from "this particular build is broken". The generation path is not independently validated, and given that two of the worst bugs here lived in exactly that code, the absolute response rates deserve less confidence than the Croatian-versus-English comparison, which survives because both languages run an identical template. And there is no unpruned baseline anywhere — 870 GB against 512 GB means no unpruned K3 has produced a single token on Apple silicon, not here and not in the toolchain that publishes these builds. Every number anyone has, including all of these, comes from a model that has already had most of it removed.
So: can you shrink a frontier-scale model down to your own use case and run it on your own desk? Not like this. Cutting 80% in one pass, choosing survivors by corpus alone, at this quantisation profile, produces something that fits and is not worth running. The idea is not disproved — it is untested at the settings that would actually matter. Gentler ratios, a control arm to separate the method from this build, a corpus swept rather than guessed, and above all a fix for a model that has the answer and never starts speaking. That last one looks like the whole game, and it is one afternoon of reading logits away from being understood.