SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Implement information extraction solutions

AI-103: Extract Content from Documents with Azure Content Understanding

20 min readAI-103 · Implement information extraction solutionsUpdated

Extracting content from documents for AI-103 means turning PDFs, Office files and scans into clean, grounded output that agents and RAG pipelines can reason over: layout-preserving markdown, structured fields with confidence scores, and the source location of every value. This lesson covers task 5.2 with Azure Content Understanding in Foundry Tools: choosing between the read, layout, digitalParse and documentSearch analyzers, configuring OCR, layout, formula and figure options, how the markdown encodes tables, checkboxes and pages, defining field schemas, using confidence and grounding, improving analyzers with labeled samples, splitting mixed files, and calling analyzers from REST and Python. It also covers when Document Intelligence is the better choice.

What you’ll learn
  • Choose between Content Understanding content extraction, RAG, domain and custom analyzers and Document Intelligence models by document type, labeling budget, connectivity and cost.
  • Configure document content options (OCR, layout, formulas, barcodes, figure description and analysis, table format) knowing which default on and which default off.
  • Interpret Content Understanding markdown: headings, HTML tables, selection marks, page-metadata comments, LaTeX formulas and figure output.
  • Design field schemas with the right extract, classify or generate method and descriptions that follow Microsoft's best practices.
  • Use confidence scores and source/spans grounding to route low-confidence values to human review, and improve weak layouts with labeled samples.
  • Classify and split multi-document files, call analyzers asynchronously through REST or the Python SDK, and keep production analyzers stable.

Which Foundry Tools option fits a document extraction job?

For most AI-103 document scenarios the answer is Azure Content Understanding in Foundry Tools, with Azure Document Intelligence kept for highly structured forms you can label and for anything that must run on premises. Both are managed services that run OCR, layout analysis and field extraction for you and return per-field confidence and grounding; building your own extraction by prompting a model deployment in Microsoft Foundry gives you neither of those without custom work.

RequirementFits bestWhy
Text, or text plus layout, from documents with no schemaContent Understanding content extraction analyzers (prebuilt-read, prebuilt-layout)OCR and layout only, no generative or embedding model needed
Fields from unstructured documents (letters, reports, policies), or fields the document implies rather than states, with no labeled dataContent Understanding custom analyzer (zero-shot)You describe each field in plain language and a generative model extracts or infers it
Standard structured forms such as invoices, receipts, IDs or tax formsDocument Intelligence prebuilt modelsReady-made models for common form types, nothing to define
Mostly unstructured standard documents such as contractsContent Understanding domain prebuilts (for example prebuilt-contract)A ready-made schema that a generative model fills from free-flowing text
Highly structured forms where you can label training samplesDocument Intelligence custom modelsTrained on your labeled layouts
On-premises or air-gapped processingDocument Intelligence containersThe only option in Microsoft's decision guide that runs without the cloud service
Calibrated per-field confidence and source locationContent Understanding or Document IntelligenceBuilt in; a hand-rolled prompt pipeline must implement this itself

A model that writes its own "confidence: 0.9" or page number into JSON is not a substitute: a self-reported number isn't calibrated, and a page number the model types isn't verified grounding. When a scenario mixes requirements, split it: each workload goes to the tool its deciding constraint points at.

This lesson covers document extraction (AI-103 task 5.2). Indexing that output into Azure AI Search, enrichment skills and hybrid or vector retrieval belong to the sibling task Build retrieval and grounding pipelines; image, audio and video analyzers and how analyzers get their model deployments are covered in the multimodal understanding lesson.

Which content extraction analyzer should you call?

Content Understanding has three content extraction analyzers that turn a file into text without any field schema, and you pick by what the file is and how much structure you need: prebuilt-read for text, prebuilt-layout for text plus structure, and prebuilt-digitalParse for machine-readable files. None of them needs a generative or embedding model, so they work on a Foundry resource with no model deployed.

AnalyzerReturnsReads scans?Use when
prebuilt-readWords, paragraphs, formulas and decoded barcode values; no layout analysis, so no tables, sections, figures or document structureYesYou need only the words (and barcode values), as cheaply as possible
prebuilt-layoutEverything read gives, plus tables, sections and headings, figures, hyperlinks and the structural reading orderYesStructure matters: tables, headings and figures must survive
prebuilt-digitalParseContent parsed from the file's own internal structure and encoding, no OCR; in the GA API (2025-11-01) the analyzer that returns embedded metadata such as author and creation date by defaultNoBorn-digital files (DOCX, digital PDFs) and when file metadata is required

A scanned page is an image, so prebuilt-digitalParse can't read it; Microsoft points scans to read or layout. The preview API extends metadata output to read and layout, but on the GA version digitalParse is the one that returns it.

Cost follows the work done

Content extraction is billed on meters that reflect the processing actually performed: born-digital files such as DOCX are charged at the minimal rate whichever analyzer processes them, OCR-only reading of scanned pages uses the basic meter, and layout analysis uses the more expensive standard meter. RAG analyzers and custom fields add contextualization and generative-model token charges on top. So the cheapest analyzer that meets the requirement wins: read when structure is never used, layout when it is, and a RAG or custom analyzer only when you need what its generative features add.

Which content options control OCR, layout, formulas and figures?

A document analyzer's config switches individual extraction steps on and off, and the defaults split cleanly: the extraction options are on by default and the generative figure options are off. A custom analyzer based on prebuilt-document inherits these defaults and overrides only what its config sets, so an empty config still runs OCR, layout, formula and barcode detection.

OptionDefaultWhat it doesTurn it off / on when
enableOcrtrueReads text from scanned and image-based pagesOff for born-digital PDFs with no scanned pages, to speed analysis
enableLayouttrueTables, sections and headings, figure locations, structural reading orderKeep on whenever tables or headings are needed downstream
enableFormulatrueDetects equations and writes them as LaTeXOff for general business documents; on for scientific or technical content
enableBarcodetrueDetects barcodes, including QR codes and many linear types, and returns their valuesKeep on when an identifier lives in a barcode
enableFigureDescriptionfalseGenerates a natural-language description of each figureOn when figures carry meaning a reader or retriever needs
enableFigureAnalysisfalseExtracts chart data (Chart.js) and diagram structure (Mermaid)On when an agent must read chart values or follow a diagram
tableFormathtmlHow tables are written into the markdownKeep html for merged cells and multi-level headers
chartFormatchartjsOutput format of chart data that figure analysis producesHas no effect unless figure analysis runs

Two habits follow. First, switch off what the content doesn't need: OCR on born-digital files and formula detection on documents without equations add work without adding output. Second, keep on what the output depends on: layout for tables and headings, barcode detection for an ID printed as a barcode, formulas for papers whose equations must come through as LaTeX. Each kind of output traces back to its own switch, so when one kind goes missing, check the option that produces it.

Microsoft documents figure description and chart and diagram analysis as supported only for PDF and image files, so don't expect figure output from other formats.

returnDetails is a different kind of switch: it controls whether the response includes detailed information such as confidence scores, bounding boxes, text spans and metadata, rather than changing what is extracted or how the markdown is written. Per-field confidence and grounding are turned on by their own settings, estimateFieldSourceAndConfidence and estimateSourceAndConfidence (see below).

How does Content Understanding markdown represent document structure?

Every document analysis returns the content as GitHub Flavored Markdown that keeps the document's structure in forms a language model reads well, and anything markdown can't express natively is written as HTML. Knowing the encoding lets you write agent instructions and chunkers that rely on it.

ElementHow it appears in the markdown
Words and paragraphsPlain text in reading order
Detected sections and titlesMarkdown headings (#, ## …)
Tables (default tableFormat html)HTML <table> markup with <th> headers and rowspan/colspan for merged cells
Selection marks (checkboxes)Unicode characters: ☒ selected, ☐ cleared, next to the option text
Page numbers, headers, footers, page breaksHTML comments: <!-- PageNumber="…" -->, <!-- PageHeader="…" -->, <!-- PageFooter="…" -->, <!-- PageBreak -->
FormulasLaTeX (when enableFormula is on)
FiguresAn image reference with the text detected inside it; a generated description becomes the image's title, and figure analysis output follows the image

Page metadata lives in comments

Markdown has no concept of a page, so page metadata is carried in HTML comments. A chunker that must cut at page boundaries splits on the page break comment, and one that must strip repeating running heads drops the page header and footer comments. Sections are headings that follow the document's logical structure, not its pages.

HTML or markdown tables

Setting tableFormat to markdown produces pipe tables, which look simpler to chunk but can't express rowspan or colspan. Financial statements with two-level column headers or merged cells then flatten, and values end up under the wrong column. The default html format keeps that structure inside the markdown.

Figure description versus figure analysis

Without figure options, a drawing appears only as an image reference with its labels. enableFigureDescription adds a short natural-language description, which suits search and short summaries. enableFigureAnalysis goes further: it extracts the data behind charts in Chart.js form (or a table) and writes diagrams such as flowcharts in Mermaid syntax, so an agent can read the plotted values or follow a diagram's branches. Descriptions summarise and lose detail; analysis preserves values and branches. Use both when you need both.

How do you produce RAG-ready output with prebuilt-documentSearch?

prebuilt-documentSearch is the Content Understanding RAG analyzer Microsoft recommends for ingesting documents into retrieval workflows: in one call it returns layout-preserving markdown, generated figure descriptions, chart and diagram analysis (Chart.js and Mermaid), handwritten annotations, a one-paragraph summary of the whole document and chunk-ready output, with no schema to write. It handles PDFs, Office files and scanned images, although figure descriptions and chart and diagram analysis are supported only for PDF and image files.

Because it uses generative models, it needs model deployments on the resource and costs more than plain layout extraction. Choose it when the knowledge base needs figures and annotations as text and a document summary; choose prebuilt-layout when structure alone is enough and no model is deployed. As a prebuilt, it needs no analyzer definition of your own.

AnalyzerKindOutput
prebuilt-read, prebuilt-layout, prebuilt-digitalParseContent extractionText and structure, no generative features
prebuilt-documentSearchRAGMarkdown plus figure descriptions and analysis, annotations, summary
prebuilt-documentFieldsUtilityKey-value pairs as printed on the page
prebuilt-invoice, prebuilt-contract and other domain prebuiltsDomainA fixed field schema for that document type
prebuilt-documentBaseThe base for your own document analyzers

Adding your own fields to RAG-style output

A custom analyzer can derive only from the four base analyzers: prebuilt-document, prebuilt-image, prebuilt-audio and prebuilt-video. A definition whose baseAnalyzerId is prebuilt-documentSearch or prebuilt-layout fails to create. To get documentSearch-style output plus your own fields, base the analyzer on prebuilt-document, add the fieldSchema, and turn on enableFigureDescription and enableFigureAnalysis, which that base leaves off by default.

How do you define fields for structured output?

Structured output comes from a custom analyzer's fieldSchema: each field has a name, a type, a description that acts as the prompt, and a method that says how the value is produced. You create the analyzer once (a PUT of its definition) and every analysis returns those fields beside the markdown.

MethodReturnsUse for
extractThe value exactly as it appears in the content (document analyzers only)Printed identifiers, names, amounts, dates that are stated
classifyOne value from the field's enumCategories a downstream system groups by, such as a document type or priority
generateA value the model infers, derives or summarisesSummaries, values the document implies, dates worked out from other facts

Decide field by field. A policy number printed on a claim form is extract; a document type that must be one of a fixed list (claim, invoice, correspondence) is classify (generate could word it any way); an end date that a contract never states but that follows from the start date and term is generate (extract has nothing to copy). Set the method explicitly when it matters: leaving it unset lets the service choose from the type and description. An extract field also requires source and confidence estimation for that field (its estimateSourceAndConfidence must be true); the sample below satisfies this with the analyzer-level estimateFieldSourceAndConfidence.

{
  "description": "Supplier invoices",
  "baseAnalyzerId": "prebuilt-document",
  "config": {
    "enableFormula": false,
    "estimateFieldSourceAndConfidence": true
  },
  "fieldSchema": {
    "fields": {
      "InvoiceNumber": {
        "type": "string",
        "method": "extract",
        "description": "Invoice identifier, labelled Invoice No or Ref, top right of the header"
      },
      "ExpenseCategory": {
        "type": "string",
        "method": "classify",
        "enum": ["Goods", "Services", "Travel"],
        "description": "Category of spend the invoice covers"
      },
      "DueDate": {
        "type": "date",
        "method": "generate",
        "description": "Payment due date; when not printed, invoice date plus the payment term"
      },
      "LineItems": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "Description": { "type": "string", "method": "extract" },
            "Quantity": { "type": "number", "method": "extract" },
            "UnitPrice": { "type": "number", "method": "extract" }
          }
        }
      }
    }
  }
}

Writing descriptions that extract well

Microsoft's best practices for field schemas are mostly about the description:

  • Be detailed. Give the format and a location hint, as in Microsoft's invoice-date example: "typically found at the top right corner"; a one-word description gives the model too little to go on.
  • List every alias a template might print; the same example adds "May be labeled as Invoice Date, Billing Date, or Issue Date".
  • Use affirmative wording that says what the field is; "not the invoice number" style descriptions are less effective.
  • Match the document's language. For Italian invoices, name and describe fields in Italian (Fornitore, not Vendor); a schema in another language can significantly reduce accuracy. (locales is an audio and video transcription setting, not a document one.)
  • Use structured types for repeated data. Line items belong in an array whose items are objects with typed properties, never in a string field asked to hold "a JSON list"; the service then returns well-formed per-row values and normalizes typed values such as numbers.
  • Keep nesting shallow, and don't ask the model to embed confidence in a value; confidence has its own setting.

Refining descriptions is the first fix for poor extraction, before labeled samples.

How do confidence scores and grounding make output trustworthy?

Content Understanding can return, for each field, a confidence score from 0 to 1 and its grounding (where in the document the value came from), so you can post confident values automatically and route doubtful ones to a person who can jump to the exact spot. It works for extract, classify and generate document fields alike, so an inferred value can still drive threshold-based routing.

SettingWhereEffect
estimateFieldSourceAndConfidenceAnalyzer configTurns confidence and grounding on for every field
estimateSourceAndConfidenceAn individual fieldOverrides the analyzer setting for that field only

Confidence and grounding add tokens, and Microsoft's cost guidance is to enable them selectively. When only a few fields drive review routing, set the field-level switch on those fields rather than the analyzer-level one (fields that use extract need it on regardless).

source versus spans

Grounding propertyContainsUse it to
sourceThe page number and a bounding polygonDraw a box around the value on the rendered page
spansThe offset and length of the text in the extracted markdownHighlight or cite the value inside the indexed markdown

The two are the visual and logical locations of the same value. They answer different questions, so each feature reads the property that matches what it displays.

Patterns that look similar but don't work

Any certainty the model is asked to express through a field's value is a model opinion, not a calibrated per-field score, and it gives no location. Only the confidence and grounding settings produce both.

When do labeled samples improve a custom analyzer?

Labeled samples help when a zero-shot custom document analyzer has low accuracy or low confidence on a layout it handles poorly, after the field descriptions have already been refined. In Content Understanding Studio you add a representative document, correct or label its field values, and rebuild the analyzer so it uses the sample and generalizes the pattern to similar documents.

  1. Refine descriptions first: aliases, location hints, language, types.
  2. Add one labeled sample per distinct template or layout that underperforms. Several samples of one layout don't teach the others.
  3. Rebuild the analyzer.
  4. Measure on a fixed, representative test set before and after, so you can show results improved rather than merely changed. Keep the labeled samples out of that test set.

What labeling can't fix

  • Generate-method fields. Training doesn't currently support fields that use generate, so a summary that leaves things out won't improve from samples; improve its description instead.
  • OCR misreads. If OCR reads the letter l as the digit 1, labeling the right character doesn't change what the text recognizer reads.
  • Non-document analyzers. Training applies to document analyzers only.

Workarounds elsewhere in the pipeline hide a weak layout rather than fix it; the fix belongs in the analyzer.

How do you classify and split files that contain several documents?

An analyzer's contentCategories classifies content into named categories, each with a description and, optionally, an analyzerId that processes content of that category; enableSegment decides whether the file is first split into segments. This is how one call handles a PDF that holds an invoice, a receipt and a delivery note one after another.

SettingEffect
enableSegment: trueSplits the file into segments using the category descriptions and content structure, classifies each segment and routes it to its category's analyzerId
enableSegment: falseClassifies the whole file into a single category; suits one-document files
segmentPerPage: trueReplaces logical boundaries with one segment per page, so adjacent look-alike forms never merge
omitContent: trueDrops the original file's content object from the response, leaving only the routed analyzers' results
A category with no analyzerIdContent is classified into it but not processed further

Classification always picks one of the defined categories, so content that fits none of them (a cover letter, a blank separator sheet) is forced into the closest match unless you add an "other" category with a description and no analyzerId. Category descriptions stay affirmative too: the classifier needs somewhere valid to put the page, not a list of exclusions.

Define categories by semantic document type (invoice, credit memo, bank statement), not one per supplier's visual template; layout differences are handled within an analyzer by its descriptions and labeled samples. Running every analyzer over the whole file instead of splitting mixes one document's values into another's fields.

How do you call an analyzer and read its result?

On the GA API (2025-11-01), analysis is asynchronous: you start it against an analyzer, poll an operation until it succeeds, then read the result's contents array, where each content object carries markdown (the layout-preserving text) and fields (the schema values).

REST

  1. POST {endpoint}/contentunderstanding/analyzers/{analyzerId}:analyze?api-version=2025-11-01 with the document URL in inputs in the JSON body.
  2. The service answers 202 Accepted with no analysis result in the body and an Operation-Location header pointing at contentunderstanding/analyzerResults/{id}.
  3. GET that URL until status moves from NotStarted or Running to Succeeded.
  4. Read result.contents[0].markdown to chunk and embed, and result.contents[0].fields for structured values.

GET /analyzers/{analyzerId} is a different resource: it returns the analyzer's definition, not an analysis result.

Python SDK

The ContentUnderstandingClient wraps the same flow: begin_analyze returns a poller and poller.result() waits for the finished analysis.

from azure.ai.contentunderstanding import ContentUnderstandingClient
from azure.ai.contentunderstanding.models import AnalysisInput
from azure.identity import DefaultAzureCredential

client = ContentUnderstandingClient(
    endpoint=endpoint, credential=DefaultAzureCredential()
)
poller = client.begin_analyze(
    analyzer_id="invoice-analyzer",
    inputs=[AnalysisInput(url=doc_url)],
)
result = poller.result()

for content in result.contents:
    text_for_rag = content.markdown   # layout-preserving text
    values = content.fields           # schema values (custom analyzers)

Use markdown as the source for chunking and embedding; fields holds only what the analyzer's schema defines, pages holds per-page layout detail such as words and lines, and warnings holds diagnostics. Prefer keyless authentication (Microsoft Entra ID through DefaultAzureCredential) over resource keys.

Copy prebuilt analyzers for production

Prebuilt analyzer definitions can change between API versions. When output feeds a fixed downstream mapping, such as invoice fields into an ERP system, retrieve the prebuilt definition (GET the analyzer) and create your own analyzer from it (PUT under your own ID). Your copy keeps its schema and behaviour while you move to a newer API version for other features.

Tip. Expect short scenarios such as a records office, an insurer, an accounts-payable team or a RAG ingestion job, each with one deciding requirement: lowest cost, no model deployed, born-digital files, an air-gapped site, no labeled data, least development effort, a stable schema across API versions, or a reviewer who must jump to the value on the page. Questions ask which analyzer to call, which content option to switch on or off (and what an empty config does), how the markdown represents checkboxes, pages, tables and figures, which field method fits each value, which grounding property a feature needs, what labeled samples can and can't fix, how to configure classification and splitting, and which line or property completes a Python SDK or REST call. Several are select-TWO items, and wrong options are usually real settings that fail only on the stated constraint, so know each option's default and exact effect.

Key takeaways
  • Content extraction analyzers need no generative model: prebuilt-read for text and barcodes, prebuilt-layout for structure, prebuilt-digitalParse for born-digital files and, in the GA API, embedded metadata.
  • prebuilt-documentSearch is the RAG ingestion analyzer: markdown plus figure descriptions, Chart.js and Mermaid analysis, annotations and a summary, with no schema to write.
  • Custom analyzers derive only from prebuilt-document, prebuilt-image, prebuilt-audio or prebuilt-video; turn on the figure options yourself to get documentSearch-style figures.
  • enableOcr, enableLayout, enableFormula and enableBarcode default to true; enableFigureDescription and enableFigureAnalysis default to false; tableFormat defaults to html.
  • Markdown encodes checkboxes as ☒/☐, page numbers, headers, footers and breaks as HTML comments, sections as headings and formulas as LaTeX.
  • extract returns printed values, classify returns one enum value, generate infers; write detailed, affirmative, same-language descriptions with aliases, and use arrays of objects for repeated rows.
  • Confidence and grounding come from estimateFieldSourceAndConfidence (analyzer) or estimateSourceAndConfidence (field); source locates the value on the page, spans in the markdown.
  • Labeled samples come after refined descriptions, one per underperforming layout, measured on a fixed test set; they can't fix generate fields or OCR misreads.
  • contentCategories with enableSegment splits and routes mixed files; add an 'other' category, use segmentPerPage for one form per page and omitContent for routed results only.
  • Analyze is asynchronous (202 plus Operation-Location to poll); read contents[0].markdown and fields, and copy prebuilt analyzers into your own for production.

Frequently asked questions

What is the difference between prebuilt-read and prebuilt-layout in Azure Content Understanding?

prebuilt-read performs OCR and returns the words, paragraphs, formulas and barcode values of a document, without layout analysis. prebuilt-layout adds layout analysis on top, returning tables, sections and headings, figures, hyperlinks and the structural reading order. Neither needs a generative model; read is billed on the cheaper basic meter for scanned pages, while layout analysis uses the standard meter.

When should I use Document Intelligence instead of Content Understanding?

Use Document Intelligence when documents must be processed on premises or in an air-gapped environment, which its containers support, or when you have highly structured forms and can label samples to train a custom model. Content Understanding custom analyzers suit unstructured documents and fields that must be inferred without labeled data.

How do I get chart data and flowcharts into Content Understanding markdown?

Turn on enableFigureAnalysis in the document analyzer's config. It extracts the data behind charts in Chart.js form and writes diagrams such as flowcharts in Mermaid syntax after the image. enableFigureDescription, a separate option, adds a short natural-language description. Both default to false on prebuilt-document; prebuilt-documentSearch already includes them.

How are checkboxes and page breaks shown in Content Understanding markdown?

Selection marks are written as Unicode characters next to their text: ☒ for selected and ☐ for cleared. Page metadata, which markdown can't express natively, is written as HTML comments, such as <!-- PageBreak -->, <!-- PageNumber="…" -->, <!-- PageHeader="…" --> and <!-- PageFooter="…" -->.

What is the difference between source and spans in Content Understanding grounding?

Both locate a field value. source gives the visual location, a page number and bounding polygon, for highlighting on the rendered page. spans give the logical location, a character offset and length in the extracted markdown, for highlighting or citing the text the RAG index holds. They are returned when estimateFieldSourceAndConfidence or a field's estimateSourceAndConfidence is enabled.

Can a custom Content Understanding analyzer be based on prebuilt-documentSearch?

No. Custom analyzers can currently derive only from prebuilt-document, prebuilt-image, prebuilt-audio and prebuilt-video. To add your own fields to documentSearch-style output, base the analyzer on prebuilt-document, add a fieldSchema and enable enableFigureDescription and enableFigureAnalysis.

Why does a Content Understanding analyze call return no result?

On the GA API (2025-11-01), analysis is asynchronous. The POST to an analyzer's :analyze endpoint returns 202 Accepted with an Operation-Location header; you poll that URL until the status is Succeeded and then read result.contents, where each content object has markdown and fields. The Python SDK's begin_analyze returns a poller that does this for you.

Source

This lesson covers the "Implement information extraction solutions" domain of the official AI-103 exam guide. Vendors revise their guides — check the source for the current version.

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?