Skip to main content

analyze-extraction-confidence

Use when analyzing, profiling, or thresholding confidence scores from ai_parse_document (element confidence) or ai_extract v2.1 (confidence_score with enableConfidenceScores), when deciding which documents, pages, or extracted fields need human review, or when confidence-based review flags fire on nothing or on everything.

Source facts

Repository
databricks-solutions/advance-document-processing
Last source activity
November 3, 2026 at 05:14
Detected SKILL.md language
English
Stars
2
Forks
5

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
analyze-extraction-confidence
description
Use when analyzing, profiling, or thresholding confidence scores from ai_parse_document (element confidence) or ai_extract v2.1 (confidence_score with enableConfidenceScores), when deciding which documents, pages, or extracted fields need human review, or when confidence-based review flags fire on nothing or on everything.
# Analyzing ai_parse_document / ai_extract Confidence ## Overview Confidence from these functions does not look like a smooth 0–1 probability, so fixed thresholds misfire. **Profile the observed distribution first, then flag relative to it.** Confidence is a routing signal: flagged items go to a review queue; nothing is dropped. For function syntax, use the `databricks-ai-functions` skill. Scoring accuracy against labels is out of scope (only calibration is covered here). ## Shapes and behavior (verified on live output) | | ai_parse_document v2.0 | ai_extract v2.1 | |---|---|---| | Where | `parsed:document:elements[i]:confidence` (page: `bbox[0]:page_id`) | `extracted:response:<path>:{value, confidence_score}` — **leaves only**; objects and arrays have no score | | Typical spread | Bunched near 1.0 (median ≈ 1.0; min ≈ 0.8 on born-digital PDFs); differs by element `type` | A handful of discrete levels (e.g. 0.95 / 0.98 / 1.0) with rare low outliers (0.1, 0.75) | | Missing | — | **Absent** field = `{value: null, confidence_score: null}`; **unscored** = value present, score null | ## Core pattern 1. Look at the distribution: `parse_type_profile` (per type) and `extract_level_profile` (distinct levels with counts). 2. **Parse:** flag elements below their **own type's** low percentile (default p5). An absolute floor like 0.5 or 0.8 flags nothing when scores sit near 1.0. 3. **Extract:** flatten nested leaves recursively, then flag scored leaves strictly below the corpus p5 **level**. Discrete levels make the cutoff land on an observed value, so ties at the cutoff are not flagged. 4. Keep three leaf states apart: absent (not a review item by itself), unscored (review), scored. 5. Roll up per page and per document; a document whose usual level sits below the corpus's is a document-level shift worth one look, not 30 field flags. 6. Calibration only with labels: correct rate **per observed level**, never per fixed 0.1-wide bins (most bins would be empty). ## Implementation `scripts/confidence_profile.py` implements steps 1–6 and is unit-tested. Copy the file's contents **unchanged** into one notebook cell, then: ```python els = parse_elements(spark.table("<cat>.<sch>.<parsed_table>"), parsed_col="parsed", doc_id_col="path") display(parse_type_profile(els)) # look first flagged_els = flag_parse_elements(els, pct=0.05) # optional abs_floor= for scanned corpora display(parse_page_rollup(flagged_els)) leaves = extract_leaves(spark.table("<cat>.<sch>.<extracted_table>"), extracted_col="extracted", doc_id_col="path") display(extract_level_profile(leaves)) # look first flagged_leaves, cutoff = flag_extract_leaves(leaves, pct=0.05) display(extract_doc_summary(flagged_leaves)) display(extract_field_summary(flagged_leaves)) review_queue(flagged_leaves, flagged_els).write.mode("overwrite").saveAsTable("<cat>.<sch>.confidence_review_queue") # with labels (doc_id, path, is_correct): display(calibration_by_level(flagged_leaves, labels)) ``` Several extraction VARIANT columns in one table (one per document type)? Union them into one `(path, extracted)` frame first so the corpus cutoff uses every leaf. ## Common mistakes | Mistake | Fix | |---|---| | Absolute parse floor (0.5 / 0.8) | Per-type percentile; read `parse_type_profile` first | | Pooling all element types | Tables, titles, and `text` score differently; cutoffs per type | | Reading `response:<field>:confidence_score` only | Nested objects/arrays have no top-level score; flatten to leaves | | Treating absent fields as low-confidence or "missing score" | `value` null = absent; only value-present-score-null is unscored | | Dropping unscored leaves (`confidence IS NOT NULL`) | Route them to review; a whole extraction can come back unscored | | Flagging "below the field's usual level" | Adjacent high levels (0.95 vs 0.98) flood the queue; use the corpus p5 level | | Fixed-width calibration bins | Group by observed level | | `calibration_by_level` on a stratified audit sample | It averages labels as given; with stratified labels, weight each row by stratum size / sample size | | Reading every parse flag as equally urgent | In types whose cutoff is ≥ 0.999 (page headers/numbers) gaps are tiny; review them last, don't drop them | | `assert IQR > 0` / z-scores on saturated scores | Percentiles with strict `<` handle ties and saturation |
View on GitHub