GenAI Consulting

Query Rewriting in Production RAG: How to Expand, Decompose, and Normalize Without Hurting Retrieval

GenAI Consulting23 min read
Query Rewriting in Production RAG: How to Expand, Decompose, and Normalize Without Hurting Retrieval

A team I worked with had a familiar complaint: “retrieval quality is inconsistent.” On good days, their internal support copilot found exactly the right policy, incident note, or architecture runbook. On bad days, it missed obviously relevant documents that a human could find in seconds.

Their first instinct was the same one many teams have: upgrade embeddings, add a reranker, and increase top-k. Those changes helped some queries, but the pattern persisted. The failures were strangely clustered. Short keyword searches worked. Long natural-language questions sometimes worked. But entity-heavy requests, underspecified references, cross-domain questions, and “do X compared to Y” prompts were unreliable. Worse, the failures were silent: the system still returned documents, just not the right ones.

When we traced the misses back through the retrieval logs, the root cause was not primarily the vector index. It was the query itself.

Users were asking things like:

  • “how did we handle the eu data residency exception for the billing exporter?”
  • “compare the old authz service rollout checklist with what platform requires now”
  • “what’s the policy for contractors viewing prod dashboards through vpn?”
  • “show me docs for incident 1847 and the follow-up change around kafka consumer lag alarms”

These are not single, clean retrieval queries. They are mixtures of shorthand, private jargon, incomplete references, temporal comparisons, entity aliases, and sometimes multiple sub-questions glued together. A retriever is only as good as the search string or embedding representation it receives. If that representation collapses the user’s meaning, retrieval degrades before ranking even starts.

So the team added an LLM-based query rewriting step. And for about two weeks, dashboards looked better.

Then the next class of bugs arrived.

The rewriting model helpfully expanded “authz” to “authorization,” but also turned a precise internal service name into a generic term, reducing precision. It rewrote “prod dashboards” into “production monitoring dashboards,” accidentally biasing retrieval toward observability docs instead of access policies. It decomposed some multi-part questions into subqueries, but dropped key constraints like “contractors” or “through vpn.” In one case it converted “incident 1847” into “incident response procedures,” because it assumed the number was not meaningful. The pipeline looked smarter, but it had introduced a new hidden failure surface.

This is the central production lesson: query rewriting can improve RAG dramatically, but only if you treat it as a controlled retrieval component with explicit objectives, policies, and evaluations. If you treat it as a magical “make the query better” prompt, it will silently hurt relevance, permissions, latency, and trust.

What follows is a practical framework for designing query rewriting in production RAG systems: when to normalize, expand, or decompose; how to preserve user intent and authorization boundaries; how to evaluate rewrites separately from retrieval; and how to keep the system fast and debuggable.

The pattern: not all “bad queries” are the same

Teams often lump all retrieval misses together, but query issues usually fall into a few distinct categories. If you do not separate them, you end up using one rewriting strategy for problems that need different treatment.

1. Normalization problems

These queries mean the right thing but are expressed in inconsistent ways:

  • abbreviations: “authz,” “rbac,” “sso”
  • aliases: “billing exporter” vs service’s official name
  • formatting differences: “incident-1847” vs “1847”
  • tense/plural/casing issues
  • noisy chat phrasing: “can you tell me where I can find…”

The objective here is not to add meaning. It is to standardize representation while preserving all constraints.

2. Expansion problems

The query is too sparse for the retrieval method or corpus vocabulary:

  • “vpn dashboard access contractors”
  • “eu residency exception”
  • “kafka lag alarms”

Here you may need to add synonyms, canonical names, adjacent terminology, or related phrases used by the corpus. The risk is drift: expansion can improve recall while lowering precision.

3. Decomposition problems

The user is asking multiple retrieval questions at once:

  • “compare the old authz service rollout checklist with what platform requires now”
  • “show me docs for incident 1847 and the follow-up change around kafka consumer lag alarms”

These often need multiple subqueries plus aggregation. Trying to retrieve everything with one embedding or one keyword query tends to underserve one or more parts.

4. Disambiguation problems

The query could mean several things:

  • “gateway policy” could be API gateway, network gateway, or org approval gate
  • “mercury” could be a project, a service, or a codename

A rewrite is dangerous if the system guesses wrong. In these cases, the right action may be clarification or broad retrieval with diversified results.

5. Constraint preservation problems

The user included critical filters that many rewriting prompts accidentally weaken:

  • time: “current,” “old,” “after 2023 migration”
  • audience: “contractors,” “SRE only,” “finance team”
  • environment: “prod,” “staging,” “eu region”
  • action type: “policy,” “runbook,” “postmortem,” “code change”

These are often more important than the head terms. A rewrite that improves fluency but drops constraints is a retrieval regression.

The first production design choice is to classify which of these situations you are dealing with before you rewrite.

Why the naive approach fails

The most common naive implementation is a single prompt like: “Rewrite the user’s question to improve document retrieval.” It feels sensible and demos well. In production it fails for structural reasons.

It optimizes for plausibility, not retrieval utility

LLMs are good at producing polished paraphrases. But the best retrieval query is often not the most natural sentence. For lexical retrieval, you may want exact tokens, aliases, IDs, and awkward keyword bundles. For dense retrieval, you may want canonical terminology and disambiguated entities. A generic rewrite prompt has no grounded objective unless you define one.

It tends to generalize away specificity

Language models often replace narrow internal terms with broad public equivalents. That sounds semantically similar to a human, but broadening a term can swamp the result set. “Billing exporter” becoming “billing data export system” might ruin matches if the docs consistently use the exact service name.

It drops constraints unless forced not to

Audience, region, environment, date range, and document-type hints are semantically lightweight but operationally critical. A rewrite model often compresses them or moves them into less retrievable phrasing.

It mixes query transformation with access control

If your rewrite expands using terms from documents the user cannot access, you can create subtle information leaks in logs, prompts, or downstream behavior. Even when the final retrieval is permission-filtered, the rewrite stage itself may have crossed a boundary.

It hides error attribution

When retrieval worsens, is the problem the rewrite, the index, the reranker, or the answer synthesis? If you do not log original query, rewritten variants, trigger reason, and per-variant retrieval outcomes, you cannot debug the system.

It adds nontrivial latency and cost

A rewrite call before every retrieval call is easy to justify in a prototype. In production, an extra model hop on 100% of traffic is often one of the highest ROI cuts available. Many queries do not benefit from rewriting at all.

This is why mature systems stop thinking in terms of “a rewrite step” and instead implement a query transformation layer with typed operations, policies, and measurements.

A better approach: a policy-driven query transformation layer

The better pattern is to separate transformation types, gate when each runs, and evaluate them independently. Conceptually, the architecture looks like this:

  1. Intent-preserving preprocessing

    • strip conversational filler
    • normalize punctuation/whitespace/casing where safe
    • detect obvious IDs, timestamps, environment tags, and document-type constraints
    • preserve exact spans for entities and filters
  2. Query analysis/classification

    • determine if the query is simple, sparse, compound, ambiguous, or entity-heavy
    • estimate whether rewrite is likely to help
    • identify protected constraints that must survive any transformation
  3. Transformation policy engine

    • normalize only
    • expand with synonyms/aliases
    • decompose into subqueries
    • ask clarifying question
    • skip rewrite entirely
  4. Multi-strategy retrieval

    • run original query alongside transformed variants selectively
    • use hybrid search: lexical + dense
    • optionally use metadata filtering from extracted constraints
  5. Reranking and result fusion

    • score results from original and variant queries
    • maintain provenance of which query produced each hit
    • prefer results satisfying preserved constraints
  6. Evaluation and monitoring

    • rewrite quality metrics
    • retrieval metrics per query class
    • latency/cost by strategy
    • drift and failure alerts

The critical design principle is this: the original query remains a first-class retrieval signal. Do not assume the rewrite is superior. In most production systems, the safest pattern is retrieve on both original and transformed queries, then fuse and rerank.

When to normalize, expand, decompose, or do nothing

A useful way to think about transformation is as a decision matrix.

Normalize when the query has high intent clarity but inconsistent expression

Use normalization for:

  • acronym expansion when mappings are stable and internal
  • standardizing service aliases to canonical IDs
  • preserving document IDs, incident numbers, ticket numbers
  • converting chatty language to concise keywords without removing constraints

Examples:

  • “can you find the pm for svc authz in prod”
    • normalize to preserve svc authz, prod, and pm while mapping known aliases if helpful
  • “incident-1847 postmortem”
    • preserve exact ID, maybe add normalized alternate token incident 1847

Normalization should be mostly deterministic where possible. Do not spend an LLM call on what a rule-based normalizer or alias dictionary can do reliably.

Expand when recall is low because the corpus uses different terminology

Use expansion for:

  • sparse keyword queries
  • domains with heavy synonymy
  • corpora with mixed official and colloquial terms
  • multilingual or acronym-heavy environments

Expansion strategies:

  • add canonical names plus aliases
  • add singular/plural variants
  • add known neighboring terms from your taxonomy
  • add exact internal tokens rather than prose

Example:

  • “eu residency exception”
    • expansion might add data residency waiver, regional storage exception, and the internal policy codename if known

Expansion is dangerous if unconstrained. Favor bounded expansions from curated dictionaries, entity catalogs, or corpus-mined terms over freeform LLM creativity.

Decompose when the question contains multiple retrieval intents

Use decomposition for:

  • compare/contrast requests
  • temporal deltas (“old vs now”)
  • reference plus consequence (“incident X and follow-up change”)
  • broad questions mixing policy + implementation + ownership

Example decomposition:

Original: “compare the old authz service rollout checklist with what platform requires now”

Subqueries:

  1. authz service rollout checklist old
  2. current platform rollout requirements
  3. platform policy rollout checklist current

Then aggregate by:

  • retrieving top docs per subquery
  • extracting structured comparison points
  • surfacing confidence and source coverage

Decomposition is most useful when your answer step can reason across multiple result groups. If your downstream application only displays documents and not synthesis, decomposition may create more complexity than benefit.

Do nothing when the query is already specific and high quality

Many production teams over-rewrite because the tooling exists. If the user query already contains exact identifiers, good constraints, and stable terminology, transforming it may only create opportunities for damage.

Example:

  • SEV2-2024-11 kafka lag alert tuning follow-up

This is likely better sent directly into hybrid retrieval with exact-match boosting than paraphrased by an LLM.

Ask a clarifying question when ambiguity is material

If the query could map to multiple entities or domains and a wrong guess would mislead the user, clarification is the right move.

Example:

  • “gateway policy”

Possible response:

  • “Do you mean API gateway access policy, network gateway configuration policy, or release approval gate policy?”

This costs a turn, but for some high-stakes workflows it is cheaper than confidently retrieving irrelevant material.

Preserve user intent and permissions as hard constraints

The most overlooked production issue in query rewriting is not relevance. It is control.

Intent preservation should be explicit, not implied

A robust rewrite spec should force the system to identify and preserve:

  • entities: service names, project codenames, people, teams
  • IDs: incident numbers, ticket IDs, doc IDs
  • filters: environment, region, audience, time
  • task type: compare, summarize, find policy, find procedure
  • temporal relationships: old/current/before/after

If you use an LLM to transform queries, have it emit structure first, not just text. For example:

json
{ "task": "compare", "entities": ["authz service"], "constraints": { "time_a": "old", "time_b": "current", "domain": "platform rollout requirements" }, "must_preserve": ["authz service", "old", "current", "platform"], "transforms": { "normalized_query": "authz service rollout checklist old compare with current platform rollout requirements", "subqueries": [ "authz service rollout checklist old", "platform rollout requirements current" ] } }

You do not have to expose this structure to users, but it makes the pipeline inspectable and testable.

Permissions must shape rewrite sources

If query expansion uses a knowledge source, that source must be authorization-aware. Common unsafe patterns include:

  • using global document terms to expand queries before permission filtering
  • allowing the LLM to see snippets or metadata from inaccessible documents during disambiguation
  • logging rewritten queries that include sensitive canonical names inferred from restricted corpora

Safer patterns:

  • use a curated enterprise glossary approved for all users, or per-tenant/per-role glossaries
  • scope alias expansion to entities the user is allowed to know about
  • keep rewrite generation blind to restricted document content unless the user is authorized
  • sanitize logs and prompts for expansions derived from sensitive taxonomies

An easy rule of thumb: the rewrite layer should never know more than the user is allowed to know.

The original query is part of the audit trail

For compliance-sensitive systems, keep the original query, transformation decision, resulting variants, and retrieval provenance. If a user challenges a result or a miss, you need to reconstruct what happened.

Practical architecture for production

Here is a reference architecture that works well for many internal RAG deployments.

1. Deterministic front-end normalization

Run cheap, deterministic operations first:

  • lowercase where safe
  • normalize punctuation and whitespace
  • extract obvious IDs via regexes
  • detect environment tags (prod, staging, dev)
  • map stable aliases from dictionary tables
  • strip filler phrases (can you show me, where can I find)

This layer should be fast, testable, and explainable.

2. Query classifier

Use either a compact model or a rules-plus-model hybrid to assign labels such as:

  • simple_exact
  • sparse
  • compound_compare
  • entity_ambiguous
  • id_lookup
  • constraint_heavy

This classifier is not trying to understand everything. It just determines whether transformation is likely to help and which types are safe.

Good candidates here are small, low-latency models or even non-LLM heuristics. You do not need your most capable model to decide that a query contains “compare X with Y” or an incident ID.

3. Policy engine

Codify decisions such as:

  • id_lookup -> no rewrite, exact-match retrieval + metadata filters
  • simple_exact -> retrieve original only
  • sparse -> original + bounded expansion
  • compound_compare -> decomposition + original
  • entity_ambiguous -> clarify if confidence below threshold
  • constraint_heavy -> rewrite only with strict constraint-preservation checks

This is where teams often discover that “rewrite everything” becomes “rewrite maybe 20–40% of traffic.” That is usually a good sign.

4. Transformation generators

Use different mechanisms for different jobs:

  • rules/dictionaries for normalization
  • taxonomy/entity catalog for expansions
  • LLM for decomposition and hard cases

Do not use one method for all transformations just because it is convenient.

5. Retrieval executor

Run hybrid retrieval across:

  • original query
  • normalized query
  • expanded query
  • decomposed subqueries when enabled

Then perform result fusion. Common strategies:

  • reciprocal rank fusion across retrieval variants
  • weighted blending favoring original query matches
  • per-variant caps to avoid one noisy expansion dominating

6. Reranker

A reranker often matters more once you add multiple transformed variants because candidate quality becomes more heterogeneous. The reranker should see:

  • original user query
  • candidate document
  • optionally the transformation provenance

In many cases, reranking against the original user query is a powerful corrective against rewrite drift.

7. Guardrails and fallback

If transformation confidence is low or preservation checks fail:

  • skip transformed retrieval
  • fall back to original-only retrieval
  • optionally ask a clarifying question

A safe fallback path is non-negotiable.

How to evaluate rewrite quality separately from retrieval quality

This is the part many teams skip, and it is why rewrite systems often regress silently.

You need at least two layers of evaluation:

  1. Rewrite quality evals: Did the transformation preserve intent and produce a useful search variant?
  2. Retrieval impact evals: Did using the transformed query improve retrieval outcomes?

Do not collapse these into one metric.

Rewrite quality evals

Build a labeled set of representative production queries covering the classes above. For each, annotate:

  • key entities that must be preserved
  • constraints that must be preserved
  • whether rewrite should be skipped, normalized, expanded, decomposed, or clarified
  • acceptable expansions if any
  • unacceptable drifts

Then score transformations on dimensions like:

  • constraint preservation rate: percentage of required constraints retained
  • entity preservation rate: exact or alias-safe entity retention
  • operation correctness: chosen action matches annotation
  • decomposition completeness: all sub-intents retained
  • unwarranted specificity/generalization: whether the rewrite guessed facts not in the query or broadened too much

You can use LLM-as-judge for parts of this, but keep some deterministic checks:

  • string or alias match for IDs/entities
  • metadata filter retention
  • forbidden-term insertion checks

A transformation that fails preservation should be considered invalid, even if retrieval sometimes looks better on aggregate.

Retrieval impact evals

For the same query set, measure retrieval on:

  • original only
  • rewritten only
  • original + rewritten fusion
  • decomposed strategy

Use standard IR metrics where possible:

  • Recall@k
  • MRR / NDCG@k
  • success@k for presence of at least one relevant source
  • coverage across sub-intents for decomposed queries

But add business-facing diagnostics:

  • miss rate on known-ID lookups
  • wrong-domain retrieval rate n- constraint-violation rate in retrieved top-k
  • clarification-needed but skipped rate

The key comparative question is not “is rewriting good?” It is:

  • For which query classes does each transformation improve retrieval?
  • Where does it harm?
  • Is original+rewrite fusion more robust than either alone?

In production, you will usually find that the average uplift hides class-specific regressions. That is why routing by query class matters.

Online evaluation and observability

Offline evals are necessary but not sufficient. Add online instrumentation for:

  • rewrite trigger rates by class
  • retrieval click-through or citation-open rate by strategy
  • answer acceptance / deflection rate by strategy
  • latency p50/p95 by strategy
  • token and model cost per request
  • “silent degradation” indicators, such as users reformulating the same question within a short window

A very useful signal is query reformulation rate after answer view. If users often re-ask with more explicit terms after rewritten retrieval, your rewrite layer may be obscuring their intent.

Model and tool choices: where to use LLMs and where not to

A production query rewriting stack usually benefits from mixing deterministic and model-based components.

Rule-based and dictionary-based tools

Best for:

  • exact alias normalization
  • acronym expansion from trusted enterprise glossary
  • ID preservation/extraction
  • document-type and environment tag parsing

Pros:

  • cheap
  • fast
  • stable
  • easy to audit

Cons:

  • limited coverage
  • requires maintenance

Small classification models or heuristics

Best for:

  • query type routing
  • ambiguity detection
  • deciding whether to decompose

Pros:

  • low latency
  • low cost
  • often good enough

Cons:

  • some edge-case brittleness

LLMs

Best for:

  • decomposition of compound questions
  • extracting structured constraints from messy language
  • generating bounded expansions when dictionaries are incomplete
  • deciding when clarification is needed in nuanced cases

Pros:

  • flexible
  • handles messy real-world language

Cons:

  • can hallucinate terms
  • may drop constraints
  • higher latency and cost
  • harder to debug

A sensible default is:

  • deterministic normalization first
  • lightweight routing/classification next
  • LLM transformation only for traffic classes where offline evals show meaningful uplift

Cost and latency tradeoffs

Query rewriting often looks inexpensive because each call is small. At scale, it is not.

Suppose your baseline RAG request is:

  • 1 hybrid retrieval call
  • 1 reranking call
  • 1 answer generation call

Now add:

  • 1 query classification model call
  • 1 rewrite model call
  • retrieval on original + rewrite + 2 subqueries

You have materially increased both latency and infrastructure load. In high-volume systems, the retrieval fan-out may be more expensive than the model call itself.

Practical controls:

Gate aggressively

Do not rewrite all traffic. Route only the classes that benefit.

Cap expansion breadth

Limit number of expansion terms and subqueries. A decomposition into six subqueries may improve recall but destroy tail latency.

Use parallel retrieval

If you retrieve original and transformed variants, run them in parallel and cap each candidate pool.

Cache deterministic and repeated transforms

Internal corpora often have repeated query patterns. Cache normalization and even LLM decompositions for frequent forms where appropriate.

Tier models by task

Use the cheapest reliable option for each stage. Query classification rarely needs your best model. Decomposition may.

Budget by query class

It can be worth spending more latency on compound research-style queries than on known-ID lookups. A single global pipeline is usually economically suboptimal.

Failure modes you should expect

A battle-tested rewrite layer is built around anticipated failures.

1. Semantic drift

The rewrite changes the topic subtly enough to look reasonable but enough to hurt retrieval.

Mitigation:

  • preserve original query retrieval path
  • rerank against original query
  • add drift evals and human review samples

2. Constraint loss

The rewrite drops time, environment, or audience qualifiers.

Mitigation:

  • structured extraction of constraints
  • deterministic preservation checks
  • fail closed: skip rewrite if constraints are lost

3. Over-expansion

The system adds too many synonyms and broadens retrieval into irrelevant domains.

Mitigation:

  • bounded, curated expansions
  • weighted fusion favoring exact matches
  • per-term expansion budgets

4. Bad decomposition

Subqueries split the problem incorrectly or omit a sub-intent.

Mitigation:

  • evaluate decomposition completeness separately
  • cap decomposition to clear patterns like compare/and/follow-up
  • keep original query retrieval in parallel

5. Authorization leakage

Expansion terms or clarifications reveal restricted entities.

Mitigation:

  • authorization-aware glossaries
  • do not use restricted corpus text in rewrite stage
  • review logging and tracing outputs

6. Latency blowups

Transformations increase fan-out and hurt p95.

Mitigation:

  • route selectively
  • parallelize retrieval
  • cap subqueries and candidate pools
  • add timeout-based fallback to original retrieval only

7. Hidden regressions after corpus changes

A new terminology standard or reorg changes what “good expansion” looks like.

Mitigation:

  • refresh eval sets with recent traffic
  • maintain class-level dashboards
  • revalidate dictionary expansions periodically

Implementation details that matter more than teams expect

A few concrete practices make an outsized difference.

Keep transformations inspectable

Store structured transformation records:

  • original query
  • detected class
  • preserved entities/constraints
  • chosen action
  • generated variants
  • confidence
  • retrieval outcomes per variant

When a stakeholder asks “why did it miss?”, this record is what turns a guessing session into an engineering conversation.

Use provenance in fusion and reranking

Track which variant retrieved each document. This lets you answer questions like:

  • Are expansions driving most useful recall gains?
  • Which rewrite pattern causes noisy candidates?
  • Should original-query hits get a ranking boost?

Build no-rewrite baselines into every experiment

Many teams compare rewrite v1 to rewrite v2, but forget to compare both to original-only retrieval. Keep the baseline visible.

Treat IDs and exact tokens as sacred

Incident numbers, ticket IDs, service IDs, policy names, and code names should almost never be paraphrased away. Usually they should be copied verbatim into all variants.

Separate user-facing clarification from internal expansion

If ambiguity exists, sometimes you can broaden retrieval internally without forcing a clarification turn. Other times clarification is required. Do not conflate these two mechanisms. Use clarification when a wrong assumption would materially mislead the answer.

Start with a narrow scope

Do not begin by solving all query transformation problems. A high-ROI starting point is:

  • deterministic normalization
  • bounded expansion for known acronyms/aliases
  • decomposition only for explicit compare/and patterns
  • original+variant fusion
  • rigorous logging

That will get you most of the value with much less risk than a fully generative rewrite system.

A simple rollout plan

If you are implementing this in an existing RAG system, a phased rollout works best.

Phase 1: Measure before changing behavior

Add logging and offline replay:

  • collect query classes
  • identify miss clusters
  • build a labeled eval set
  • quantify baseline by class

Phase 2: Deterministic normalization only

Ship alias dictionaries, ID extraction, and filter parsing. Measure uplift on exact-match and entity-heavy queries.

Phase 3: Bounded expansion on selected classes

Enable original+expanded retrieval for sparse queries only. Monitor recall gains versus wrong-domain retrieval.

Phase 4: Decomposition for explicit compound queries

Start with compare and “X and Y” patterns. Keep candidate caps low and rerank against original query.

Phase 5: Add LLM assistance where the data justifies it

Use an LLM for hard messy queries, but only where offline and online evidence shows meaningful net benefit.

At each phase, keep a kill switch and class-based rollback option.

What good looks like

A mature production query rewriting layer does not try to sound intelligent. It tries to be boringly effective.

It preserves what the user actually said. It knows when not to interfere. It routes different query shapes to different strategies. It treats expansions as hypotheses, not truth. It keeps the original query alive through retrieval and reranking. It respects permission boundaries. And it is evaluated as its own subsystem, not hidden inside aggregate RAG metrics.

If there is one operational takeaway to remember, it is this: rewriting should be accountable for retrieval outcomes, not just linguistic elegance. A rewrite that reads better but retrieves worse is a bug. A decomposition that increases answer confidence while doubling p95 might still be the wrong choice for your highest-volume path. And a normalization layer that preserves IDs and aliases exactly may outperform a more sophisticated generative approach on a surprisingly large share of traffic.

The temptation in RAG is always to add more model intelligence earlier in the pipeline. Sometimes that is right. But query transformation is one of those areas where production maturity usually means adding more policy, more structure, and more measurement.

That is how you expand, decompose, and normalize queries without hurting retrieval.