Skip to content
tarıtas
Build decisions POST-21 8 min read

We Split One Prompt Into Two to Fix a Small LLM. Then We Deleted Both.

A small, cost-optimized LLM asked to do two jobs in one call, classify a caller's intent and generate a response, silently dropped hard formatting rules on roughly 1 in 30 turns once the combined prompt passed 500 lines. At taritas we fixed this by splitting the work into two focused calls, a classifier and a responder, and ran them so the added latency stayed under a second. Weeks later, on the same voice agent, we deleted the classifier anyway, not because splitting the jobs was wrong, but because a broader review found the whole layered pipeline sounded robotic and moved auditing to a step after the call ends. Small LLMs still prefer narrow jobs. The fastest way to find out whether you still need a layer is to remove it and watch what breaks.

Published · Updated · Supreet Tare

All names, numbers, and identifiers in this post are anonymized. The patterns are real.

Two architectures for one caller turn: a single small LLM call handling both classification and response drifted on hard format rules and misrouted requests, while two focused calls, a classifier and a responder, stayed reliable at the cost of under a second of added latency, mitigated by running the classifier and a knowledge base search in parallel

The question a code reviewer would reasonably ask

A voice agent we operate for a public-sector call center runs a small, cost-optimized LLM at temperature 0. Every caller turn fires two separate calls to it, not one:

  1. A classifier call. Input is the caller’s latest message plus a short history window. Output is exactly one line: a category label and a brief reason. Nine categories cover things like an immediate transfer, a transfer request, a routine request, a request that needs clarification, an out-of-scope question, legal advice, small talk, and emotional distress. The classifier prompt is about 290 lines.
  2. A responder call. Input is a 244-line system prompt, the running conversation, and a per-turn context block the code injects with the classifier’s label and pre-fetched knowledge base results. Output is the spoken response.

Together that is about 534 lines of instructions split across two calls, and roughly 600 milliseconds of extra latency for the classifier step that one combined call would not have. Any reviewer looking at this codebase would reasonably ask why we pay that latency twice instead of using one prompt with structured output that classifies and responds in the same call.

We tried the combined version. It failed in a specific, repeatable way, and we reverted it.

What we tried instead

The combined-prompt attempt was one LLM call with a single prompt containing both the classifier’s rules and the responder’s rules, asked to return a structured object with two fields: a classification and a response. Same model, same temperature, same generation settings as the split version.

The failure showed up in two complementary ways on different calls:

  • Sometimes the classification came out correct but the response broke a specific hard rule from the responder prompt, most often reading something in digit form when the spoken form was mandatory, or using a written phrasing that a phone caller would mishear.
  • Sometimes the response was fine but the classification was sloppy, for example labeling a clear payment-action request as a routine request instead of an immediate transfer, which then meant downstream code silently disagreed about what the turn actually was.

Both failure modes matter. A bad response is a bad caller experience. A bad classification breaks the deterministic code that depends on it: an abuse counter, a daily rate limit, transfer routing, distress detection, and the gating that decides whether a canned response is appropriate. The classifier was not just deciding what to say next. It was the gatekeeper for guardrails the rest of the system trusted.

Why the combined prompt degraded

The model’s instruction-following got worse as the combined prompt grew. Somewhere between 200 and 400 lines of instructions in one call, hard rules started to be silently dropped, not on every turn, but often enough that roughly 1 in 30 turns violated a specific format rule.

Asking one call to also produce a machine-readable classification adds a second job the model has to hold in working memory while generating a response. The classification stayed correct surprisingly often, since it is a small, example-heavy decision. The response quality is what degraded. The opposite failure, a good response with a sloppy classification, was worse for us, because we had code that acted on the classification directly.

Splitting the work avoided this because each call had one job and one output format:

  • The classifier prompt is dominated by labeled examples: representative messages with their correct category. Small models pattern-match examples reliably even when they drift on generalized rules.
  • The responder prompt is dominated by formatting rules and per-category playbooks. It assumes the routing decision is already made, since the classifier’s label arrives as part of the per-turn context, and only has to follow the playbook for that one label.
  • Each prompt changes independently. A new classifier example does not risk breaking a responder formatting rule, and a new responder rule does not risk breaking a classifier example.
Classifier output format:

Respond with exactly: CATEGORY: reason
CATEGORY is one of nine fixed labels.
The reason is a brief phrase, under 25 words.
Do not add a greeting before the category.
Do not wrap the response in quotes, JSON, or markdown.

Example: ROUTINE_REQUEST: Caller is asking about payment options

Making the extra latency affordable

Two calls instead of one adds latency, so we ran the classifier and a knowledge base search concurrently instead of in sequence. The classifier takes about 0.6 seconds. The knowledge base search, a vector and keyword lookup, takes about 0.7 seconds. Run one after the other, that is 1.3 seconds before the responder call even starts. Run in parallel, it is the slower of the two, about 0.7 seconds.

On the roughly 80 percent of turns classified as a routine request, the knowledge base result is needed anyway, so the parallel run costs nothing extra beyond the 0.7 seconds either call would have taken alone. On other labels, the knowledge base task is cancelled once the classification is known; the wasted lookup costs a fraction of a cent and adds no latency the caller notices.

The reliability gain was worth the added latency. A wrong response is a bad caller experience. A wrong classification breaks code. An extra half second of thinking time is just thinking time, and it is largely hidden by running two things at once instead of one after another.

What changed a few weeks later

Here is the part worth being honest about. A few weeks after we shipped the two-call design, a client review of this same voice agent came back with a low score. Not because of the classifier specifically, but because the whole pipeline it belonged to, the classifier plus a routing table plus a set of canned responses plus a separate sub-agent for one complex flow, made the agent sound like it was reading from a script instead of holding a conversation.

The fix for that was a much bigger redesign: one LLM call per turn, one prompt file, no pre-classification, no canned short-circuits, no sub-agent. The audit trail that the classifier’s label used to feed moved to an evaluation step that runs after the call ends instead of a decision the caller has to wait on. We wrote about that redesign, what got deleted, what stayed, and how we kept it auditable without a live classifier, in when to build a custom voice agent versus a platform.

Once that redesign moved the audit trail off the caller’s clock, the classifier’s output had nowhere left to go. Nothing downstream needed a machine-readable label anymore. That is a different question than the one this post answers. This post is about whether one LLM call can reliably do two jobs at once; the answer on this small model was no. The later redesign is about whether you need the second job at all; the answer, once the audit trail moved elsewhere, was also no. Both conclusions are correct for the question they answer.

Hardening still worth doing

A few items stayed on the list even after the classifier was retired from this particular system, because the underlying lesson applies to every prompt we write for a small model:

  • A rule budget. Every rule added to a prompt competes with every other rule for the model’s attention. The discipline that kept both prompts working was simple: add a rule, remove a rule, or move it into code.
  • A drift eval. Picking a handful of hard format rules and replaying them against a sample of real calls on every model update would catch silent drift before a caller does.
  • Documenting the rule-budget convention at the top of the prompt file itself, not just in engineering memory, so the next person maintaining it inherits the discipline.

Key takeaways

  • A small, cost-optimized LLM asked to do two jobs in one call will degrade on one of them once the combined prompt gets long enough. On this model, the cliff started around 200 to 400 lines.
  • Structured output constrains the shape of a response, not its content. It does not fix content-level drift.
  • A classifier’s output is often a routing signal that other code depends on, not just metadata for a response. Treat it with the weight of the guardrails it feeds.
  • Splitting a prompt and deleting a prompt are different decisions that can both be correct. One is about whether a model can do two jobs at once. The other is about whether you still need the second job.

What this means if you are an IT services firm

Ask your team what job each LLM call in your voice agent is doing, and whether anyone has tested what happens when one call is asked to do two of those jobs at once. If a single prompt is quietly growing past a few hundred lines while also producing a machine-readable output your code depends on, that is worth a deliberate test before it becomes a production surprise. This kind of prompt-level reliability work is part of what we do behind IT services firms, under their brand.

Related questions
Why not use a bigger model instead of splitting the prompt?
Cost. A larger model would likely have handled the combined prompt without dropping rules, at roughly three times the per-call price. The budget for this deployment did not justify that jump for a reliability problem a second small-model call could fix for less. The decision is worth revisiting if model pricing drops or call volume grows enough that engineering complexity costs more than the extra tokens.
Why not force the combined call to return structured output instead of free text?
Structured output constrains the shape of a response, not its content. The model can return a syntactically valid object whose response field still breaks a formatting rule, like reading a phone number in digit form instead of the spoken form we require. The drift we saw was content-level, and a JSON schema does not fix content-level drift.
Does deleting the classifier later mean splitting the prompt was the wrong call?
No, and this is the part worth sitting with. Splitting the prompt fixed a real, measurable reliability problem: a small model was silently dropping hard format rules on about 1 in 30 turns. That fix worked and stayed in production for weeks. The classifier was deleted later for a different reason: a client review found the entire layered pipeline, classifier, routing table, canned responses, and a sub-agent, sounded robotic, and a redesign moved the audit trail to a step that runs after the call ends instead of a live classification the caller has to wait on. Once that redesign removed the need for a live routing signal, the classifier's job disappeared, not because it was unreliable, but because nothing downstream needed its output anymore. We wrote up that full redesign separately.
How do you test for prompt drift without rerunning every test on every release?
A focused regression harness covering the known failure patterns runs in under 30 seconds and gates every commit. A larger production-call replay corpus, real caller messages replayed against the current prompt and model, runs before every deploy and is the one synthetic tests cannot substitute for. Anything that improves a synthetic test but regresses a real-call replay is not an improvement.
Has anyone measured exactly where a small model's instruction-following starts to fail?
Not that we have found in a public benchmark with sharp thresholds for this model class. Our own empirical read: drift started to show around 200 lines of combined instructions on a single call and became routine past 350 lines. Two separate prompts of similar size, on separate calls, behaved reliably. This is an observation from one production system, not a controlled study, and a rigorous public benchmark would be useful.

Reading this because a client asked for voice AI? That is the conversation we are built for. What taritas does for partners.

More from Build decisions
PROJECT taritas.com/blog
DWG POST-21
REV 1.0
DATE 2026-07-13