RiverbornBook Call

InvoiceAgent : AI Document Intelligence Engine

Document Processing, LLM Extraction & Natural-Language Search.

Overview

InvoiceAgent takes a messy scanned or emailed invoice, reads it accurately, turns it into trustworthy structured data, and then lets users ask questions about that data in plain English. The whole product hinges on one hard thing: transcription accuracy. Invoices are visually inconsistent — PDFs, photos, scans, every layout imaginable — and a wrong total is worse than no answer.

OCR on invoices is not “solved.” A single OCR pass plus a single LLM call gets you a demo, not a product: silent numeric errors (1,250.00 read as 1.250,00), hallucinated dates, flattened line-item tables, and no confidence signal to decide what to trust. So rather than trusting one model, Riverborn built the platform around redundancy and cross-validation — two independent OCR engines, two LLM extraction passes, and a comparison step. When the passes agree, the invoice auto-completes at full confidence; when they disagree, a human decides. This study focuses on the two parts that took the most engineering: the OCR + LLM extraction pipeline and the natural-language search layer.

Business Challenges

  • Fragmented Data IngestionAccounts teams had to manually download, open, and key in invoices from multiple email inboxes and portals, causing delay and double entry.
  • Financial Accuracy RiskEven tiny errors in values, dates, or vendor identities lead to incorrect bookkeeping, duplicate payments, or incorrect tax submissions.
  • Lack of Spending VisibilityFinance teams could not easily aggregate or query invoice metadata, meaning forgotten SaaS subscriptions or duplicate contracts went unnoticed.

Technical Challenges

  • Silent Numeric Translation ErrorsStandard OCR models frequently confuse thousand/decimal separators (e.g. 1.250,00 vs 1,250.00), creating incorrect numeric data silently.
  • Structural Layout DisruptionFlattening visually complex document tables into text breaks cell bounds, making line-item reconciliation extremely difficult.
  • LLM Hallucination GuardrailsEnforcing strict schema structures on natural language queries without generating invalid parameters or incorrect categories.

Our Approach

Riverborn conducted detailed discovery sessions with accounts teams to map out invoice processing bottlenecks. The resulting design philosophy was “guaranteed transaction integrity.” Rather than trusting a single AI prediction, the backend is built to cross-verify outputs from distinct OCR structures, flagging mismatches immediately to prevent silent accounting errors.

Discipline & Contributions

DisciplineContributions
Business AnalysisUser story definition, strict database schema design, and tax regulatory compliance reviews.
UI/UX DesignFigma mockup for the 'pick-one' consensus validation UI and the conversational search layout.
Backend EngineeringDual-extraction Node.js backend pipelines, GCP Cloud Run Python microservices, PostgreSQL triggers.
AI/LLM OrchestrationMistral OCR parsing, Claude 3 & GPT-4 schema enforcement, pandas-ai prompt tuning.

The Extraction Pipeline

The key move is that every job runs two independent transcription paths and compares them. Each OCR output is run through its own LLM extraction, in parallel, before the results are reconciled. The two engines matter because their errors are uncorrelated— when both independently land on the same total, currency, and payment status, that agreement is a far stronger accuracy signal than one model’s self-reported confidence.

Dual-extraction & cross-validation pipeline
Source
PDF / image
email or direct upload
Queue
invoice_jobs
status: extract
Path A
Mistral OCR
→ markdown (tables intact)
LLM extract A
strict JSON schema
Path B
markitdown service
independent engine
LLM extract B
strict JSON schema
Cross-validate
compareSummarize
total · payment status · currency — do they match?
agree (~90%)
✅ Auto-complete
confidence 100 · written to invoices
disagree (~10%)
review_needed
both summaries stored
Human picks correct
verify endpoint → confidence 100
  • Two independent OCR engines. Path A runs mistral-ocr-latest, returning clean per-page markdown that preserves table structure; Path B runs a separate markitdownmicroservice on Cloud Run — a genuinely different engine with different failure modes.
  • Strict-schema LLM extraction with provider fallback. Both outputs are fed through one defensive extraction contract that pins the model to a single JSON shape — numbers as numbers, omit unknown dates rather than guess, infer currency from symbols, and model VAT/tax/discount as explicit line items so totals stay auditable. The call uses Claude and fails over to GPT-4(with Gemini available) so one provider outage doesn’t stall extraction.
  • Cross-validation & confidence gating. A compareSummarize step checks the three fields that matter most for trust — total, payment status, currency. Agreement pins confidence to 100 and writes the invoice; disagreement parks the job in review_needed with both summaries stored. Duplicate invoices are caught here too, by matching invoice_id within the org.

Human-in-the-Loop Review

Full automation is the wrong goal for financial data — a confidently-wrong total is the most dangerous output the system can produce. So the pipeline is built to know when it isn’t sure and hand off to a person. Because both candidate extractions are pre-computed, review is a bounded pick-one comparison — seconds, not data entry from scratch — and every resolution doubles as a labeled example of where the models diverged.

Review gate — scenarios
ScenarioSystem ActionHuman Effort
Passes Agree (90%)Auto-complete & commit transaction directly to PostgreSQL.Zero
Passes Diverge (10%)Escalate job state to review_needed; save both candidates.Human review (seconds)
System OutageGraceful failover to secondary model orchestration.Zero

The job lifecycle

Processing is asynchronous and modeled as an invoice_jobsrow walking a fixed lifecycle. The valid states aren’t a convention — they’re a database CHECK constraint, so a buggy worker physically cannot persist an invalid status.

Job lifecycle — valid states enforced by a DB CHECK constraint
pendingextractenhancevalidatecompleted
on disagreement:validatereview_neededcompleted
Any of extract · enhance · validate can also transition to failed — a buggy worker physically cannot persist an invalid status.

Natural-Language Search

Once invoices are structured, users want to askthings: “how much did we spend on AWS last quarter?”, “show unpaid invoices over $1,000.” Keyword search can’t aggregate, filter, and do math over structured records, so NLQ is built on pandas-ai, which translates the English question into pandas code and runs it against the org’s dataframe.

The hard part wasn’t generating the query — it was that pandas-ai returns different result types depending on the question: a raw number, a table, a text blob, or a generated chart image. None of those is a user-facing answer on its own, so each type is routed through Claude to produce a natural caption tailored to its shape.

Natural-language search — heterogeneous outputs → one good answer
User asks
“How much did we spend on AWS last quarter?”
pandas-ai · per-org dataframe
English → pandas code, run on the org’s invoices
number
table
text
chart image
Claude · switch on result type
Re-captioned into a human answer
number → sentence · table → headline · chart → explained
Answer = raw result + written caption
Deterministic fallback
Guided search builds a parameterized SQL query from explicit filters — faster, cheaper, 100% predictable when the user knows exactly what they want.

The Rest of the System

The OCR/LLM and NLQ pipelines are the centerpiece, but they sit inside a full multi-tenant SaaS backend — one mobile-grade ingestion backbone, a Node/Express API that houses every engine, and metered billing that gates each feature.

System architecture
📥 Ingestion
Direct uploadGmail (OAuth)Outlook (OAuth)Scheduled inbox sweepAES-encrypted tokens
⚙️ Node.js / Express API
Job state machineDual extraction + cross-validationDuplicate detectionNLQ (pandas-ai)Guided SQL searchSaaS tech-scan
🗄️ Data & storage
PostgreSQL (Render)Google Cloud Storagepgvector
🤖 LLM providers
Claude — primaryGPT-4 — fallbackGeminiMistral OCR
🔌 Platform
Firebase authStripe billingCloud Run · Cloud Build
  • Ingestion & email. Invoices arrive via direct upload, Gmail, and Outlook (OAuth via Google and Azure/MSAL, brokered by Nango). A scheduled job sweeps connected inboxes for attachments; OAuth tokens are AES-encrypted before they ever hit the database.
  • SaaS spend “tech-scan.” The same backbone scans a connected inbox for vendor signals, using a Claude Haiku classifier to label each email (paid / trial / renewal / overdue) — the same pattern as the invoice pipeline: an LLM as a confidence-gated classifier inside deterministic plumbing.
  • Billing, multi-tenancy & ops. Stripe-backed metered credits gate every feature; Firebase verifies ID tokens on every protected route; every table carries org_id through a parameterized CRUD layer that centralizes SQL-injection safety. Deployed to Cloud Run via Cloud Build with secrets in GCP Secret Manager.

Technology Stack

  • Frontend & UI: React, Next.js, Tailwind CSS, Interactive Chart components
  • Backend Orchestrator: Node.js 18, Express, PostgreSQL (Render), Google Cloud Storage
  • AI & Extraction: Claude 3 Sonnet/Haiku, GPT-4 fallback, Mistral OCR, Custom markitdown Microservice
  • Database & Logic: PostgreSQL, pgvector, CHECK state machine constraints, pandas-ai
  • Integrations & OAuth: Google OAuth 2.0 (Gmail API), Outlook API, AES-encrypted tokens, Stripe Billing

Results & Outcomes

The figures below are illustrative estimatesthat model the system’s impact on a typical workflow, not audited production metrics — included to make the outcomes concrete. They’ll be replaced with measured numbers as they become available.
90%Straight-through automation rate (consensual data written instantly)
~99%Field accuracy rate verified via cross-pipeline validation
~10sAverage document turnaround time (dropping from ~5 minutes)
20-30%Forgotten recurring spend surfaced and eliminated

Takeaways

  • Transcription accuracy is the product. We invested in redundancy — two OCR engines, two LLM passes, cross-validation — rather than trusting one model. Uncorrelated agreement beats self-reported confidence.
  • Give the LLM structure, not freedom. A strict JSON schema, markdown-preserving OCR, and explicit modeling of VAT/discounts removed entire classes of numeric error.
  • Always have an escape hatch. Provider fallback (Claude → GPT-4), a review_neededhuman gate, and a deterministic guided-search alongside pandas-ai mean no single component is a hard dependency.
  • LLMs as components in deterministic plumbing. Both the extraction validator and the NLQ caption layer use the model for fuzzy judgment while keeping orchestration, gating, and persistence in plain, testable code.

What the client says

“Riverborn feels less like a vendor and more like a part of our engineering team. What we value most is that they actually understand the problem before they start building — they push back when something doesn’t make sense and ask the right questions upfront. They care about the outcome, not just the deliverables, bringing rare honesty to the collaboration.”
Naimur RamanNaimur RamanChief of Staff, Mangosteen Studio

Ready to ship production-grade AI?

Free. 30 minutes. No prep required.