A multi-tenant service that reads financial documents with a fine-tuned model, learns from corrections, and pushes structured data into accounting systems.
Financial documents are a parsing nightmare: every bank, vendor, and accounting
package emits its own statement and invoice format, and the people who have to
reconcile them do it by hand. A general LLM can read one document well, but doing it
at volume, accurately, cheaply, and with an audit trail, is an engineering problem,
not a prompt.
Axiom ingests statements and invoices from Google Drive, OneDrive, or direct upload;
extracts and classifies the transactions; and pushes structured results back out to
QuickBooks, Xero, or a webhook. The interesting parts are how it stays cheap, how
it gets better over time, and how it stays auditable.
The document pipeline
Ingest Drive · OneDrive · upload
→
OCR Tesseract
→
Parse PDF · CSV · bank-specific
→
LayoutLM fine-tuned weights
→
Classify enrich · dedup · reconcile
→
Push QuickBooks · Xero · webhook
Fig. 1 · Ingest to structured output
Decisions worth surfacing
Confidence-gated dual-model serving. A locally fine-tuned LayoutLM model handles
extraction first. It’s fast and free per call. Every prediction carries a confidence
score; below a configurable threshold, the row falls back to Claude for a second
opinion. Each transaction records which path it took, so you can watch whether the
local model is regressing and whether retraining is actually helping, rather than
paying for a frontier model on every line item.
Online retraining with an atomic version flip. User corrections accumulate in a
corrections table. Once enough pile up, an APScheduler job trains a new model into
its own models/weights/vN/ directory and writes a new row to a model_registry
table. Serving behaviour changes only when a single is_active flag flips to the new
row. No file mutation, no service restart, no warmup hit, and rollback is one flag
away.
Corrections user edits
→
Trainer APScheduler
→
Weights vN model_registry row
→
Atomic flip is_active = 1
Fig. 2 · The learning loop
Two databases, split by concern. Authentication and tenant config live in one
SQLite database; the domain data (documents, transactions, anomalies, the model
registry) lives in another. The auth DB is small and stable; the data DB is the one
that grows. Splitting them means they back up and restore on independent cadences,
and a schema migration to one never risks the other.
Three key types with scope hints. Each tenant has a dashboard key (UI), a service
key (server-to-server, e.g. a Drive watcher writing back on the client’s behalf), and
a legacy API key for backward compatibility. An optional X-Key-Scope header lets a
client narrow exactly which credential is being checked, defending against
key-confusion bugs and keeping audit trails clean.
Idempotent by construction. Webhook ingestion is logged with status code and
latency on every attempt, and a uniqueness constraint on (config_id, file_id)
guarantees the same Drive file can’t be processed twice. That’s the kind of guarantee
you want before you let an automated system write into someone’s books.
Note
Axiom was built as a complete, deployable platform; the case study above describes
the system architecture rather than client deployments. Customer-identifying details
are intentionally omitted.