When a company relies on artificial intelligence to process financial data, the temptation to delegate validation is enormous. But anyone who has built extraction systems with language models knows that the real challenge is not achieving 99% accuracy, but detecting that 1% that looks correct but is not. At Q2BSTUDIO, where we develop custom software for critical sectors, we learned that the weakest link in any AI pipeline is not the model, but the absence of a deterministic verification mechanism. This article explores why a financial document extractor that does not verify itself is more dangerous than one that fails loudly, and how an approach based on redundant signals—like account balances—can transform the reliability of systems handling real numbers.
The beauty of an extractor that uses computer vision and language models lies in its ability to interpret complex layouts: irregular tables, changing date formats, foreign currencies. However, no model—however advanced—can guarantee that every extracted digit matches the original. A single character error, such as reading 1,240.50 instead of 1,340.50, goes unnoticed in any manual or automated process that does not cross-check data redundantly. That error, weeks later, throws off a bank reconciliation by a hundred euros, and nobody knows why. The root of the problem is that a plausible lie—a value that fits the total sum, sorts correctly, imports without errors—is far more dangerous than an obvious error. Because an error you fix; a plausible lie you integrate.
At Q2BSTUDIO, when designing AI systems for financial automation, we apply a fundamental principle: verification must be independent of the model. We cannot ask the same model that extracted the data to validate it; we need an external source of truth. In the case of bank statements, that source is embedded in the document itself: the running balance that appears next to each transaction. That balance column is not decoration; it is a control signal the bank gives you for free. If we correctly extract both the amount and the balance from each row, then the relationship between consecutive rows must satisfy a simple identity: the older row's balance plus the newer row's amount must equal the newer row's balance. This holds if the bank prints transactions in descending order (newest first). If the order is ascending, the identity changes sign, but the principle is the same: the chain of balances must close.
This mathematical reconciliation approach is the heart of a system we built to convert bank statement PDFs into spreadsheets. We do not trust the model; we trust the arithmetic. Each adjacent pair of rows is compared with a tolerance of one cent (to absorb floating-point noise). If the fraction of pairs that close is above 0.99, we consider the extraction verified. If not, the output is labeled 'UNVERIFIED' and carries a clear message in the downloaded file, the filename, and the API response. This way, the user always knows whether the numbers have passed a deterministic check or are merely the result of a probabilistic inference.
There are two twists that make this system robust against the diversity of bank formats. The first is that banks do not agree on time direction: some print the most recent transactions first (like Nordic banks) and others print the oldest first (like most US banks). Instead of heuristically detecting the order, we can score the extraction in both directions and keep the one with the better score. An incorrect extraction will not score high in either direction, because wrong numbers do not fit into any consistent chain. The second twist is that many statements—especially two-column ones from the UK or day-grouped formats—only print the balance on the last row of each day, leaving most rows without a balance. In those cases, we cannot do row-by-row verification, but we can accumulate amounts between two consecutive printed balances and check that the sum matches the difference between those balances. This method localizes the error to a specific segment, which is more powerful than simply verifying that the opening balance plus totals of debits and credits match the closing balance.
The part I care about most is that the verification gate refuses to bless what it cannot verify. A subtle bug in a naive implementation is returning a perfect score (1.0) when there are not enough rows with balance to check. That would mean that an empty extraction, or one where the model returned no balances, would pass the check. It is exactly the opposite of what we need: an unverifiable result is not a verified one. Therefore, the pass condition requires that at least one pair has been checked (total > 0) and the score exceeds the threshold. If it cannot be verified, the 'UNVERIFIED' label follows the data everywhere.
This approach has deep implications for any business handling financial data. At Q2BSTUDIO, we integrate these kinds of checks into our cloud AWS/Azure and BI / Power BI projects, where data integrity is as important as availability. For example, when we build Power BI dashboards from AI-extracted bank data, reconciliation becomes an automatic governance step: if the statement is not verified, the dashboard is generated with a visible warning. Similarly, in banking and fintech environments where cybersecurity is a priority, a system that is never 'confidently wrong' reduces the risk of decisions based on manipulated or misinterpreted data.
Beyond bank extraction, the principle applies to any domain where a redundant signal exists. Invoices carry the relationship between line items, taxes, and totals; ledgers have double entries; inventories have opening and closing stock. That redundancy is a free, deterministic check we can wrap around probabilistic models. It allows making a promise that most AI tools cannot make: if I am not sure, I will tell you, instead of guessing.
The tool we have developed as a proof of concept (available in our development lab) accepts PDFs from any bank, extracts transactions with a vision-language model, and applies reconciliation. In tests with a real 16-page statement with 742 transactions, the score was 740/741 correct pairs (0.9986). Nothing ships below 0.99. That number is not a marketing label: it is a measurement recalculated on every conversion. It is the difference between a system that 'guesses' and one that 'verifies'.
In summary, if you are putting an LLM near numbers that people will act upon, look for the redundant signal already in your input data. Bank statements carry balances; invoices carry totals; ledgers carry double entries. That redundancy lets you build a deterministic verification gate around a probabilistic model. And that gate lets you do what few AI applications can: if I am not sure, I warn you, instead of risking you making a decision based on a false number.




