DEV Community

Cover image for Verdandi: Document Intelligence, Simplified
Akshay Singh
Akshay Singh

Posted on AI-assisted

Verdandi: Document Intelligence, Simplified

Preface

You should probably skip the preface, It's just me ranting

I can summarise my entire time at EY with one word - Documents

And it's not just me, I saw people teams all the way from analysts to senior consultants spending north of 6 hours a day validating and extracting data from documents. People spending all day, opening PDFs containing documents and Excel in split screen on their 14" laptops and copying data all day, everyday, in 2026. The difference in position, experience, and expertise were practically non-existent - the same task, and the only real difference was the language in which the documents were produced. From where I sat, the incentive structure seemed to reward billable hours far more directly than improving the process.

So I decided as an Analyst in Risk consulting from a non technical background that I would set out to work on one of the most annoying technical problem to ever exist. When I started building Verdandi in June, I was completely unaware of just how insanely complicated this problem statement was, and the stakes could not be higher since some validation errors could have direct impact on financials and processing times.

All of this while programming in 2026, where opening Twitter (fine, X) felt like there were 10 more major developments in agentic coding and the current system was obsolete

A few examples - Loop engineering is the new thing. Graph engineering is the new big thing. This model is complete garbage and benchmaxxed (and the next tweet was talking about how that model changed someone's life forever). I can't believe people still write their prompts like this - here's 6000 ways you can improve your prompting skills and become an expert! Here's why you only need Claude with notion/obsidian for every development task ever .................... Get it ?

Problem Statement // Introduction

When I started out researching at my time in EY, it didn't start with me looking for a platform that can intelligently process complex documents, it started out with me looking for something as simple as a tool that can turn non-OCR PDFs into OCR, so we didn't have to manually extract data from the documents, and could instead just copy the data, relying less on eyeballing blurry and disoriented documents and reporting the wrong data.

Everything on the open web related to document processing was scattered and desperately monetised, of the 7-9 companies I could find that handled document processing for global logistics, which was the division I worked in - none had a product that was transparent and could be used by end consumers outright. The 2 options were always "Book a demo" or "Contact our sales team". It was there I realised that all these companies missed one major point - Regardless of industry, the problem was the same - Document intelligence. And when I say document intelligence, I mean what I saw consultants doing. Extracting, validating, and summarising data in their desired format from complex and varied documents.

When I zoomed out, Document intelligence for global trade, healthcare, insurance, manufacturing, research, can all be solved with one platform that can be customised to the preference of the end user, instead of having 10 different companies and tools, because at its core, the problem was the same.

I saw a glimmer of hope when I learnt that Microsoft recognised this problem and offered Azure Content understanding, but that quickly went away when I went through the tragedy of having to open and sign up. Opening Azure Foundry feels like walking into the cockpit of an Airbus A350. You'll find out more about this in the benchmark section of this writeup

Companies that have resources would much rather outsource this process rather than use one tool internally, because of how cluttered and confusing DI really is. organisations and smaller companies that do not have access to the same level of resources are forced to manually process documents, or use tools that are not transparent and have borderline predatory pricing.

Document intelligence was a real problem, and needed to be solved, while remaining accessible to everyone who needs it. That's how Verdandi was born

Comparisons/Benchmarks

Verdandi was benchmarked against Microsoft's Azure Content Understanding platform on a set of 100 documents, that will be attached. Verdandi used GPT-6-luna while Azure content understanding used GPT-5.5, which is the latest model that is supported by ACU and text-embedding-3, both deployed on Azure Foundry.

1. Setup

Both systems processed the same 100 frozen, sha256-verified documents (103 pages). They shared one 8-field schema plus line items, ran zero-shot, and were scored by one scorer with identical normalisers. Each used its strongest available model.

Dataset slice Docs Source
invoice/clean 35 FATURA2
receipt/messy 25 CORD v2 (real Indonesian receipt photos)
invoice/scan 10 Kaggle scanned invoices
Synthetic 30 Generated: clean, degraded scans, handwriting-style, Hindi+English, multi-doc

2. Headline results

Metric Verdandi ACU
Field macro accuracy (mean of 2 runs) 97.0% (97.0 / 97.0) 96.2% (96.3 / 96.1)
Line-item precision / recall (mean) 95.4 / 96.3 94.2 / 95.3
Line-item F1 0.958 0.947
Documents found 100/100 100/100

3. Per-field accuracy (correct / scored)

Field Verdandi A Verdandi B ACU A ACU B
invoice_number 68/70 (97.1%) 68/70 (97.1%) 69/70 (98.6%) 69/70 (98.6%)
invoice_date 72/73 (98.6%) 72/73 (98.6%) 73/73 (100%) 73/73 (100%)
vendor_name 67/68 (98.5%) 68/68 (100%) 67/68 (98.5%) 67/68 (98.5%)
buyer_name 46/46 (100%) 45/46 (97.8%) 43/46 (93.5%) 43/46 (93.5%)
currency 46/51 (90.2%) 47/51 (92.2%) 47/51 (92.2%) 47/51 (92.2%)
subtotal 75/77 (97.4%) 74/77 (96.1%) 72/77 (93.5%) 72/77 (93.5%)
tax_total 56/59 (94.9%) 56/59 (94.9%) 58/59 (98.3%) 57/59 (96.6%)
total_amount 96/98 (98.0%) 96/98 (98.0%) 93/98 (94.9%) 93/98 (94.9%)
Macro 97.0% 97.0% 96.3% 96.1%

4. Per-run results (correct / scored cells)

Stratum Verdandi A Verdandi B ACU A ACU B
invoice/clean 330/332 329/332 330/332 330/332
invoice/degraded 21/21 21/21 21/21 21/21
invoice/handwriting 28/28 28/28 28/28 28/28
invoice/scan 52/58 53/58 52/58 52/58
receipt/clean 24/24 24/24 18/24 18/24
receipt/degraded 21/24 21/24 19/24 19/24
receipt/messy 50/55 50/55 54/55 53/55

Verdandi is stronger on clean and degraded receipts and the buyer_name, subtotal and total_amount fields. ACU is stronger on messy receipt photos and the invoice_number, invoice_date, tax_total and currency fields. All four invoice strata are effectively tied.

5. Cost (per 100 documents)

Item Verdandi ACU
Primary model $0.167 (mean of runs) n/a
Rechecks (gpt-5.6-luna) $0.095 (mean of runs) n/a
Pages + contextualization n/a $0.618
Model input + output n/a $1.934 (mean of runs)
Total, corrected $0.2619 $2.5522
Per document $0.0026 $0.0255
Cost basis Verdandi ACU Ratio
Corrected, no-cache bound (used as headline) $0.2619 $2.5522 9.7x
If gateway caching fully applied (floor) $0.1326 $2.5522 19.2x
As reported by scorer (recheck mispriced) $0.2121 $2.5522 12.0x
Tokens per run Verdandi ACU
Total ~1.31M (primary ~948k + rechecks ~371k) ~568k (incl. 103k contextualization)

Verdandi uses more than twice the tokens but is far cheaper overall because its per-token rates are much lower. ACU billing is Azure list prices (east-us); Verdandi uses per-token list prices via a subscription gateway.

ACU also has different pricing tiers based on features like OCR, Tables, Tables + Forms and so on, while Verdandi's only cost incurring aspect is the VLM.

6. Caveats

  • The accuracy gap (0.8 points) is a few cells over two runs, and ACU won several fields and messy photos. The cost gap is the more robust finding.
  • Public datasets (FATURA2, CORD, Kaggle) may appear in either model's training data. The 30-doc synthetic set is the contamination-clean control.
  • Kaggle scans carried the most risk: on kaggle_01, both systems read GBP 7555.55 while the label says USD 13600, which is an open question.
  • Verdandi's day-first date policy is deliberate, so some US-style dates in the Kaggle scans score as misses for it.

Demo

Review

One of Verdandi's core value props is how involved humans are still in the process, it does not give the VLM complete decision making ability. Depending on the users confidence thresholds, the VLM flags extraction and validation aspects that it is unsure on and the decision falls on to the secondary model to look at the discrepancy and come up with a confident answer, in cases where even the backup model fails to come to a conclusion accurately, it is raised as a "flag" where a human can intervene and visually confirm what the value on the document says and if it's right or needs to be changed.

Users can see the model claimed vs text claimed position of the extracted data and come up with a decision to agree, disagree, or input a custom value if both the provided option aren't applicable in the situation

Results

Users have the ability to review the results of a run by choosing the run - and the specific file within that run to carry out thorough forensics of how the data was extracted, from where on the document it was extracted and the confidence with which it was extracted. This is an extremely useful feature for users who want a clean audit trail of where and how the data was extracted. This section was built with simplicity in mind and the side by side display of data and document allows for easy review and documentation.

Run

The screen from which users can choose crucial information before starting extraction like the model, the template/profile in which they want the data to be extracted, how many files they want to process in parallel, and if they want to pin certain documents within a file before extracting (Really cool feature, you should try it!)

This is the place where you choose which files/folders you wanna process using Verdandi

Console

The data gold mine - Console allows users to get a complete snapshot of a run, details like files processed, tokens consumed, models used, and much more! Console is really useful to understand what exactly conspired during a run and if there's anything the user should do differently in the next runs.

All the data in console can be exported and used to audit/fine-tune the extraction process.

Templates


This is the part where things get fun and users have complete control over how the data is extracted from the document, wait there's 5 documents in a file and you only wanna extract from one of the documents, if only I had thought of that, oh wait I did.

Document description

User's can describe the document from which they wanna extract data, what it is, how it looks and how the VLM can find it among multiple other documents in the same file and can also use words that are 100% going to be present on the document, unique only to it.

Allow-no-match is a feature that lets you tell the VLM that if it isn't confident that the document that it found is the one the user described, it's gonna flag and give up instead of extract data from an irrelevant document

Fields

Users can decide what fields from a document they want to extract instead of getting all the data from the document, including irrelevant information. With the field, they can add a description of the datapoint to aid in the triangulation and extraction of that datapoint.

every data point get's its own confidence threshold that is customisable by the user. A higher confidence threshold implies that the data extracted by the VLM must be highly accurate, and if it isn't it's flagged as "not met confidence threshold" in the reviews section of the run where you can decide if the extracted value is right or not!

Line items

Documents like invoices have line items with their corresponding tax and amounts, with each row denoting a new line item. Verdandi allows users to extract these line items and also in edge cases where the wording of the table headers differ, user can input data to help the VLM understand what datapoints it's extracting from the table.

You can also set custom arithmetic rules such as sum of line items = total invoice amount to ensure the data is accurate and nothing was missed out, and a table note where you can input more details about how to read the table.

Workflows

Now this is where verdandi stands out, the benchmarking details compare against Azure Content Understanding, but this feature doesn't even exist on ACU.

Cross-Document validation

Let's imagine a case where a supplier provides a file containing an invoice and the corresponding transport document pertaining to that invoice. This is important because the supplier can only charge you for transportation provided this specific shipment involved transportation and requires compensation.

cross document validation allows you to check if the documents attached in the file are all relevant and are related to one another. Instances where the documents attached are not related to each other are flagged and can be reviewed manually in the "reviews section"

This section was added to ensure the wrong documents are always flagged and help in compliance.

Expected documents

This section allows users to set an expected number of documents per file, and if the minimum number of documents are not met per file, it is flagged for review.

Exports

The ability to export data in excel format was one of the first features I thought I would add if I ever decided to build a document intelligence platform, and it turned out to be the final feature I added. User can create export profiles and decide which datapoint should be displayed under what column. details like file name , datapoints, line items, etc can all be extracted into excel. What good does extracting data accurately do if you can't view and manipulate it in real time on a platform that's used by pretty much everyone.

Settings

Default Extraction model

Users can choose from a list of vision enabled models from opencode and set it as the default model to run extractions from. This section also shows the estimated cost per million input/output tokens, so you can decide which model is best for your use case.

You can also choose the backup vision model that is used to recheck, resolve conflicts in cases of low confidence and disagreements between the text and vision pipelines.

Vision candidates

This list contains all models currently offered by opencode on their GO subscription.

By hitting verification - verdandi makes a small paid call and checks if the model has vision capabilities or not. Only models that are vision capable can be run by Verdandi.

This catalog of models is constantly updated to reflect all new models integrated into opencode and if any models have been removed from the catalog.

** Free disk after export deletes all the documents images from your disk to free up space, the images are only deleted after the data from the documents has been exported **

Gateway Key

This is where you input the opencode GO API key you wanna use to extract data from. You can also test keys to make sure they're valid and work.

In case you've exhausted your usage on the API, Verdandi will default to using your credit balance on the account, and if there is no credits available, the run fails.

Privacy and Data Security

  • Local OCR: Verdandi can OCR documents entirely on-device, so documents do not need to leave the machine for OCR.
  • ZDR models: Through OpenCode, Verdandi can restrict model selection to Zero Data Retention (ZDR) models, preventing providers from retaining submitted data.
  • Provider controls: Verdandi can also exclude Chinese models via Opencode - from the available model pool when processing sensitive documents.
  • Disk cleanup: Users can enable Free disk after export, which deletes generated document images from local storage after successful export.

The goal is simple: keep sensitive processing local where possible, minimise provider-side data retention, and give the user control over which models can ever see their documents.

Core Features

OCR

The first problem Verdandi had to solve was the one it all started out from: actually reading the damn document.

So the first step in Verdandi's document pipeline is figuring out what it is dealing with.

Does this page actually need OCR?

Verdandi inspects the contents of each page before deciding whether to run an OCR engine on it.

This means Verdandi doesn't treat OCR as a mandatory step that every page has to go through. It treats it as a tool that gets used when the document actually needs it.

That distinction becomes particularly useful when processing large documents. A 100-page PDF doesn't necessarily mean 100 pages of OCR work.

Apple Vision

On Apple Silicon, Verdandi uses Apple's Vision framework as one of its OCR engines.

The OCR can run locally, which means the document doesn't have to leave the machine just to turn pixels into text. It also gives Verdandi a native OCR path on the hardware I use for development and testing, without introducing another external service or API dependency into the most fundamental part of the pipeline.

PaddleOCR

Of course, building a document intelligence platform around a single platform-specific OCR implementation would be a slightly strange decision.

So Verdandi also supports PaddleOCR as an alternative OCR engine.

Data Co-ordinates

Document extraction is fundamentally spatial.

An invoice number isn't just a string somewhere in a 2,000-word document. It exists in a particular location on a particular page, usually next to a label, inside a table, or within some other visual structure.

The OCR layer therefore produces structured text information that can be consumed by the rest of the system rather than simply dumping a giant block of text into a variable and calling it a day.

That distinction becomes important later when Verdandi's vision models start making extraction decisions and the text pipeline needs to independently verify those decisions.

Vision Model Pipeline

The model isn't told what to extract

One of the design goals of Verdandi was to avoid building a separate extraction implementation for every document type.

A bill of entry, an invoice, a packing list and an insurance document obviously contain different information. Hard-coding the extraction logic for each one would quickly turn Verdandi into exactly the kind of fragmented system I was trying to avoid building.

Instead, Verdandi uses document profiles to define what information is required.

The profile describes the document and the fields that matter, along with the expected structure and validation requirements.

The extraction engine then uses that definition to construct the request sent to the vision model.

The model is replaceable

Another decision I made early was that Verdandi should not depend on one particular VLM.

The model landscape changes far too quickly for that to be a sensible architectural decision.

A model that is excellent at document extraction today can be surpassed by another model next month. One model might be better at tables, another might be better at spatial reasoning, another might be dramatically cheaper, and another might simply be faster.

So instead of making the model the foundation of Verdandi, I made it a replaceable component.

Verdandi uses OpenCode as the model access layer, allowing different supported vision models to be used without rewriting the extraction pipeline around each provider's API.

The model returns more than a value

There is another important distinction here.

Verdandi doesn't treat the VLM's output as simply:

{
  "invoice_number": "INV-49281"
}
Enter fullscreen mode Exit fullscreen mode

For each extracted field, the system can retain additional information about the extraction, including confidence and where on the document the model believes the value came from.

That means an extraction is closer to:

Field: Invoice Number
Value: INV-49281
Confidence: 0.94
Source: Page 1
Region: [document coordinates]
Enter fullscreen mode Exit fullscreen mode

This is deliberate.

If a model tells me that the invoice number is INV-49281, I don't just want the answer.

I want to know how confident it is and where it got the answer from.

That information becomes extremely important later when Verdandi starts independently checking what the model said.

Vision first, verification second

The VLM is therefore not the final authority in Verdandi.

That distinction is important because vision models are still probabilistic systems. They can misunderstand a field, confuse similar numbers, misread a table, or confidently produce an answer that looks perfectly reasonable while being completely wrong.

Verdandi was built around making sure the VLM doesn't act as the Judge, Jury and Executioner

Text-Pipeline

Building the text representation

The OCR layer produces text, but Verdandi doesn't treat it as one enormous string.

The extracted text is retained alongside information about where it appeared on the page.

That gives the system a representation closer to:

Page 1
 ├── "Invoice Number"      → region A
 ├── "INV-49281"           → region B
 ├── "Invoice Date"        → region C
 └── "14/08/2026"          → region D

Page 2
 ├── ...
 └── ...
Enter fullscreen mode Exit fullscreen mode

This matters because documents are spatial.

If I search a 30-page invoice for 49281, finding the number somewhere in the document isn't necessarily useful. I want to know whether it appeared in the place where the model claimed it found the invoice number.

The text pipeline therefore preserves enough of the document's structure to let Verdandi reason about both what was written and where it was written.

The Text Oracle

This eventually led to one of the core ideas in Verdandi: the Text Oracle.

Suppose the vision model extracts:

Invoice Number: INV-49281

and tells Verdandi that it found the value in a particular region of page one.

The Text Oracle gets a much less glamorous job.

It asks:

"Can I actually find **INV-49281** in the text around that region?"

If the answer is yes, we have independent evidence supporting the model's extraction.

If the answer is no, Verdandi doesn't try to be clever and invent a replacement.

It raises a flag, and this is an important difference.

For a document-processing system, "close enough" can be spectacularly wrong.

Why not just use another AI model?

Because that would defeat much of the point.

If the first VLM says:

"The invoice number is INV-49281."

and I ask another VLM:

"Do you agree?"

I now have two probabilistic systems agreeing with each other.

That can be useful in some situations, but it doesn't give me an independent source of truth.

Confidence Scores

Getting an answer from a vision model is only half the problem.

The other half is figuring out whether I should actually trust it.

This sounds like something that should be easy. Just ask the model how confident it is and use the number it gives you.

Unfortunately, that would be a little like asking a student how confident they are immediately after they've submitted an exam and using their answer to calculate their grade.

So Verdandi treats confidence as a piece of evidence, rather than a verdict.

Model confidence is only the beginning

For every extracted field, the vision model provides a confidence value alongside its answer.

For example:

Invoice Number
Value: INV-49281
Model confidence: 0.94
Enter fullscreen mode Exit fullscreen mode

That's useful, but it doesn't tell me whether INV-49281 actually exists in the document.

A model can be highly confident and still be wrong.

So Verdandi combines the model's confidence with information gathered from the rest of the pipeline.

Confidence is field-level

Another important decision was to make confidence granular.

A document shouldn't receive one giant:

Confidence: 87%

score.

Imagine a customs document with fifty extracted fields.

Forty-nine might be perfectly grounded while one field is ambiguous because the scan is damaged.

A document-level score would hide that problem.

Verdandi instead evaluates confidence at the field level, so uncertainty can be attached to the specific piece of information that caused it.

That allows the system to say, effectively:

Invoice Number     ✓ High confidence
Invoice Date       ✓ High confidence
Currency           ✓ High confidence
Tax Amount         ⚠ Review
Total              ✓ High confidence
Enter fullscreen mode Exit fullscreen mode

Confidence can trigger action

This is where confidence becomes useful rather than decorative.

A low-confidence extraction can be flagged for review.

uncertainty becomes actionable.

Instead of forcing a human to manually inspect every extracted field, the system can direct their attention toward the parts that actually deserve it.

The important thing is what happens when confidence is low

Verdandi isn't designed around the idea that every uncertain field should be automatically repaired.

In that case, the answer is simply:

send it to a human.

That is an important philosophical distinction for document processing.

A system that returns an answer for every field is not necessarily a reliable system.

A reliable system should also be capable of saying:

"I don't have enough evidence to tell you this confidently."

That's ultimately what I wanted confidence scores in Verdandi to represent.

Not how confidently an AI can make a claim, but how much confidence the system has earned in that claim.

Custom Extraction Rules

One of the easiest ways to make a document extraction system unusable is to hard-code every document type into the application.

Today you need an invoice.

Tomorrow someone wants a government document.

Next week someone wants an insurance claim form.

Eventually you end up with something that looks like:

if document == invoice:
    do_invoice_things()

elif document == government_document:
    do_government_document_things()

elif document == insurance_claim:
    do_insurance_claim_things()

this is a very watered down explanation of the problem, but it's pretty funny
...
Enter fullscreen mode Exit fullscreen mode

I wanted Verdandi to work differently.

The extraction engine shouldn't need to know what an invoice, a customs declaration or an insurance document looks like. It should simply know how to execute an extraction definition.

Rules are data, not code

Verdandi uses custom document profiles to define what information should be extracted from a particular document.

A profile can describe things such as:

  • the document type

  • the fields that need to be extracted

  • the expected data type

  • whether a field is required

  • extraction instructions

  • validation requirements

  • confidence requirements

  • line-item structures

  • relationships between fields

The important part is that these definitions live outside the core extraction engine.

So adding a new document type doesn't mean opening the extraction code and teaching Verdandi a completely new way of thinking.

You define what the document contains.

Verdandi already knows how to process documents.

That distinction is one of the most important architectural decisions in the project.

The same engine, different documents

Consider an invoice.

You might define fields such as:

Invoice Number
Invoice Date
Currency
Subtotal
Tax
Total
Enter fullscreen mode Exit fullscreen mode

A Bill of Entry might instead require:

BE Number
Importer
Port of Entry
HS Code
Assessable Value
Duty
Country of Origin
Enter fullscreen mode Exit fullscreen mode

The extraction engine doesn't fundamentally change.

The schema does.

This means the same underlying pipeline can process completely different document types without requiring a separate implementation for every one.

And that matters because the entire point of Verdandi is that document intelligence shouldn't have to be reinvented every time the industry changes.

Extraction rules aren't just field names

A field definition can also carry information about how that field should be interpreted and subsequently validated.

For example, if a field is supposed to be a date, Verdandi knows it isn't dealing with an arbitrary string.

If a field represents a monetary amount, it can be subjected to numerical validation.

If a document contains line items, the profile can define the structure of those rows rather than treating the entire table as one enormous blob of text.

This creates an important separation:

The model handles interpretation.

The extraction profile defines what interpretation is required.

The verification layer determines whether the resulting interpretation makes sense.

Each layer has a different job.

Document Review

At some point while building Verdandi, I had to accept an uncomfortable fact:

There is no point trying to make an AI document extraction system that never needs a human.

At least not if the alternative is a system that confidently gives you the wrong answer.

Documents can be blurry. Fields can be ambiguous. OCR can fail. A model can misunderstand a table. Two documents can disagree. Sometimes the information simply isn't there.

The goal, therefore, isn't to eliminate the human.

It's to make sure the human only has to look at the parts that actually need them.

From extraction to review

Verdandi's extraction pipeline is designed to surface uncertainty as it moves through the system.

A field might have low model confidence.

The Text Oracle might fail to find the extracted value.

An arithmetic rule might fail.

A cross-document validation might find two conflicting values.

Instead of quietly pushing that field into the final output, Verdandi can turn it into something a human can review.

This changes the workflow from:

PDF
 ↓
Verdandi
 ↓
Excel
 ↓
Human discovers something is wrong later
Enter fullscreen mode Exit fullscreen mode

to:

PDF
 ↓
Verdandi
 ↓
Validation
 ↓
Uncertain / contradictory fields
 ↓
Human review
 ↓
Final output
Enter fullscreen mode Exit fullscreen mode

The difference is subtle, but important.

The human is no longer doing the extraction.

They're doing the exception handling.

Humans can actually make the final decision

The review process isn't just a glorified approval button.

A reviewer can inspect the flagged extraction and determine what the correct value should be.

If the model is wrong, the value can be corrected.

If the value is actually correct despite failing an automated check, the reviewer can accept it.

If the document genuinely doesn't contain enough information to resolve the issue, the reviewer can leave it unresolved rather than forcing a guess.

The final output therefore retains the distinction between:

what the model originally extracted

and

what was ultimately accepted or corrected.

That distinction matters for traceability.

Run Explorer

Once Verdandi started doing more than simply sending a PDF to a model and waiting for some JSON to come back, another problem appeared.

If an extraction went wrong, I needed to know why.

Not just:

"The invoice number is incorrect."

I wanted to know:

Which model produced it?

What did the OCR layer see?

How many attempts did the extraction take?

Did a validation rule fail?

Did the Text Oracle find the value?

Was another model called?

What did Verdandi ultimately decide?

At that point, a simple output file wasn't enough.

So I built the Run Explorer.

A document run is more than its final JSON

A Verdandi run can involve considerably more than one model call.

Depending on the document and workflow, it can involve:

PDF
 ↓
Document detection
 ↓
OCR
 ↓
Vision model
 ↓
Extraction
 ↓
Validation
 ↓
Flags
 ↓
Retries / rechecks
 ↓
Second opinion
 ↓
Human review
 ↓
Final output
Enter fullscreen mode Exit fullscreen mode

If something goes wrong somewhere in that chain, the final JSON doesn't tell you much about what happened along the way.

The Run Explorer exists to preserve that history.

Instead of treating a run as:

Input → Output

Verdandi treats it more like:

Input → Process → Evidence → Decisions → Output

What actually happened?

The Run Explorer exposes the metadata and intermediate information associated with a processing run.

This includes things such as:

  • model usage

  • token consumption

  • extraction attempts

  • validation results

  • flags

  • run metadata

  • processing events

  • generated outputs

  • errors and failures

  • relevant intermediate artifacts

This makes it possible to inspect a run after the fact rather than trying to reconstruct it from memory, logs and a slightly haunted terminal window.

Cost becomes observable

Token usage is particularly important when working with vision models.

A document isn't just a prompt.

You might be processing multiple pages, sending images, retrying an extraction, or invoking another model to resolve a disagreement.

The cost of a run can therefore vary considerably depending on what happened inside it.

Verdandi exposes that information instead of hiding it behind a single "processing complete" message.

That means I can answer questions like:

Why did this document cost more to process than the previous one?

or:

Which model is consuming the most tokens in this workflow?

or:

Did a retry actually improve the result enough to justify the additional processing?

Those are difficult questions to answer if the only thing the system gives you is a final Excel file.

Debugging document intelligence

This also changes how the system can be developed.

Suppose I change an extraction rule and suddenly accuracy gets worse.

Without run-level observability, I might know that the output changed, but not necessarily why.

With the run history, I can inspect what changed in the pipeline and determine whether the issue came from:

  • the model

  • the prompt

  • OCR

  • validation

  • a retry

  • a changed document profile

  • or something further downstream

That makes the Run Explorer useful not just for users, but for improving Verdandi itself.

Cross-document Validation

Once Verdandi could process multiple documents as part of the same workflow, another problem became obvious.

Sometimes the information you need to validate doesn't exist in one document.

It exists in the relationship between several documents.

Take a shipment with an invoice and a Bill of Entry.

The invoice might contain:

Bill of Entry: 1234567
Enter fullscreen mode Exit fullscreen mode

And the Bill of Entry might contain:

Bill of Entry: 1234568
Enter fullscreen mode Exit fullscreen mode

If I process those documents independently, there is nothing obviously wrong with either extraction.

Both fields contain valid-looking numbers.

Both might have high confidence.

Both might even be correctly grounded in their respective documents.

And yet, one of them is wrong.

This is where cross-document validation comes in.

Documents can validate each other

Verdandi allows fields from different documents within the same workflow to be compared against each other.

Conceptually, a rule can say:

Invoice.BillOfEntryNumber
        MUST EQUAL
BOE.BillOfEntryNumber
Enter fullscreen mode Exit fullscreen mode

Or:

Invoice.Currency
        MUST MATCH
Payment.Currency
Enter fullscreen mode Exit fullscreen mode

Or:

Invoice.Total
        MUST AGREE WITH
Expected transaction value
Enter fullscreen mode Exit fullscreen mode

The exact relationship depends on the workflow, but the underlying idea is the same:

Don't just ask whether each document makes sense by itself. Ask whether the documents make sense together.

This catches a different class of errors

This is important because not every extraction error can be detected by looking at the document that produced it.

A field can be:

  • correctly formatted

  • confidently extracted

  • present in the source text

  • located in the correct region

and still be wrong in the context of the overall transaction.

That's the annoying part.

A perfectly extracted mistake is still a mistake.

Cross-document validation gives Verdandi another layer of evidence that individual document validation simply can't provide.

The system doesn't decide which document is wrong

There's another deliberate choice here.

If two documents disagree, Verdandi doesn't automatically decide that one of them must be incorrect.

Suppose:

Invoice → ₹1,48,200
BOE     → ₹1,52,700
Enter fullscreen mode Exit fullscreen mode

There are several possible explanations.

One document could contain an error.

The values could represent different concepts.

One document could have been updated while the other wasn't.

Or the extraction itself could be wrong.

The validation system's job is therefore not to play judge.

It's to say:

"These two things don't agree. Someone should look at this."

That distinction is particularly important for financial and compliance-related documents, where automatically "fixing" one value based on another could be much worse than simply flagging the discrepancy.

Cross-document validation is also configurable

Just like the extraction rules and workflows themselves, these relationships are defined rather than hard-coded into the application.

The user can specify which fields should be compared and what relationship they are expected to have.

That means the same validation engine can support completely different workflows.

A global trade process might compare:

  • Bill of Entry numbers

  • invoice values

  • currencies

  • quantities

  • HS codes

  • shipment identifiers

An insurance workflow might compare completely different fields.

The underlying mechanism doesn't need to know anything about the industry.

It only needs to understand the relationship being defined.

From extraction to consistency

This is probably the point where I stopped thinking of Verdandi as simply a document extractor.

Cross-document validation asks something slightly more powerful:

"Do all of these documents tell the same story?"

And that is a very different problem.

A document can be perfectly readable.

The OCR can be correct.

The VLM can extract the field correctly.

The Text Oracle can verify it.

And the workflow can still discover that something is wrong.

Because sometimes the error isn't inside a document.

It's between them.

Export to Excel/JSON

After all of that, there is a surprisingly important final question:

What am I supposed to do with the data now?

Getting a beautifully validated JSON object trapped inside an application isn't particularly useful if the person who requested the extraction ultimately needs an Excel file.

The output layer is therefore deliberately boring.

And I mean that as a compliment.

JSON when you want the machine to keep going

JSON is the natural output for programmatic workflows.

It preserves the structured representation produced by Verdandi, including the extracted fields and the information associated with them.

That makes it useful when Verdandi is one component in a larger system rather than the final destination for the data.

The idea is simple:

Document
   ↓
Verdandi
   ↓
Structured JSON
   ↓
Your application / database / workflow
Enter fullscreen mode Exit fullscreen mode

No proprietary format required.

Excel when a human needs to do something with it

Excel is a slightly different beast.

A lot of the work Verdandi is designed to eliminate ultimately ends up in spreadsheets anyway, so pretending Excel doesn't exist would be a little counterproductive.

Verdandi can therefore turn the structured extraction into an Excel workbook designed around the document schema and workflow.

That can include the extracted fields, validation state, issues and line-item information rather than simply dumping everything into one enormous cell and calling it a day.

For documents containing tables, this distinction matters particularly.

A line-item table should remain a line-item table.

It shouldn't become:

["Item 1", "Item 2", "Item 3", ...]

inside cell A17.

The point of all of this

This might be the least glamorous feature in Verdandi, but it completes the entire pipeline.

The objective was never to build an impressive AI demo where a PDF goes in and a futuristic-looking UI displays some extracted fields.

The data has to go somewhere useful.

Sometimes that means another application consuming JSON.

Sometimes it means a consultant opening Excel five minutes later.

And, given where this whole project started, there's something mildly satisfying about that.

I started Verdandi because I was tired of people manually copying information from PDFs into Excel.

The final step of the pipeline is therefore making sure the machine does the copying this time.

Console

If Verdandi is going to let me choose models, configure extraction rules, inspect runs and optimise processing, I need somewhere to actually see what the system is doing.

That place is the Console.

I didn't want the usual AI application experience where the interface tells you:

Processing document...

and then, several seconds later:

Done!

Great.

What happened in those several seconds?

The model might have processed ten pages. OCR might have run on six of them. A field might have failed validation. A retry might have been triggered. A different model might have been called. Thousands of tokens might have been consumed.

And the UI would still just say:

Done.

That's not particularly useful.

The Console is the engine room

The Console exposes the parts of Verdandi that would normally disappear behind the UI.

Model configuration.

Processing metadata.

Token usage.

Flags.

Runtime information.

Provider configuration.

And the information needed to understand how Verdandi is actually behaving.

The idea is simple:

If Verdandi is doing something on your behalf, you should be able to see enough of it to understand what happened.

Conclusion

Completely usable by people from a non-technical background and can go up against some of the best options for Document intelligence out there - That's what I wanted to build. There's a lot more features I wanted to implement into Verdandi - like self learning - where the pipeline took into account the human verified output for documents and used that as context when processing similar documents in future runs, or a document explainer where you can ask any details about a document and pretty much have a conversation with it, but I remembered that line from Arcane - "there is no price to perfection only an end to pursuit" (don't judge)

How I wished something like this existed during my time at EY. It's nice to see Verdandi be a usable application rather than an idea on Obsidian I jotted down and forgot about. All the complaining about "surely there's no way consultants spend all day copying data from documents at a big 4" feels a lot more substantiated after building something that does the job.

Having said that, this is part where I have to be humble and provide a disclaimer. Verdandi has rough edges and there are aspects where further development is needed. I'm probably gonna put this up on reddit for a brutal feedback, because if not reddit, where else can you get a bunch of people to be extremely honest about what you built.

Built using the indomitable human spirit and models from Moonshot, Deepseek and OpenAI

Download Verdandi from here --> https://github.com/Akshay-M-Singh/verdandi-app

Top comments (0)