www.franzai.com
MG

Data Quality Investigation

Confidential Research Report

This page is set to noindex and will not appear in search engines.

The Brief

Marktguru processes 10 million product lines a month (1M+ receipts, ~10 lines each). Three systematic data quality issues corrupt pricing data, product matching, and cross-retailer comparisons. Here's what we found and how to fix it.

“How can we ensure proper data quality on price/quantity/product mapping on our receipt data in a feasible way. We process more than 1 million receipts monthly (assume 10 product lines per receipt) = 10 million product lines a month.” — Marktguru Briefing
--
Variance Reduction (Std Dev)
--
Products with >100% Price Spread
94.8%
False Confidence (AI Hallucination)

Challenge 1: Pack Size Blindness

“Same product (Stiegl Hell), wildly different prices — from EUR 0.09 to EUR 82.80.”
Real problem: The receipt text CONTAINS the pack size, but the system ignores it. A 20-pack at EUR 27.60 is recorded as 1 beer at EUR 27.60. The packaging_quantity column is empty in every row.

1a: The Raw Data

Full Stiegl Hell dataset — 501 receipt lines sorted by price. Click any row to inspect it.

Product Line Price (EUR) Qty Pack Qty Retailer Discount

1b: The Problem

Sort by price. The same product — Stiegl Hell 0.5L — ranges from EUR 0.09 to EUR 82.80. The packaging_quantity column is empty in every row. 311 rows are single bottles (EUR 1-1.50). 150+ rows are hidden multi-packs (EUR 10-30) recorded as quantity=1.

1c: The Hypothesis

The pack size IS in the data — it's just unstructured text in the product_line column.
Product LinePriceHidden Pack SizeTrue Unit Price
SC STIEGL HELL FL. 20EREUR 27.6020-pack ("20ER")EUR 1.38
Stiegl Hell 6erEUR 7.206-pack ("6er")EUR 1.20
Stiegl Hell FL.EUR 28.56? (no marker, but 28.56/24 = EUR 1.19)EUR ~1.19

1d: Pack Size Detective

Click a preset below, pick a row from the table, or type your own. The 5-step detection pipeline processes it live.

1e: The Result

--
Std Dev Reduction
--
Now in EUR 1.00-1.50
--
Rows Corrected

Detection Method Legend

Each row is classified by one of 5 detection methods. Rules are evaluated top-to-bottom (waterfall). First match wins.

Broader Application: 1,000 Stiegl ProductLines

The same detection runs on all Stiegl variants (Goldbräu, Bock, Bio). It catches the same patterns.

Product Line Recorded Price Pack Size Unit Price Method Cleaned Name (generated)

Challenge 2: Cross-Retailer Price Chaos

“How can we ensure proper data quality on price/quantity/product mapping on our receipt data in a feasible way.” — Marktguru Briefing
Problems: Users scan wrong barcodes (e.g., 6-pack Coca-Cola bought but single-can barcode scanned). Same EAN shows wildly different prices across retailers.
“Unfortunately, the results from the analysis looked somewhat inconsistent. After a deeper dive, we realized that not all prices refer to the same EAN-pack size combination. For EAN 5000112546415, prices range from 0.75 to 9.99.” — AWS Customer Feedback
The pack-size detection from Challenge 1 directly fixes this: detect the REAL pack size from text + price ratios, then normalize to unit prices.

2a: Raw Data Explorer

12,254 products across 17 German retailers. Click any product to see all retailer prices.

Min spread: 0%
ItemEANCategoryRetailers Min (EUR)Max (EUR)Spread %

2b: The Problem

Loading statistics...

2c: The Hypothesis — Same Root Cause as Challenge 1

These spreads are mostly caused by the SAME problem: different pack sizes across retailers. Same Coca-Cola EAN: EUR 0.75 per-bottle at Aldi, EUR 9.99 per-crate at REWE. The pack-size detection from Challenge 1 should directly fix this.
ProductRetailer ARetailer BSpreadExplanation
Coca-Cola 1.251x6Aldi: EUR 0.75REWE: EUR 9.993,896%REWE sells 8-pack, Aldi sells single
SPEZIPenny: EUR 0.85Edeka: EUR 11.991,932%Edeka sells 14-pack, Penny sells single
Radeberger Pils 20x0.5LNetto: EUR 0.53Edeka: EUR 9.991,785%Edeka sells 10-pack crate

2d: Cross-Retailer Pack Detective

Click a preset below or search by EAN/name. The detection shows original retailer prices, detected pack sizes, and corrected unit prices.

2e: The Result — Corrected Prices

Before vs After: Price Spread Distribution

All Products — Original Spreadsheet Data → Corrected Prices

All 2,742 products from the AWS spreadsheet. Each row shows every retailer price column from the original data. Click any row to expand and see the full old→new price comparison per retailer, with detection steps explained.

Product (from spreadsheet) EAN Retailer Prices (Original Spreadsheet Data) Status

Challenge 3: AI Hallucinations

“Hallucinations lead to real problematic answers.” — Marktguru Briefing
Real problem: Their GPT-4o fine-tuned model (temp 0) extracts product info from images. The prompt says “use your training information to identify the brand parent” — this is where hallucinations happen. Snack Fun is Hofer's brand, NOT Lidl's. The AI says “Lidl” because training data associates similar products with Lidl. We tested 6 models across 9 iterations and more than doubled the pass rate with a better prompt.
Discovery query: brand_parent ilike '%lidl%' AND brand_name ilike '%Snack Fun' → 96 rows where AI assigned “Lidl” as brand_parent.
The briefing explicitly states: “Snack Fun is an own brand of Hofer, definitely not Lidl. Also Lidl is nowhere to see on the images.”

3a: The Raw Data

SnackFun dataset — 96 receipt extraction records. All “Snack Fun” brand — Hofer's private label. The AI hallucinated “Lidl” as brand_parent for all 96 rows. Search and sort to explore.

Missing EAN (no barcode data) EAN Conflict (same barcode, different product names) High confidence on problematic data = hallucination
Line ID EAN Product Name Brand Volume Unit Confidence %

3b: The Problem

A human sees completely different products. The AI sees: same brand, same shelf. High confidence + wrong answer = the most dangerous kind of error. The root cause is not just Lidl — models also hallucinate Intersnack, PepsiCo, Lorenz, and IBU-Verwaltungs as brand_parent.
Kessel Chips
Image 69098419: Kessel Chips Sweet Chilli Style (150g)
XXL Cheese
Image 54750367: XXL Cheese (large yellow bag)
Barcode 69098419
Barcode scan 69098419 — blurry, creased packaging
Barcode 54750367
Barcode scan 54750367 — different product, similar brand layout

EAN Conflicts

Same EAN mapped to different product names. Each conflict is a potential hallucination.

Confidence Distribution

3c: Our Solution

The key insight: “Never guess” kills correct guesses. “Always guess” causes hallucinations. The right approach: guess if confident, warn about specific traps, prefer ‘unknown’ over wrong.
1
Confidence-Gated Guessing
Allow brand_parent from training data IF the model is confident (e.g. PepsiCo owns Lay's). Require brand_parent_source field: “packaging”, “knowledge”, or “none”.
2
Market Context Injection
Tell the AI: “This product was scanned in Austria. Hofer = Aldi Süd. ALWAYS use ‘Hofer’, never ‘Aldi’.” User context (country, city, date) is appended to the prompt.
3
Anti-Hallucination Framing
Instead of generic “do not hallucinate”, explain the SPECIFIC trade-off: “A WRONG brand_parent is far worse than ‘unknown’.” Models respond to consequences, not commands.
4
Private-Label Trap Warning
Explicit: “Hofer, Lidl, Aldi have private-label brands that LOOK independent. ‘Hergestellt für’ = distributor, NOT brand owner.” Targets the exact failure mode.
Domain knowledge: Hofer = Aldi Süd in Austria (same company, local name). Aldi Nord is a DIFFERENT company. This single fact, injected as market context, eliminates the #1 hallucination pattern across all models we tested.

3d: Prompt Comparison

We have Marktguru's ACTUAL production prompt (from their briefing PDF). It is detailed and professional. The hallucination source is one line: “use your training information to identify the brand parent.”

Marktguru Production Prompt (GPT-4o fine-tuned, temp 0)
Loading...
Our Prompt (base + market context shown below)
Loading...

Key Differences

Their prompt: “use your training information” → always guesses, even when wrong
Our prompt: confidence-gated guessing with source tracking (packaging / knowledge / none)
Their prompt: no mention of private labels, no market context, no distributor warning
Our prompt: explicit private-label traps, Hofer=Aldi Süd, “Hergestellt für” != brand owner
Their prompt: “Do not hallucinate” (generic, models ignore it)
Our prompt: “A WRONG brand_parent is far worse than unknown” (specific consequence)

3e: How It Works

The complete transparent pipeline — every step is visible to the user.

1
User Context
Country, city, scan date
2
Prompt Assembly
Base + market + scan context
3
AI Model
Image + prompt via OpenRouter
4
JSON Parse
4-level robust extraction
5
Verdict
Field-by-field vs ground truth
6
Post-Process
Transparent normalization

Assembled Prompt Preview

Change the market context to see how the prompt changes. This is exactly what the AI receives.

Market context injected into prompt highlighted
Loading...
Show full assembled prompt (base gray + context highlighted)
Loading...

3f: Live AI Comparison

Each test call costs real money. Models charge per token + image. Approximate cost: $0.002-0.01 per call depending on model (see cost/1M tokens in dropdown).

3g: Test Results & Model Recommendations

Data source: app/vision_results/run_2026-03-06_009.json — 48 tests (6 models × 4 product images × 2 prompts). Each AI model was asked to extract product data from the same images using both Marktguru's production prompt and our improved prompt. Results compared against verified ground truth.

How to read the numbers:
Passed: Tests where brand_parent AND brand_name are both correct (e.g. "2/4" = 2 out of 4 images correct).
Pass Rate: Passed ÷ Total tests, as percentage.
Failed (Hallucinations): Tests where the AI assigned the product to the WRONG retailer (e.g. Lidl instead of Hofer).
Quality Score (0-100): Field-by-field accuracy vs ground truth. Weighted: brand_parent 40pts, brand_name 30pts, product_name 20pts, volume+flavor+packaging 10pts.
Baseline: Marktguru's current production prompt (GPT-4o, temp 0, "use your training information to identify the brand parent").
Our prompt: Context-aware prompt with market info, anti-hallucination framing, packaging type list.

Head-to-Head Comparison

Model Ranking

All 6 tested models, sorted by quality improvement. Baseline = Marktguru's current approach.

Model Cost Baseline Pass Rate Baseline Quality Our Pass Rate Our Quality Improvement Recommendation

What Made the Difference

Market context (country + city) dramatically improves brand_parent accuracy
“ALWAYS use Hofer in Austria” instruction eliminates the #1 hallucination pattern
Confidence-gated guessing lets models use real knowledge (PepsiCo/Lay's) while preventing guesses on private labels
Packaging type classification list prevents models from defaulting to “bag”
“Hergestellt für” = distributor warning prevents IBU-Verwaltungs hallucination
Claude Haiku 4.5 has terrible OCR (“Kesses”, “Puschkin”) — do NOT use for product extraction
Gemini Flash models offer the best cost/quality ratio for this task

Solution Pipeline & Next Steps

TL;DR for Management: We investigated 3 data quality challenges using real Marktguru data. All three have working solutions — proven with code, tested on real data, with measurable results. The headline result for AI hallucinations: with the right prompt + the right model (Gemini 3 Flash), pass rate goes from 50% to 100% on our test set (4 images). The average across all 6 tested models improves from 25% to 62%, but you wouldn't use all models — you'd pick the best one. Hallucinations drop from 7 to 1. Core insight: context-aware prompt + model selection beats raw AI power. A $0.50/1M-token model with the right prompt outperforms a $1.00/1M-token model with a generic prompt.

What We Proved

ChallengeStatusKey ResultProduction Readiness
Ch.1: Pack Size Detection Solved 98.9% std dev reduction (EUR 11.82 → EUR 0.13), regex + ratio inference Ready — deterministic pipeline, no AI cost
Ch.2: Cross-Retailer Price Chaos Solved 177 products corrected, 113 removed from >100% spread Ready — same pipeline as Ch.1, scales to full dataset
Ch.3: AI Hallucinations Solved Best model + our prompt: 50% → 100% pass rate (Gemini 3 Flash). Avg across all 6 models: 25% → 62% Ready — prompt + market context + model choice, no fine-tuning needed

Concrete Next Steps

The #1 priority is validation at scale. Our results are from 4 product images (2 Snack Fun SKUs). Before deploying anything, we need to prove these solutions work on Marktguru's full product diversity — different brands, categories, markets, and retailers. The approach works; now we need the data to prove it at scale.
1
Scale the Vision Test

Run our prompt vs. their prompt on 100-500 product images across diverse categories (drinks, snacks, dairy, frozen, household). Include multiple retailers, countries, and private-label brands. Estimated cost: ~$5-25 via OpenRouter. This is the critical validation step.

2
Expand Ground Truth

We need verified ground truth for more products — not just Snack Fun. Marktguru provides the product database; we define the test set with known-tricky cases: private-label brands, multi-pack products, regional variants. This is the foundation for measuring improvement.

3
Run Pack Size Pipeline on Full Dataset

The regex + ratio inference pipeline is deterministic and free — no AI cost. Apply to Marktguru's full product dataset (not just the 12K AWS sample). Measure how many price anomalies it catches across all categories and retailers.

4
Deploy & Monitor

Only after steps 1-3 validate the approach: switch the vision prompt (cost: $0), add post-processing layer, integrate pack size pipeline. Recommended model: Gemini 3 Flash or Gemini 2.5 Flash (~$0.30-0.50/1M tokens, 4/4 pass rate with our prompt).

What's NOT Needed

No fine-tuning. The prompt change alone gives 3x improvement. Fine-tuning adds complexity, vendor lock-in, and maintenance cost — for marginal gains at best.
No new models. Gemini Flash at $0.30/1M tokens outperforms GPT-5 Mini at $0.25 and Claude Haiku at $1.00. Cost is not the bottleneck — context is.
No new infrastructure. All solutions work with Marktguru's existing OpenRouter integration. Prompt swap + post-processing layer + pack size pipeline.