AI agents
Key points

Key points

  1. 1Run trimming as an ordered pass (dedupe, score cut, tier cut) and only then enforce the token cap, so the cap cuts the cheapest material rather than the best.
  2. 2Redundant chunks crowd out coverage: a swarm of near-duplicates fills the top of the ranking and leaves little room for other sections.
  3. 3Every trimming rule has two prices, tokens saved and relevant chunks removed, and both must be measured on a held-out labeled set before the rule ships.
  4. 4Keep a rule only when its token saving is large relative to the recall it costs, and re-measure when the corpus or the retriever changes.

Why the cap should not be the first cut

Most RAG pipelines retrieve a generous candidate list, assemble a prompt, and then let a token cap trim whatever does not fit. That order is backwards. The cap preserves whatever happened to rank highest, and the highest-ranked material is exactly what near-duplicates tend to dominate.

Duplicate chunks are usually produced upstream, by chunking. Overlapping windows exist to preserve continuity, but they increase the number of stored chunks and introduce redundancy into the indexed corpus, as one study of chunk filtering notes in its analysis of chunking redundancy. Multiple splitters firing on the same document can yield a paragraph chunk, a token-window chunk that overlaps it, and a heading chunk that wraps both, all embedding into nearly the same neighborhood, as one practitioner account of chunk rules describes the crowd-out effect. If six of your top ten are cousins of one section, you have four slots for the rest of the corpus. The retriever looks confident and coverage is poor.

Ordering matters for a second reason. A cap discards by tokens, not by quality. Reordering the pipeline so trimming happens first means each later rule works on a cleaner candidate set, and the cap that finally fires is removing genuinely low-value material. The cap becomes a safety limit instead of a de facto relevance filter.

There is also a placement cost worth fixing before any trimming. Document content belongs in the user message, not baked into the system prompt, because a system message that changes with every retrieval is a prefix that never repeats and nothing can be cached against it as this budgeting walkthrough shows. Get that split right first, then trim.

The three rules in order

The trimming pass has three rules applied in sequence, each cheaper to evaluate than the next:

  1. Dedupe: collapse near-identical chunks, keeping the highest-scoring representative of each cluster.
  2. Score cut: drop chunks below a relevance threshold, absolute or relative to the top score.
  3. Tier cut: from each source tier (primary docs, secondary docs, transcripts, web), keep only the best N chunks, so no single tier monopolizes the window.
  4. Cap: enforce the token limit on what remains.

The order is deliberate. Dedupe first because duplicates distort any threshold you set afterwards. A score cut second because it is a per-chunk decision that does not need global knowledge. A tier cut third because it is the only rule that considers provenance, and it should operate on a set that is already clean and relevant.

def trim(chunks, cfg):
    chunks = dedupe(chunks, cfg.similarity_threshold)   # 1. near-duplicates
    chunks = [c for c in chunks if c.score >= cfg.score_floor]  # 2. relevance
    chunks = tier_cut(chunks, cfg.per_tier_keep)        # 3. provenance
    return cap(chunks, cfg.token_budget)                # 4. hard limit

Each rule takes one configuration value, which is the knob your measurement will tune.

Rule one: dedupe near-identical chunks

Dedupe compares chunks against each other rather than against the query. The practical choice is embedding similarity (cosine distance on the chunk vectors you already store) or a cheap lexical overlap measure such as shingle Jaccard. Keep the representative with the higher relevance score and record the others as suppressions.

Two decisions matter. The similarity threshold controls how aggressive the collapse is; too low and you merge chunks that carry distinct facts, too high and you leave the swarm intact. The representative choice controls what survives; keeping the highest-scoring member biases toward the query, keeping the first biases toward document order.

Dedupe is the one rule where the recall cost is usually near zero, because a suppressed duplicate almost never contains information absent from its representative. The exception is overlap chunks that straddle a boundary. If chunk A ends mid-fact and chunk B begins it, collapsing them can lose the join, so compare on the merged span where your chunker overlaps.

The saving is easy to state. If a candidate set of 40 chunks contains 12 near-duplicates averaging 100 tokens, dedupe removes roughly 1,200 tokens before the cap ever runs. Some of that saving would have been taken by the cap anyway; the difference is that dedupe removes the redundant copies and keeps the diverse ones.

Rule two: the score cut

The score cut removes chunks below a relevance threshold. The core tradeoff is the classic precision and recall one: lowering the threshold captures more relevant chunks but pulls in more noise, raising it gives cleaner results but misses relevant documents as this evaluation primer puts it.

Set the threshold empirically, not by taste. Two forms work:

  • Absolute: drop anything below score s. Simple and auditable, but scores are not comparable across queries.
  • Relative: drop anything below alpha times the top score, plus a minimum floor so a uniformly weak result set does not survive on a single lucky chunk.

The relative form usually wins in production because retrieval scores drift with query type. A definitional query may produce a strong cluster; a multi-hop query may produce a flat, weak one. Cost-aware routing work shows that anchoring every query to the same retrieval depth wastes budget on simple questions and under-serves hard ones, and that a per-query choice beats a static one on both tokens and latency in the CA-RAG results. A relative score cut is the cheap version of the same idea.

The recall risk here is real. A chunk that is essential but lexically dissimilar to the query can score below the cut. Measure it rather than assuming.

Rule three: the tier cut

The tier cut keeps the best chunks from each source tier rather than the best chunks overall. Tiers might be primary documentation, support tickets, transcripts, and third-party pages, each carrying a reliability weight.

Why keep a tier cut at all if you already have a score cut? Because scoring models are imperfect and provenance is a prior. If your score floor lets eleven chunks from a single verbose tier through, you have spent the budget on one voice. A tier cut that keeps, say, the top three per tier guarantees diversity and stops one source from crowding out another.

The cost is that the tier cut can discard a chunk that the score cut rated highly, purely on provenance. That is the point, but it is also the rule most likely to quietly hurt recall on queries that genuinely need depth from one tier. Measure per-tier recall loss, not just aggregate.

Watch for a mismatch between tiers and query intent. A query about an internal policy should not reserve two slots for third-party web results. Consider letting the tier cut take per-tier allowances that vary by query class, which is the same per-query idea the routing literature applies to retrieval depth in the MDPI version of the CA-RAG study.

How to measure a rule's cost and saving

You need three assets before you tune anything: a held-out labeled set of queries, a gold label of relevant chunks per query, and a harness that runs the full pipeline with and without each rule.

The labeled set is the expensive part and the one teams skip. Chunk-level recall requires knowing which chunks contain the answer: recall is the number of relevant chunks retrieved divided by the total number of chunks containing the answer per this metric explanation. Build it with human annotation plus an LLM-as-judge first pass, and hold out queries the embedder and chunker tuning never saw.

For each rule, compute four numbers on the held-out set:

MeasureDefinitionWhy it matters
Tokens savedMean tokens before minus after, per queryThe benefit side of the ledger
Chunks removedCount of chunks dropped, per querySanity check on aggressiveness
Recall lostGold relevant chunks removed divided by gold relevant chunks availableThe cost side of the ledger
Queries brokenQueries whose final answer set loses its only gold chunkThe tail risk that hurts users

The decision rule is a ratio, not an absolute. Compute tokens saved per relevant chunk lost. Keep the rule when that ratio is high relative to your cost of context: if a thousand tokens cost you very little and a missed chunk costs a wrong answer, the bar rises. Prefer rules that save many tokens and break no queries; scrutinize any rule that breaks queries even if its average recall loss looks small, because averages hide the queries that fail outright.

Context precision, which weighs retrieved chunks by relevance and rank position, is a useful companion metric because it captures whether the good chunks sit near the top of what survives trimming as Galileo's documentation describes. A rule can hold recall steady while pushing relevant chunks to worse positions, and the model's answer can still degrade.

Which rules earn their place

A worked example makes the decision concrete. Suppose a held-out set of 120 queries retrieves a mean of 38 chunks at 95 tokens each, about 3,600 tokens, against a 1,500-token cap.

RuleMean tokens savedMean gold chunks lostQueries brokenVerdict
Dedupe at 0.92 similarity1,0500.2 of 61 of 120Keep
Score floor 0.259000.5 of 66 of 120Tune the floor
Tier cut, 3 per tier3001.1 of 614 of 120Per-query tiers only
Cap only (no trimming)n/a1.8 of 622 of 120Baseline to beat

The shape of the result is what matters, not the specific numbers, which belong to your corpus. Dedupe characteristically pays for itself: large saving, near-zero loss. The score cut is the tunable middle, where you sweep the threshold and pick the point where queries broken stays at zero. The tier cut is the risky one, and it is the rule most likely to justify a per-query allowance instead of a global one.

Two operational habits make this stick. First, re-measure when the corpus, chunker, embedder, or retriever changes; a threshold tuned against one embedding model is not portable to the next. Second, log the full trimming trace, including what was suppressed and why, so that a bad answer can be traced back to the rule that removed the answer.

The later stages of the pipeline benefit too. Shorter, cleaner context lowers billed tokens and latency, and the cost of retrieval and generation is what most of the budget conversation is really about as this token cost guide frames it. And the ordering of what survives matters: models use long contexts unevenly, and performance is typically highest when relevant information sits at the beginning or end of the input and degrades when it is buried in the middle per the Lost in the Middle findings. Trimming before the cap gives you the discretion to place the surviving chunks well, instead of inheriting whatever order the retriever produced.

If you are assembling this across several models and vendors, one API key for text and embedding models removes a layer of plumbing from the benchmarking loop: Quanta Inference exposes text, image, video, audio and embedding models through a single OpenAI-compatible endpoint, so the trimming harness can swap scorers without a rewrite.

A short checklist before you ship a rule

  • Held-out labeled set exists and was never used for chunker or embedder tuning.
  • Tokens saved and recall lost are recorded per rule, not just in aggregate.
  • Queries broken count is reported separately from mean recall loss.
  • The rule's threshold came from a sweep, not a default.
  • The trimming trace is logged with reasons and config values.
  • A re-measurement trigger exists for corpus and retriever changes.
FAQ

FAQ

Why must dedupe run before the score cut?

Duplicates inflate the top of the ranking and distort any threshold set on raw scores, because a cluster of near-identical chunks looks like strong agreement. Collapsing them first gives the score cut an honest distribution to work with. Running the score cut first can leave you tuning a threshold against duplicate noise.

How do I know the token saving is worth the recall cost?

Compare tokens saved per relevant chunk lost against what context costs you. If a missed gold chunk produces a wrong answer a user notices, set the bar high and reject any rule that breaks queries. If context is expensive and the model tolerates noise, accept a larger loss. The ratio and the broken-query count together decide it.

Is a tier cut ever better than ranking everything together?

It is better when provenance is a genuine prior, such as mixing vetted documentation with unvetted web pages, and when one verbose tier can monopolize the window. It is worse when a query legitimately needs depth from one tier. The default should be a per-query allowance rather than a global one.

How large should the held-out labeled set be?

Large enough that the queries broken count is meaningful, because that metric is a tail measure and small samples cannot characterize rare events. Report every percentile alongside its sample size and observation window, as latency budgets guidance recommends in its discussion of percentile reporting. A few hundred queries is a reasonable starting point for chunk-level labels.

Does trimming replace reranking?

No. Reranking reorders candidates; trimming removes them. They compose well, with reranking before the score cut so the threshold acts on better scores, and dedupe either before or after reranking depending on whether you dedupe on embedding distance or reranker scores. Decide with the same measurement harness.

Sources

Sources

  1. Reducing Redundancy in Retrieval-Augmented ...
  2. We Fixed RAG Recall by Deleting Chunk Rules | by Praxen
  3. How to Budget an LLM Context Window
  4. Precision, Recall, and F1 Explained for LLM Evaluation
  5. Cost-Aware Query Routing in RAG: Empirical Analysis of ...
  6. Cost-Aware Query Routing in RAG: Empirical Analysis of ...
  7. 13 RAG chunking strategies for better retrieval
  8. Context Precision - Galileo
  9. Understanding LLM Cost Per Token: A 2026 Practical Guide
  10. Lost in the Middle: How Language Models Use Long ...
  11. Latency Budgets for Memory Retrieval
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles