NOW LET US – AI RAG SaaS Studio TP.HCM
NOW LET US
Digital Product Studio
Back to news
DEV-TOOLS...6 min read

Fine-tuning an LLM to write docs like it's 1995

Share
NOW LET US Article – Fine-tuning an LLM to write docs like it's 1995

An experiment in fine-tuning modern LLMs like Llama 3.1 and Qwen 2.5 using QLoRA to mimic the technical writing style of 1980s and 1990s Microsoft manuals.

Fine-tuning an LLM to write docs like it's 1995

In my predictions for 2030 I wrote that tech writers would be using specialized LLMs, running locally on powerful hardware. I see hints of this move to “local first” among engineering pundits, but we’re not there yet, in part because of how much more powerful connected frontier models are. That doesn’t mean we can’t experiment, though. That’s precisely what I did last week, trying to fine-tune an instruct model to write like a software technical writer from the 80s and 90s.

Summoning old tech writing lore for research

To train a personal, local model to write like a technical writer from the 90s, one needs tons of written sources. If I wanted to fine-tune a model to write like myself, for example, this blog would not be enough, as it’s barely 100k words at the time of this post. You would need more samples for thorough training, and those are not easy to come by, nor simple to produce. The only quick way is to use an existing corpus. Where could I get one?

Meet Bitsavers: it’s a website that collects and scans old computer manuals and brochures. It’s an incredibly valuable repository of computer history and ancient tech writing, with mirrors available everywhere. As I’m fond of Microsoft manuals from the 90s, I chose the Microsoft collection as the source of training materials. The collection contains out-of-print docs published between 1977 and 2005: more than 37 million words, covering old systems and SDKs.

I downloaded the OCR’d text files and cleaned the content from artifacts and clutter (like indices and frontmatter) using good old Python scripts. I then used a cheap and fast model through OpenRouter, gemma-4-26b, to classify each paragraph as either “keep” or “drop” based on its intelligibility. This second pass cost around 8 dollars. Even with this two-pass cleaning, though, training data retained noise that I discovered only later, but that was largely OK for my tests.

I split the sanitized text into training examples on paragraph and section boundaries, breaking at headings and keeping code blocks whole, with each chunk capped at around 512 tokens as per Claude advice. Each chunk was paired with a synthetic instruction drawn from templates. I ended up with 192,456 examples in JSONL format (one JSON object per line). I could have used a small model to also come up with better instructions and questions, but I’m an impatient person.

Fine-tuning as an alternative to training from scratch

In an ideal world, I would have several millions of dollars lying around, ready to be burned creating my own LLM, Fabrice. Since I’m far from rich (I wouldn’t be writing this otherwise), the alternative to Fabrice is fine-tuning, which involves tweaking the “weights” of a model so that each token generated is conditioned by the training materials. I like to picture fine-tuning as slightly steering the trajectory of a massive iceberg using tugs; just a little, just to get the intended effect.

Why fine-tuning and not, say, retrieval-augmented generation (RAG)? Because in this experiment I was not so much interested in retrieving facts, a scenario where RAG excels, as in getting an LLM to behave and write in a specific style, whatever its knowledge of the context. Compared to full training, fine-tuning doesn’t require a massive amount of data, so it’s cheaper. Also, just because: I always wanted to try fine-tuning as a technique and see how feasible it could be.

To avoid spending days or weeks fine-tuning a model on my computer, which has a rather old graphic card, I relied on Runpod, an online service for AI developers that provides on-demand pods with pre-configured GPUs and tools for a (relatively) small price. For less than $6 per hour, for example, you can lease a beast of a card, the Nvidia B200 (192gb of memory). The service has a convenient API with configurable auto-recharge and cost control mechanisms.

Entering a world full of mysterious buzzwords

After deciding to fine-tune a model, I consulted with Claude on the sanest methods to achieve that. We settled on QLoRA (Quantized Low-Rank Adaptation), which achieves fine-tuning not by altering each weight of an LLM, but by “freezing” them and putting an adapter on top, which is a small file that reshapes the model behavior (a bit like a mask, if you will). The Q in QLoRA means that the result is quantized, that is, compressed, reducing memory requirements.

Are you still with me? Good. If you think this is dense, it’s because it is.

Doing anything with LLMs at home these days is an exercise in compromises: you either sacrifice time, spend money, or curb your ambitious goals. I tried to strike a balance to get something meaningful in less than a weekend. I chose to try fine-tuning on two models, Llama 3.1 8B Instruct and Qwen 2.5 7B Instruct. At their size (around 8B) they run comfortably on a Macbook Air. I also tested a Llama base model (which is not trained to answer questions).

I tested fine-tuning under several different conditions: varying the volume of training materials (a subset vs. the full corpus), the number of epochs (training rounds), and structural parameters like the rank. I only hold a superficial knowledge of all this, but I trusted my agent to make the right choices, which I happily questioned at every step. For example, 3 epochs can result in “overfitting” in some cases; in the world of LLMs, that translates to excessive training. Fun times.

| Run | Base | Data | Epochs | Rank | |---|---|---|---|---| | Llama instruct-40k | Llama 3.1 8B Instruct | 40k | 1 | 16 | | Llama base-40k | Llama 3.1 8B (base) | 40k | 1 | 16 | | Qwen-40k | Qwen 2.5 7B Instruct | 40k | 3 | 16 | | Qwen-192k | Qwen 2.5 7B Instruct | 192k | 1 | 16 | | Qwen-r8 | Qwen 2.5 7B Instruct | 40k | 1 | 8 | | Qwen-r16 | Qwen 2.5 7B Instruct | 40k | 1 | 16 |

Adapters can only be applied to the target model you fine-tuned for. After training each adapter, I exported them to my laptop and converted and quantized them to a GGUF LoRA file, and then registered it as a local Ollama model I could run in my laptop for benchmarking purposes. The local-conversion approach is faster and requires no GPU, though inference is somewhat slower than a fully merged model. For the test at hand, I did not care about speed that much.

Training the adapters for all conditions took perhaps an entire day, including breaks, for a total cost of $50. Along the journey, I lost two adapters: Runpod is unforgiving of budget and deletes pods immediately if funding is zero (there’s a lesson learned, yes). Claude took care of setting up each run and following up with Runpod’s API. The /goal command of Claude Code was quite helpful to loop through each phase (in retrospect, I would have run it in YOLO mode).

This table shows all the models I compared and their conditions:

| Name | What it is | |---|---| llama3.1:8b | Unmodified Llama baseline | qwen2.5:7b | Unmodified Qwen baseline | msft-base-40k | Llama base (non-instruct) + 40k (control) | msft-instruct-40k | Llama instruct + 40k, 1 epoch, rank 16 | msft-qwen-40k | Qwen + 40k, 3 epochs, rank 16 | msft-qwen-192k | Qwen + 192k, 1 epoch, rank 16 | msft-qwen-r8 | Qwen + 40k, 1 epoch, rank 8 | msft-qwen-r16 | Qwen + 40k, 1 epoch, rank 16 |

Did the style transfer after fine-tuning?

I subjected each model to the same prompts:

  • Document malloc(), a staple C function, something the training materials might know about.
  • Document a fictitious ConnectWifi() Win32 API function. No presence in the training materials.
  • Explain what a REST API is in 1990s Microsoft style (the anachronistic test).

For the malloc() test, the unmodified models generated modern Markdown docs in the style of a README, while the fine-tuned models used a period correct structure, with a Synopsis block, a Return Value section, and so on. For the fictitious ConnectWifi() function, only the 3 epochs model maintained the fiction and documented i

© 2026 Now Let Us. All rights reserved.

Source: Hacker News

Advertisement
Ad slot ready: 5887729102

More in this category

NOW LET US Related – Changing How We Develop Ladybird

dev-tools

Changing How We Develop Ladybird

The Ladybird browser project has announced a major shift in its development process, closing public pull requests to tighten security and code quality. The decision is heavily influenced by the rise of AI tools, which have altered the trust dynamics of open-source contributions.

NOW LET US Related – The IsUpMap lets you check the status of over 100 major sites at once

dev-tools

The IsUpMap lets you check the status of over 100 major sites at once

isUpMap is a real-time status heatmap that allows users to quickly check the operational status of over 80 popular online services. From leading AI platforms like OpenAI to cloud and payment services, this tool helps you easily identify whether a connection issue is system-wide or on your end.

NOW LET US Related – Open Code Review – An AI-powered code review CLI tool

dev-tools

Open Code Review – An AI-powered code review CLI tool

Open Code Review is an AI-powered code review CLI tool, originally developed as Alibaba Group's internal assistant, now open-sourced to provide precise, line-level code feedback.

NOW LET US Related – Leap in DNA synthesis slashes time to build new genetic sequences

dev-tools

Leap in DNA synthesis slashes time to build new genetic sequences

A new DNA synthesis method called Sidewinder promises to unlock the potential of generative AI in biology by offering a fast, cheap, and highly accurate way to physically build novel genetic sequences.

NOW LET US Related – The Website Specification

dev-tools

The Website Specification

A platform-agnostic specification of the technical features every decent website should have, designed for both humans and AI agents.

NOW LET US Related – Avian Visitors

dev-tools

Avian Visitors

Avian Visitors is an open-source project that combines a Raspberry Pi, the BirdNET acoustic classifier, and Gemini AI to automatically identify bird calls and generate beautiful Japanese kachō-e style collages.

EXPLORE TOPICS

Discover All Categories

Deep dive into the specific technology sectors that matter most to you.