Founders

How to Route Bank Rows Between a Cheap and a Strong Model

Antonio Evans11 min read

A split-flow diagram: on the left, a stack of bank rows flows through a simple gate labeled 'confidence check'.
Key points

Key points

  1. 1Score each bank row with a cheap deterministic check before any model sees it, and escalate only rows that fail.
  2. 2Send clean rows to a small model and ambiguous rows to a large model, because clean rows dominate most bank exports.
  3. 3Estimate cost per row as routing logic plus the blended model call, then compare it with sending everything to the large model.
  4. 4Calibrate the escalation threshold on rows with known correct answers, because a badly set threshold can cost more than no routing at all.

Why a single model is the expensive default

A bank transaction export is a long tail of easy and hard rows. Most rows have a complete description, a single matching amount, and a counterparty name that points at one obvious category. A minority are genuinely ambiguous: a merchant description that fits two categories, a missing reference, a sign that could be a refund or a charge, an amount that does not match any invoice. If you send all of them to one large model, you pay large-model prices for the easy majority. If you send all of them to a small model, you get cheap output with silent errors on the hard minority.

Confidence-threshold escalation is the pattern that resolves this. The cheap model answers first and produces a confidence signal, and only requests that fall below a threshold move to the stronger model. The structural advantage over deciding difficulty before generation is that you never have to guess how hard a row is before anyone has tried it: you look at what came back. See the write-up on confidence thresholds for escalating requests for the three routing families (rule-based, classifier-based and cascade) and where each one breaks.

The same logic that makes contribution margin the number to watch in a growing business applies here. Revenue per row is fixed. What changes with routing is the variable cost per row, so the only question worth optimizing is how much of each row's value you keep after the model bill.

The decision rule: a cheap pre-check, then a threshold

Build the router in two stages. Stage one is free: deterministic rules over the row itself, no model call. Stage two is the paid cascade: small model first, escalation only when the small model's output is below a confidence threshold.

Stage one flags a row as ambiguous when any of these are true:

CheckAmbiguous whenWhy it matters
Missing fieldsDescription, counterparty, or amount is null or emptyNothing to reason from
Amount mismatchRow amount differs from any linked document or expected recurring amountReconciliation error or duplicate
Short textDescription is under a set character count or is a generic string like a POS terminal IDNo semantic signal
Multi-candidate matchTwo or more categories score close on keyword rulesGenuine classification tie
Sign or type conflictDebit/credit sign disagrees with the document typeRefund vs charge confusion
Currency or country mismatchCounterparty country differs from the account's usual setCross-border fees and FX rows

Rows that pass all checks go straight to the small model. Rows that fail any check either go straight to the large model, or go to the small model with the failure recorded so the threshold can catch them. Rows that pass the pre-check but whose small-model output comes back under the confidence threshold also escalate.

Bank reconciliation is fundamentally a matching problem between statement lines and internal ledger entries, and mismatches fall into a known set of causes: a transaction in the bank feed with no matching posting, a posting with no bank transaction, or a timing difference. Microsoft documents exactly these categories and the resolution for each in its bank reconciliation guidance, which makes a good basis for your stage-one rules. Statement parsing itself has a separate failure mode, so keep parsing bank statement files as its own step before classification.

A minimal version of the gate looks like this:

def needs_large_model(row, small_result, threshold=0.70):
    if not row.get("description") or row.get("amount") is None:
        return True
    if len(row["description"]) < 12:
        return True
    if row.get("amount_mismatch"):
        return True
    if small_result["confidence"] < threshold:
        return True
    return False

The threshold is the one number that decides the whole cost-quality trade-off. Too high and you escalate constantly, paying more than sending everything to the large model would have cost. Too low and the small model keeps handling rows it cannot do, quietly lowering quality with no error logged. Calibrate it on a sample of rows where the correct category is already known, find the point where the confidence signal best predicts the small model's own mistakes, and set the threshold there rather than from a guess or from a benchmark that does not resemble your export.

Confidence signals you can actually use

You have three classes of signal, and they differ a lot in reliability and in engineering effort.

Verbalized self-assessment ("I am not sure this is payroll") is the weakest, because models are not well calibrated at describing their own uncertainty in words. Log-probability based signals are better and cheap to collect: take the probability distribution over your allowed category set and use the top probability, or 1 minus it as an uncertainty score. A query where one category clearly dominates stays on the small model; a query with several plausible answers escalates. Training-based approaches, such as teaching a model to emit explicit confidence tokens, perform best on routing and rejection tasks according to the ICML poster on learning to route with confidence tokens, but they need a training loop and access to model internals, so they only work with open-weight models.

There is a real caveat you should design around. Confidence routing is task-dependent. A systematic evaluation across three model families, four languages and three task types found that confidence identified useful escalations on reading comprehension and topic classification (mean correction-detection AUC of 0.612 and 0.705), but on a knowledge and reasoning dataset the mean AUC was only 0.510 and routing gave no consistent improvement over random selection, because small models often stayed highly confident while wrong. The same study found the method can create language escalation gaps of up to 30.33 percentage points, which equal-quota routing removed with little aggregate accuracy cost. The full results are in Confidence-Based Small-to-Large LLM Routing.

The practical translation for a bank export: confidence works well for categorization and matching, which are closer to classification than to open-ended reasoning. Test it on your own rows before trusting it. If a subpopulation (say, non-English merchant descriptions) is systematically under-escalated, apply a quota so that each subpopulation escalates at a similar rate rather than letting a global threshold allocate compute unevenly.

One more signal worth considering is a verifier rather than a self-report. If your small model must output a structured object with a category, a confidence, and a cited rule, you can validate the object against a schema and reject anything that does not conform. Structured outputs are designed exactly for this: you define a JSON Schema and get typed data back instead of free text you have to parse, as described in Snowflake's structured output documentation. Databricks notes that batch structured generation with a response format is built for precisely this case of extracting fields reliably across millions of data points, and that constrained decoding limits which tokens can be returned at each step. See structured outputs for batch and agent workflows. AWS covers the same technique in more depth with the Outlines framework in this post on structured output from LLMs.

A schema-validated response plus a confidence field is a stronger gate than a single number from a chat completion, because a malformed answer is an automatic escalation rather than a silent failure.

Cost per row, worked with numbers

Assume an export of 100,000 rows. The illustrative prices below are placeholders you should replace with your own contract rates: a small model at 0.10 USD per million input tokens and 0.40 per million output tokens, a large model at 3.00 and 15.00, and an average of 600 input and 120 output tokens per row with the shared instruction prompt cached.

Line itemSmall modelLarge model
Input tokens per row600600
Output tokens per row120120
Input price per million0.103.00
Output price per million0.4015.00
Cost per row0.0001080.00360
Cost for 100,000 rows10.80360.00

Now add routing. Suppose the deterministic pre-check costs nothing per row, runs at about 1 millisecond of a modest compute instance, and you value that instance at 0.05 USD per hour. Across 100,000 rows at 1 ms each that is 100 seconds, or about 0.0014 USD. Effectively zero. The real routing overhead is the small model call you make on every row you do not pre-escalate, plus the large model call on the escalated share.

With a 12 percent escalation rate:

  • Small model handles 88,000 rows: 100,000 x 0.000108 x 0.88 = 9.50 USD
  • Large model handles 12,000 rows: 100,000 x 0.00360 x 0.12 = 43.20 USD
  • Routing logic: about 0.0014 USD
  • Total: about 52.70 USD, or 0.000527 USD per row

Against 360.00 USD for the all-large baseline, that is roughly a 85 percent reduction. The blended average sits much closer to the small model's price than the large model's, which is the whole point: the average cost per row is dominated by whichever model handles most rows.

This is the same structure as a contribution margin calculation, where every incremental dollar of variable cost has to be earned back. If your per-row economics are revenue minus variable cost, then reducing variable cost per row from 0.0036 to 0.00053 raises the contribution of each row by 0.0031 USD. On a 100,000-row month that is about 310 USD of margin, and the arithmetic scales linearly with volume. For how contribution margin and break-even work in general, the contribution margin formula and examples walk through the per-unit version, and Contribution Margin is King makes the case that it, not revenue, is the number that tells you whether a unit is worth producing.

Finding the break-even escalation rate

The break-even point for routing is the escalation share at which the blended cost equals the all-large baseline. Solve for the escalation rate e:

Blended per row = (1 - e) x small + e x large + routing

For the numbers above, small is 0.000108 and large is 0.00360, so blending always lands below the all-large cost for any e below 1. That means routing in a two-model setup almost always beats a single large model on pure token cost, and the real question is whether it beats doing nothing at all on quality. Compare instead against the all-small baseline: routing costs more than all-small by exactly the escalated share times the price gap, and that is the premium you pay for accuracy on the hard rows.

The decision rule that follows:

  • If your error cost per misclassified row is below about 0.0035 USD, send everything to the small model.
  • If it is between roughly 0.0035 and 0.05 USD, route, and tune the threshold until escalation lands where the quality gain is concentrated.
  • If it is above about 0.05 USD (tax-filing errors, fraud flags), send the flagged rows to the large model regardless of confidence.

That middle band is wide, which is why the threshold, not the model choice, is where most of the work is.

Work out your own break-even by writing down three numbers: small model cost per row, large model cost per row, and the cost of one error. Then set the escalation rate so that the marginal escalated row's expected error reduction is worth more than the price gap. If you would rather not run the arithmetic or hold contracts with three providers, Quanta Inference exposes text, image, video, audio and embedding models through one OpenAI-compatible API key, prepaid and priced in US dollars, which makes it straightforward to price a small and a large model against the same export and swap between them per row.

Wiring it up: batching, schema and audit trail

Three implementation details decide whether the routing holds up in production.

First, batch. Rows from a bank export do not need real-time processing. Batch inference lets you group rows into one call with a shared prompt and amortize the instruction tokens across many rows. On the numbers above, input is about 87 percent of each row's token count, so caching or sharing a long categorization prompt is the single largest lever after routing itself. One bank that moved to LLM transaction categorization, ANNA, reported cutting LLM costs by 75 percent through offline prediction, better context use and prompt caching, as summarized in this LLMOps case study.

Second, enforce a schema. Every model call should return the same object shape so the router can read the confidence field and the category, and so a malformed answer is a validation failure rather than a parse error three steps later. The structured output pattern is worth reading before you write the prompt, because the retry behavior matters: a model that fails schema validation twice should be escalated rather than retried indefinitely.

Third, log the routing decision per row. Store the pre-check failures, the small model's confidence, whether it escalated, the final category, and whether a human later corrected it. Without the correction column you can never recalibrate the threshold, and without the escalation column you cannot see when a rule has started over-firing. Reconciliation work is exception-based by nature, so review only the rows that failed, not the whole export, as the ad spend reconciliation playbook argues: automate the match, then review exceptions.

A small worked example of the payoff of the audit trail: if your form says 12 percent escalation but you find that one generic merchant name ("SQ *") accounts for a third of escalations, tighten a rule for that merchant and your escalation rate falls, which lowers your blended cost without touching the model.

When not to route

Escalation routing is not free of downside. It adds latency on escalated rows (two calls in sequence, or one if you pre-escalate from the cheap rule), adds a threshold you must calibrate and maintain, and adds a failure mode where the small model is confidently wrong. Three cases argue against it.

When the export is small. The setup, calibration and monitoring effort exceeds the token savings on a few thousand rows. Route only when monthly volume is high enough that the absolute saving covers the engineering time, and use the break-even table above to check.

When the task is open-ended reasoning rather than classification. The evidence that confidence predicts useful escalation was weak on knowledge and reasoning tasks, with AUC near chance. If your rows need multi-step judgment, either send them all to the large model or build a verifier that checks the output against the ledger rather than trusting self-reported confidence.

When the cheap rule fires so often that the small model rarely runs. If your pre-check flags 60 percent of rows as ambiguous, the cascade degenerates into a mostly-large pipeline with extra steps and extra latency. Measure the flag rate before you build: if it is above roughly 40 percent, fix the data quality or the rules first.

For teams where the routing logic itself is the hard part, or where a line of business needs the export classified end to end, a short scoping call with an AI specialist is the fastest way to size the threshold and the rules against your actual data. You can book a free 30-minute AI discovery call with your goals and get a tailored recommendation, no obligation.

FAQ

FAQ

How do I choose the confidence threshold?

Build a labeled sample of a few thousand rows where the correct category is known, run the small model on all of them, and plot accuracy against the confidence score. Set the threshold where the score best separates correct from incorrect outputs. Then check the escalation rate it produces against your error cost, because a threshold that maximizes accuracy almost always escalates more than the economics justify.

What if the small model is confident but wrong?

This is the main failure mode, and it is common on reasoning-heavy tasks, where confidence-based routing showed no consistent benefit over random escalation. Guard against it with schema validation, a separate verifier that checks the output against the ledger, and per-subpopulation escalation quotas so no group is systematically under-escalated. Never rely on verbalized self-assessment alone.

Does routing still help if most rows are already clean?

Yes, and that is the case it helps most. If 88 percent of rows are clean, the blended cost per row sits close to the small model's price while the hard rows get large-model treatment. The saving is roughly the escalated share times the price gap, so a low escalation rate is exactly what makes the average cheap.

Should I use the pre-check rules or the model confidence as the gate?

Use both, in sequence. The rules are free and catch the failures a model cannot fix, such as a missing amount or a missing counterparty. The confidence threshold catches failures the rules cannot see. Rows that fail a rule should skip the small model on cost grounds; rows that pass the rules still go through the threshold.

How do I keep costs down if the instruction prompt is long?

Share one long instruction prompt across a batch and let prompt caching handle the repeated prefix, then batch rows per call. Input tokens are the bulk of the per-row count in most categorization workloads, so caching and batching usually cut more cost than switching models. Measure tokens per row before and after so you can see the effect.

Sources

Sources

  1. Using Confidence Thresholds to Escalate Requests to a ...
  2. Why a Growing Business Should Never Overlook Contribution Margin
  3. Reconcile bank accounts - Business Central
  4. Automate Bank Reconciliation By Parsing Bank Statements
  5. Learning to Route LLMs with Confidence Tokens
  6. Who Pays for Efficient Inference? Confidence-Based Small ...
  7. Structured output
  8. Introducing Structured Outputs for Batch and Agent ...
  9. Generate structured output from LLMs with Dottxt Outlines ...
  10. Contribution Margin: Formula, Calculator & Examples 2026 Guide
  11. Contribution Margin vs. Gross Margin | Reformation Partners - Medium
  12. ANNA: Cost-Effective LLM Transaction Categorization for ...
  13. Chapter 15: Structured Output and Schema-Constrained ...
  14. What Is Ad Spend Reconciliation? Definition
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