All projects

RVL-CDIP-Classifier

Vision LLMs & prompt engineering

At a glance

82.6% accuracy on 1,120 images (925 correct). The slice shares at least 320 images with the 800-image slice; overlap with tuning not verified

99.4% on the 160-image slice I tuned against, so an optimistic number

29 registered prompt versions, v0 to v19

≈ $0.0004 per image for the main model

The problem

RVL-CDIP is the standard benchmark for document-type classification: scanned pages from a tobacco-litigation archive, sorted into 16 classes such as invoice, memo, letter and budget. Models trained for it usually need labeled data and a fine-tuning pipeline. I wanted to know how far a general-purpose vision model could get with no training at all, using only the prompt, and what that would cost.

Approach

The model gets the page image and a long written prompt. The prompt names the 16 classes and then walks through an ordered list of checks, so that a page is judged by what it does rather than what it is about. I changed the prompt one version at a time and scored every version the same way, so each change could be traced to a number.

What I built

Results

On the 160-image slice, accuracy climbed from 80.1% at v1 to 99.4% at v11.8. That is a tuning-slice number. I read the misses on that slice and wrote rules for them, so it overstates what the prompt can do on pages it has not seen.

Line chart of exact-match accuracy on the 160-image tuning slice for prompt versions v1, v4, v7, v10, v11 and v11.8, rising from 80.1 percent to 99.4 percent.

Accuracy of qwen3.7-flash on the 160-image tuning slice across prompt versions, rising from 80.1% at v1 to 99.4% at v11.8.

The honest headline comes from larger slices. The same v11.8 prompt scored 82.6% on a balanced 1,120-image slice. That slice is a seeded, class-balanced sample of 70 images per class from the Hugging Face mirror of RVL-CDIP, which holds 100 per class across its three splits. The 800-image slice is the mirror’s train split (50 per class), so the two slices share at least 20 images per class, 320 in all, and the 83.1% and 82.6% results are not independent. I did not verify whether the 1,120-image slice shares images with the 160-image tuning slice. Across slice sizes it scored 87.2% at 320 images, 89.1% at 476 scored images, and 83.1% at 800. On that 800-image slice, the untuned v0 prompt scored 66.1%, so the prompt work is worth about 17 points on that slice. I did not check whether the 800-image slice shares images with the 160-image tuning slice either.

Line chart of v11.8 exact-match accuracy against slice size, falling from 99.4 percent at 160 images to 87.2, 89.1, 83.1 and 82.6 percent at 320, 480, 800 and 1,120 images.

v11.8 accuracy by slice size: 99.4% on the 160-image tuning slice, then 87.2%, 89.1%, 83.1% and 82.6% on larger slices. The 800- and 1,120-image slices overlap.

Heads up. The 160-image points in both charts come from the slice I iterated on. The 1,120-image point is the one to quote. The 1,120-image slice shares at least 20 images per class with the 800-image slice, so those two results are not independent evidence. I did not check it against the 160-image tuning slice or the other earlier slices, so it may share images with them. Treat it as a better estimate than the tuning slice, not as a clean test.

Where it fails is consistent. Budget (67.1%), letter (70.0%), presentation (70.0%) and scientific report (71.4%) are the weak classes on the 1,120 run, and the most common single error is letter predicted as memo (16 cases). In 72 of the misses, the correct class was the model’s own runner-up.

What the simulations showed

The repository’s Monte Carlo scripts treat every recorded run as a draw from a per-image distribution of answers, then resample it to ask “what if” questions without spending any model credits. They work on a pooled corpus of 5,599 rows covering 1,512 images from 18 experiments. The corpus mixes prompt versions and models, so its 82.1% baseline is a pooled rate and not the best prompt’s accuracy. For the same reason, a “read” in the voting forecast is a draw from that mixed pool, not a repeat of one fixed classifier.

Question What the simulation said What I measured
Would majority voting help? Forecast from the pooled, mixed-model corpus: 7 reads, 85.0%; 25 reads, 86.3%. Cost assumed to scale with the number of reads. Not tested on a live run.
Would sending the least-confident pages to a stronger model help? The least-confident 40%: 91.9% at 1.8 times the cost, if the stronger model is 90% accurate at 3 times the cost. Down, not up. On a 48-image low-confidence slice, 66.7% became 62.5%. On the tuning slice, v19 went from 97.5% to 96.9% at 7.8 times the cost.
Would a few worked examples for the commonest confusions help? About 4.3% of errors fixed (33 of 767). Down. On a 48-image slice, 68.8% became 64.6%.
Which prompt changes were real? A paired bootstrap on shared images puts v0 to v11.8 at +13.0 points (95% interval 10.1 to 15.9, 898 images). This one is a test of measured runs, not a forecast.
Would retries and a fallback model cover API failures? With a fallback, 0.11% of calls fail, against about 2.9% without one. Extra retries barely matter. Modelled only.

Four findings stood out.

I also mined the reasoning traces for the words that appear when the model stops checking early. The prompt works through up to 14 checks in order, and the typical trace stops at check 9.4. Words such as “minutes”, “routing” and “variance” show up in traces that stop early and are wrong far more often than the 17.1% baseline error rate. Each appears in only 10 or 11 traces, so these are leads to test and not findings.

Horizontal bar chart of the ten words with the highest hasty-score, from minutes at 1.89 down to survey at 0.71, with routing, variance, products, addresses, introduction, process, meeting and food between them.

Ten words associated with the model stopping earlier and erring more, scored by how much earlier it stops and how much the error rate rises, against a 17.1% baseline error.

Chart of simulated accuracy and cost factor against the fraction of images escalated to a stronger model, with accuracy peaking at 91.9 percent and cost reaching 2 times at 50 percent.

Simulated confidence-gated escalation: accuracy peaks at 91.9% at a 40% escalation fraction and 1.8 times the cost.

Heads up. These are resampled results from recorded runs, not new experiments. Two of the forecasts I tested by measurement, routing and worked examples, and neither held up. Voting and the failure model are untested, and the word list rests on small counts. The report has the full tables.

Explore the data and tools

The repository ships the tooling I used to look at the data and to watch the runs, and a Quarto site that pulls the results together. The site renders offline with no model spend.

What I learned

Stack

Python OpenRouter Vision-language models Prompt engineering Tesseract OCR Monte Carlo simulation Braintrust Quarto Error analysis pytest

Credits

Built with co-author Grant Mooslin, advised by Siddharth Suresh. The dataset is RVL-CDIP (Harley, Ufkes and Derpanis, 2015).