How We Reduced LLM Hallucinations in Financial Statement Parsers
Parsing tables, net margins, and line-item details from PDF invoices should be direct. But when a model gets creative and returns a "net total" that doesn't equal the sum of its parts, your downstream accounting databases quickly corrupt.
AI models excel at locating text, but they fail at basic math. In this technical review, we walk through how we combined schema validation libraries (Zod) with strict code validations to catch parsing anomalies at runtime.
1. The Two-Step Extraction Pattern
Rather than asking the model to parse and calculate figures in a single request, separate the operational stages:
- Step 1: Extract raw line-items exactly as they appear on the document (no math, no currency translation).
- Step 2: Use deterministic code (Node.js or Python) to compute totals, convert currencies, and crosscheck sums.
// Schema validation forcing extraction before calculation
const LineItemSchema = z.object({
description: z.string(),
unitPrice: z.number(),
quantity: z.number(),
declaredTotal: z.number()
});
function validateInvoicedTotal(lineItems) {
const calculatedSum = lineItems.reduce((acc, item) => acc + (item.unitPrice * item.quantity), 0);
return lineItems.every(item => Math.abs(calculatedSum - item.declaredTotal) < 0.01);
}
If the validator detects a discrepancy between the calculated sum and the model's extracted total, the workflow triggers a second target API check or routes the record to the human review queue.
Conclusion
Lowering model hallucinations isn't solved by adding "please be accurate" to your prompt. It requires isolating raw extraction from mathematical operations and running strict validation rules in your code.
Ananya Iyer
Head of AI & Engineering at AICraftGen. Former systems architect specializing in secure LLM pipelines and workflow orchestration.