Jason Belnick

Writing · · 4 min read

I trained a local model to write like Claude

I trained a 9B to write like Claude, benched it blind, and the ending flipped: the bigger model with the distilled skill took the seat

I set out to replicate the skill-as-teacher pattern from cjzafir on X, whose post about distilling a writing skill and aiming it at a small local model started this whole experiment. The owner directive was specific: create a skill that forces a local model to adopt the writing style of Claude. I did not aim for general capability. I aimed for stylistic mimicry. The target was a narrow band of prose.

I trained an adapter and adopted it into the writer seat. The model did not become Claude. It became a model that attempts to write like Claude. The distinction matters for the inference cost and the output quality. I ran the adapter through the serving stack to verify it loaded without crashing.

The end-to-end writer.py smoke test confirmed the pipeline worked. The script sent a prompt through the adopted serving instance and returned text. The text arrived. I then had to determine if the text actually sounded like the target. The smoke test proved connectivity, not competence.

What I built

I followed the cjzafir skill-as-teacher directive to create a local model that writes like Claude. I did not start from scratch. I salvaged data from prior workflow journals: 180 deslop pairs, 5 fact packs, and draft-final pairs. This formed the training corpus.

Before training anything I calibrated the gate: all 11 of my published posts scored 100 on the style scorer, and a deliberately slop-filled control paragraph scored 52. A scorer that cannot separate my prose from slop would have made everything downstream meaningless.

Training attempt 6 exited with code 0. Train loss dropped from 2.94 to 0.64. The run succeeded.

I built a pipeline that converts raw journals into structured pairs. The fact-miner extracted the 180 pairs. The adapter learned the style. The gate kept the slop out. The result was a narrow improvement on specific briefs. I measured the gain in pass rate and judge score. I did not measure general capability. I stuck to the directive. I built a writer that mimics Claude on held-out data. The OOM fix was the hardest part. The rest was configuration.

What broke first

The training itself broke before the style transfer got a chance to. Five runs died on Metal out-of-memory errors, and every crash landed at the same iteration regardless of batch size, checkpointing, or cache caps.

The out-of-memory errors traced directly to per-example sequence length, not batch size or precision. I could not fix the crash with runtime knobs or gradient checkpointing. I had to cut the input at compose time. I capped every training example at 950 words. The OOMs stopped. The tradeoff was explicit: I sacrificed context window for stability. I accepted that limit because a crashed job teaches nothing.

Overfitting arrived before validation loss told me about it. I stopped trusting the final checkpoint for quality. I began benching intermediate saves every hundred steps. The early saves generated cleaner prose. The later saves memorized the training distribution and collapsed into repetitive patterns. I learned to pick the checkpoint that sounded most like the target, not the one with the lowest loss.

The final failure was factual. The model hallucinated numbers when the prompt omitted them. It invented statistics to fill the silence. I realized the brief must carry the facts. The model cannot fact-check itself. I stopped asking it to generate data and started feeding it verified snippets. The writer follows the brief. It does not invent the world.

The verdict

I benched the adapter blind on 12 held-out briefs. The raw judge preferred it 8 to 4 over the prompted base. Through the production pipeline it averaged 91.0 on the style gate with 11 of 12 briefs passing, against the base's 90.0 and 10. The production judge split 6, 5, and 1. Two wins and a tie; the adapter took the seat.

Overfitting appeared in generation samples long before validation loss said anything conclusive. The final checkpoint leaked the exact patterns the corpus trains against, so I benchmarked intermediate saves and shipped the checkpoint from step 400 instead of the final weights. That decision saved me from deploying a brittle model.

Then the ending flipped. I pointed the same distilled skill prompt at the 27B that already runs around the clock on this machine and reran the whole bench. No training at all: 95.0 average with 12 of 12 passing, and a blind judge preferred it 8 to 4 over my trained adapter. The seat went to the bigger model. The adapter keeps the fallback slot.

If you try this, the honest summary is that the fine-tune worked and still lost. The durable asset turned out to be the skill itself, the distilled contract of how I write, which transferred to the stronger model for free. Train the small model if you need the dedicated slot. Measure it against a well-prompted big one before you believe the adapter earned anything.