Why Did a Fine-Tuned Support Model Spout Python Reasoning? A LoRA Training Postmortem

10% replay data skewed a support model's style because long reasoning samples outweighed tickets in tokens.
A developer training a customer support LoRA model mixed in Nemotron general data at 10% by row count. The model then output long reasoning and Python code on a simple question, delaying the demo. Postmortem: the dataset's English splits were dominated by long math/STEM reasoning samples, replay tokens surpassed all real tickets, and reasoning-on samples weren't filtered. The developer had only checked duplicates and PII, missing token length distribution. The fix—chat split only, reasoning-off answers, length caps—restored two-sentence replies, but general scores dipped slightly, revealing the trade-off between domain fit and conversational generalization.
A developer on Reddit who was doing LoRA fine-tuning for an enterprise shared a fairly representative failure story: the customer support model he trained for a client, when asked a simple question like "how long after five failed logins before I can retry," first output a long stretch of step-by-step reasoning, threw in a small code block using Python to add thirty minutes to a timestamp, and only then gave the answer. And this question was meant to be replied directly to the customer support lead. The demo got postponed as a result.
On the surface this looks like a joke, but it actually exposes a high-frequency yet easily overlooked pitfall in fine-tuning work: when training data is mixed with a large number of samples that contain reasoning processes and code, the model learns these "expression styles" as if they were the task itself, even if your business scenario has no need for a chain of reasoning at all.
A Seemingly Harmless Training Recipe
The developer's usual approach wasn't aggressive by any measure: for an 8B instruct model, apply LoRA to all linear layers, and as is customary, mix in a portion of general conversation data—because on a previous occasion, after narrow-domain training, the model couldn't even hold a normal chat.
The client had one hard constraint: content produced by closed-source models could not be used. Legal accepted datasets built primarily under the CC BY license, sourced from open-source models. So he chose Nemotron-Post-Training-Dataset-v2, mounted it into a container on HyperAI (finding the mount point took quite a while), sampled from all English splits, with replay data making up 10% of total rows.
Looking at just this ratio, 10% sounds quite restrained. The problem is that row count and actual token count are completely different things.
LoRA (Low-Rank Adaptation) is a parameter-efficient fine-tuning technique: it freezes all the original weights of the pre-trained model and only attaches a pair of low-rank matrices (A and B) alongside each linear layer, updating only these two small matrices during training. Taking an 8B model as an example, the trainable parameter count typically accounts for only 0.1%–1% of the total, with VRAM and storage costs far lower than full-parameter fine-tuning, which is why it has become a mainstream approach for enterprise custom models.
"Applying LoRA to all linear layers" means the Q/K/V/O projections of the attention layers and the up/down projections of the feed-forward layers all get adapters injected—broad coverage and strong expressiveness, but also more prone to learning the stylistic features of the training data (such as verbose reasoning and code formatting) wholesale. Another characteristic of LoRA is that adapters can be saved independently and hot-swapped, so the same base model can host multiple business adapters, making it very popular in multi-client delivery scenarios. Understanding this is what makes it clear why a small deviation in data ratio can show up so directly in the final output.
Replay Data's Token Count Surpassed All Real Tickets
After the demo was postponed, he went back and counted tokens, discovering that the token count of the replay portion was roughly equal to the sum of all tickets combined. The reason was clear: in the English splits of the Nemotron dataset, the largest share is math and STEM content, and these samples are long, complete reasoning processes, with individual lengths far exceeding a single customer support ticket.
More critically, he hadn't filtered out the samples with "reasoning switched on." The dataset card actually mentioned this, but he missed it. As for that Python code, he guessed it came from the code split.
There are two levels here worth examining separately.
Level One: Length Distribution Never Made It onto the Data Checklist
His data checks covered duplicate samples and personal privacy information, but length was not on the checklist. This is a very typical blind spot—when people check data, they habitually focus on "is it dirty" and "is there PII," but rarely plot a distribution of token lengths. When one end of the scale is a few hundred words of a ticket and the other end is a several-thousand-token reasoning chain, a 10% row share becomes an overwhelming presence in terms of gradients.
Level Two: Task Mismatch Is More Insidious Than Dirty Data
This model's sole responsibility was to "sound like their customer support agent," while factual content already went through the help center's retrieval. In other words, reasoning ability has no value for this task—it's actually interference. What the math and code samples brought wasn't knowledge; it was an output habit.
There was one more signal he attributed to noise: held-out ticket accuracy dropped by a few points. In hindsight, this was more likely a direct consequence of imbalanced training ratios rather than random fluctuation.
Replay data refers to general conversation samples mixed in at a certain ratio during domain fine-tuning, meant to prevent the model from overfitting on narrow-domain data and losing general conversation ability (commonly called "catastrophic forgetting" in the industry). A common practice is to sample from public instruction datasets and give a fixed ratio by row count, such as 5% or 10%.
The problem is that "proportioning by row count" implies an assumption: samples from different sources have similar lengths. Once long reasoning chains are mixed into replay data, that assumption breaks down. Training loss is computed per token, and long samples contribute far more gradient than short ones, so 10% of rows can easily correspond to 50% or more of tokens and gradient signal. The correct approach is to first tokenize and tally the total token count of each source, then sample with weights based on token ratios, truncating or downsampling overly long samples as needed.
The reasoning switch (reasoning on/off) is an annotation dimension introduced by many post-training datasets. Samples with reasoning retain a chain of thought or internal reasoning process before the final answer, typically generated by models with long-thinking capability; samples without reasoning retain only a concise final answer. Dataset cards generally specify which splits or fields belong to which type.
For customer support, shopping guide, and notification-type response models, what's needed is a "give the answer directly" behavior pattern. Once a large number of reasoning-on samples are mixed into training data, the model treats "reason at length first, then answer" as the task specification. The filtering method is usually to check whether sample fields contain tags or delimiters like reasoning, thinking, or chain_of_thought, and keep only the versions with reasoning turned off. Skipping this step amounts to accepting everything by default, and style drift is almost inevitable.
The Fix: Keep Only the Chat Split, Turn Off Reasoning, Cap Length
The final adjustment was quite clean:
- Use only the chat split for replay
- Keep only reasoning-off answers
- Set a cap on length
After the changes, the model answered questions in two sentences. The style returned to the goal of "sounding like a customer support agent."
The cost was a slight decline in general evaluation scores. He planned to figure out exactly which tasks had degraded before the client sent in the new year's tickets next month. This trade-off itself is very real: there is tension between a support model's conversational generalization ability and its domain fit. General data was mixed in earlier to remedy the side effects of narrow-domain training; now tightening the replay brings part of that problem back.
The chat split refers to the subset of a dataset organized specifically in multi-turn conversation format, with samples that are usually shorter, more natural in tone, and closer to real interaction; other common splits alongside it include math, code, stem, etc., used to train reasoning and programming abilities. When doing domain fine-tuning, taking only the chat split preserves the "conversational style" to the greatest extent while removing the expression habits of reasoning and code.
The accompanying length cap is a hard constraint: for response models, you can set a maximum token count per sample (such as 512), truncating or discarding anything beyond it. This both suppresses the gradient weight of long reasoning samples and teaches the model to complete answers within a limited length. The three adjustments combined essentially realign the training distribution to the target behavior of "customer support agent."
A Few Reminders for Teams Doing Domain Fine-Tuning
This kind of problem is not an isolated case and is worth distilling into procedural checklist items:
Proportion by token, not by row. Row-count ratios have almost no reference value when length differences are huge. After sampling, first tally the total token count of each source, then decide the weights.
Read the dataset card's notes on the reasoning switch. Many post-training datasets explicitly distinguish "with reasoning" from "without reasoning" samples, and not filtering by default amounts to accepting everything by default.
Treat output length as a hard acceptance metric. For response models aimed at end users, length isn't just a style issue—it directly affects whether the output can be used as-is.
Don't casually dismiss small declines in evaluation scores as noise. In runs with obviously abnormal ratios, it's often the first observable warning sign.
One last point: if what you're doing is making a model imitate the way a certain role expresses itself, then "being smarter" isn't necessarily a plus. In this case, the Python timestamp arithmetic the model learned was a pure liability for an account lockout question.
One-line Summary
10% replay data with long reasoning samples outweighed tickets in tokens and skewed the support model's style.
Paragraph Summary
When a developer trained a customer support LoRA model for a client, he mixed in Nemotron general data at 10% by row count. As a result, the model output long reasoning followed by Python code on a simple question, delaying the demo. A postmortem found that the dataset's English splits were dominated by long math and STEM reasoning samples, and replay's total tokens surpassed all real tickets, with reasoning-on samples left unfiltered. The developer had only checked duplicates and PII, overlooking token length distribution. The fix was to use only the chat split for replay, keep only reasoning-off answers, and cap length. The model returned to two-sentence answers, but general evaluation scores dipped slightly, revealing the trade-off between domain fit and conversational generalization.
Related articles

Felix Rieseberg Personal Homepage
Felix Rieseberg's personal homepage sparks attention on Hacker News. This article covers the Slack engineer's technical background, the rise and fall of nativefier, and the value of a developer homepage as a tech calling card.

@ai-sdk/vue 3.0.306 Patch Release Syncs with [email protected] Update
@ai-sdk/vue 3.0.306 released, synced with [email protected]. A routine patch release for the Vercel AI SDK ecosystem with no public API changes; the Vue adapter layer stays version-aligned with the core package.

Gemini 4 Argon API Launches: The Era of Million-Token Output Begins
Google launches Gemini 4 Argon with sparse MoE architecture, up to 1M output tokens, and a 68.90% Vals Index score, available across API, AI Studio, and the Gemini app.