Azure AI Document Intelligence

Azure AI Document Intelligence

Azure AI Document Intelligence (formerly Form Recognizer) is Microsoft's document-AI service. It extracts printed and handwritten text, layout (lines, paragraphs, tables, figures), key-value pairs, and semantic fields from forms, invoices, receipts, IDs, and contracts. Unlike a pure OCR engine, it preserves document structure and provides prebuilt models for common document types — the Azure counterpart to AWS Textract.


Model Types:


Key Features:


Examples

1. Layout Extraction with Markdown Output (for LLM Ingestion)


from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest, ContentFormat
from azure.core.credentials import AzureKeyCredential

client = DocumentIntelligenceClient(
    endpoint="https://myco-docintel.cognitiveservices.azure.com/",
    credential=AzureKeyCredential("<key>"),
)

with open("contract.pdf", "rb") as f:
    poller = client.begin_analyze_document(
        "prebuilt-layout",
        AnalyzeDocumentRequest(bytes_source=f.read()),
        output_content_format=ContentFormat.MARKDOWN,
    )

result = poller.result()
print(result.content[:2000])   # Markdown with headings, tables, etc.
  

2. Extract Invoice Fields with the Prebuilt Model


poller = client.begin_analyze_document(
    "prebuilt-invoice",
    AnalyzeDocumentRequest(url_source="https://myco.blob.core.windows.net/inv/inv-0421.pdf"),
)
invoice = poller.result().documents[0]

print("Vendor:", invoice.fields["VendorName"].value_string)
print("Total :", invoice.fields["InvoiceTotal"].value_currency.amount)

for item in invoice.fields.get("Items", {}).value_array or []:
    desc = item.value_object["Description"].value_string
    amt  = item.value_object["Amount"].value_currency.amount
    print(f"  - {desc}: {amt}")
  

3. Query Fields (Natural-Language Field Extraction)


poller = client.begin_analyze_document(
    "prebuilt-layout",
    AnalyzeDocumentRequest(url_source="https://myco.blob.core.windows.net/claims/claim-88.pdf"),
    features=["queryFields"],
    query_fields=["PolicyNumber", "DateOfIncident", "ClaimedAmount"],
)
result = poller.result()
for doc in result.documents:
    for name, field in doc.fields.items():
        print(name, "->", field.content)
  

4. Pair with Azure OpenAI for RAG Ingestion

The typical pattern for document-heavy RAG: Document Intelligence → chunks of Markdown → Azure OpenAI embeddings → Azure AI Search index.


# 1) Parse PDF to Markdown via Document Intelligence Layout
md = client.begin_analyze_document(
    "prebuilt-layout",
    AnalyzeDocumentRequest(bytes_source=pdf_bytes),
    output_content_format=ContentFormat.MARKDOWN,
).result().content

# 2) Chunk by headings / token count (use langchain MarkdownHeaderTextSplitter, etc.)
chunks = chunk_markdown(md, max_tokens=500)

# 3) Embed chunks with Azure OpenAI
from openai import AzureOpenAI
aoai = AzureOpenAI(azure_endpoint="...", api_key="...", api_version="2024-10-21")
vectors = aoai.embeddings.create(model="embedding-3-large-prod", input=chunks).data

# 4) Upload to Azure AI Search (see the AI Search page for index schema)
documents = [{"id": f"doc-{i}", "content": c, "content_vector": v.embedding}
             for i, (c, v) in enumerate(zip(chunks, vectors))]
search_client.upload_documents(documents)
  

When to Choose Document Intelligence:

1. Summary

Document Intelligence turns documents into structured data. Its models form a hierarchy: Read extracts text, Layout adds structure such as paragraphs, tables, selection marks and reading order, prebuilt models add domain fields for common document types, and custom models learn your own layouts. Results are returned as JSON with coordinates and confidences, or, for Layout, as Markdown that keeps headings and tables intact for language models. It is typically the first step of a document pipeline: ingestion for RAG, automated data entry from invoices and receipts, or classification and routing of mixed document batches.

2. How analysis works

Document Intelligence Processing Flow PDF / imagebytes or Blob URL begin_analyzeasync LRO Modellayout / invoice / custom Poll resultpoller.result() AnalyzeResultpages, tables, fields Markdown / JSONto LLM or DB Analysis is a long-running operation: the client submits, then polls until the result is ready. Every word, cell and field carries a bounding polygon and confidence score.

Each analysis call is a long-running operation. The SDK's begin_analyze_document uploads the bytes (or passes a URL the service can read, such as a Blob SAS URL) and returns a poller; result() waits until the service finishes. The AnalyzeResult contains pages with words and lines, tables with cell spans, paragraphs with roles such as title or section heading, and, for field-extraction models, a list of documents with typed fields. Options such as page ranges, add-on features (high-resolution OCR, formulas, barcodes, query fields) and output format are set per request.

3. Choosing a model

Choosing a Model Need plain text?Read Structure, tables?Layout Known doc type?Prebuilt Own forms?Custom extraction Start with the simplest model that meets the need; Layout is the usual choice for RAG ingestion, prebuilt models for invoices, receipts and IDs, custom models for in-house forms.

Prebuilt models save labelling work but return a fixed schema; if a field you need is missing, query fields can ask for it by name. Custom extraction models are trained from labelled samples in Document Intelligence Studio, and a custom classifier can split and route mixed batches to the right extractor. For high-volume pipelines, the batch API processes a whole container of files and writes results to another container.

4. Worked example: confidence-based review

from azure.identity import DefaultAzureCredential
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import AnalyzeDocumentRequest

client = DocumentIntelligenceClient(
    endpoint="https://myco-docintel.cognitiveservices.azure.com/",
    credential=DefaultAzureCredential(),          # Entra ID instead of a key
)

REQUIRED = ["VendorName", "InvoiceId", "InvoiceDate", "InvoiceTotal"]
THRESHOLD = 0.85

def extract_invoice(path):
    with open(path, "rb") as f:
        poller = client.begin_analyze_document(
            "prebuilt-invoice", AnalyzeDocumentRequest(bytes_source=f.read()))
    doc = poller.result().documents[0]
    out, review = {}, []
    for name in REQUIRED:
        field = doc.fields.get(name)
        if field is None or (field.confidence or 0) < THRESHOLD:
            review.append(name)
        out[name] = field.content if field else None
    return out, review

data, needs_review = extract_invoice("inv-0421.pdf")
print(data)
print("route to human review:" if needs_review else "auto-approved", needs_review)

Real pipelines rarely trust every field blindly. This pattern auto-approves documents where all required fields are present with high confidence and sends the rest to a human queue, which keeps accuracy high while automating the bulk of the volume. Using DefaultAzureCredential with a managed identity avoids storing API keys in code.

5. Document Intelligence vs alternatives

OptionStrengthsConsider when
Azure Document IntelligencePrebuilt + custom models, Markdown output, containers for on-premYou are on Azure or need disconnected deployment
Amazon TextractForms, tables, queries, AnalyzeExpense/IDYou are on AWS
Google Document AISpecialised processors, Workbench custom extractorsYou are on Google Cloud
Open-source (Tesseract, docTR, Docling)No per-page cost, full controlVolume is high and you can host and tune models
Multimodal LLM directlyFlexible, no trainingSmall volumes; needs validation and is less deterministic

6. Pitfalls